diff --git a/build.vc11/mpir.net/mpir.net-tests/mpir.net-tests.csproj b/build.vc11/mpir.net/mpir.net-tests/mpir.net-tests.csproj index 5f6e11ae..65a8c1c6 100644 --- a/build.vc11/mpir.net/mpir.net-tests/mpir.net-tests.csproj +++ b/build.vc11/mpir.net/mpir.net-tests/mpir.net-tests.csproj @@ -164,7 +164,9 @@ mpir.net - + + + diff --git a/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj b/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj index aa1c43f7..4fb6a606 100644 --- a/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj +++ b/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj @@ -142,6 +142,7 @@ + @@ -150,6 +151,7 @@ + diff --git a/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj.filters b/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj.filters index a3d009fc..a423f954 100644 --- a/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj.filters +++ b/build.vc11/mpir.net/mpir.net/mpir.net.vcxproj.filters @@ -33,6 +33,9 @@ Header Files + + Header Files + @@ -50,6 +53,9 @@ Source Files + + Source Files + diff --git a/mpir.net/mpir.net/HugeFloat.cpp b/mpir.net/mpir.net/HugeFloat.cpp new file mode 100644 index 00000000..2382e45a --- /dev/null +++ b/mpir.net/mpir.net/HugeFloat.cpp @@ -0,0 +1,343 @@ +/* +Copyright 2014 Alex Dyachenko + +This file is part of the MPIR Library. + +The MPIR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation; either version 3 of the License, or (at +your option) any later version. + +The MPIR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the MPIR Library. If not, see http://www.gnu.org/licenses/. +*/ + +#include "Stdafx.h" +#include "HugeInt.h" +#include "HugeFloat.h" +//#include "Random.h" + +using namespace System::Runtime::InteropServices; +using namespace System::Text; + +namespace MPIR +{ + #pragma region construction + + MPTYPE::MPTYPE() + { + AllocateStruct(); + MP(init)(_value); + } + + MPTYPE::MPTYPE(bool initialize) + { + AllocateStruct(); + if(initialize) + MP(init)(_value); + } + + MPTYPE::MPTYPE(MPEXPR_NAME^ value) + { + AllocateStruct(); + MP(init)(_value); + value->AssignTo(_value); + } + + MPTYPE::MPTYPE(IntegerExpression^ value) + { + AllocateStruct(); + MP(init)(_value); + SetTo(value); + } + + MPTYPE^ MPTYPE::Allocate(mp_bitcnt_t precision) + { + auto result = gcnew MPTYPE(false); + MP(init2)(result->_value, precision); + return result; + } + + void MPTYPE::FromString(String^ value, int base) + { + AllocateStruct(); + MP(init)(_value); + + IntPtr ptr = Marshal::StringToHGlobalAnsi(value); + bool success = 0 == MP(set_str)(_value, (char*)(void*)ptr, base); + Marshal::FreeHGlobal(ptr); + + if(!success) + { + DeallocateStruct(); + throw gcnew ArgumentException("Invalid number", "value"); + } + } + + void MPTYPE::SetTo(String^ value, int base) + { + IntPtr ptr = Marshal::StringToHGlobalAnsi(value); + bool success = 0 == MP(set_str)(_value, (char*)(void*)ptr, base); + Marshal::FreeHGlobal(ptr); + + if(!success) + throw gcnew ArgumentException("Invalid number", "value"); + } + + MPTYPE::MPTYPE(mpir_si value) + { + AllocateStruct(); + MP(init_set_si)(_value, value); + } + + MPTYPE::MPTYPE(mpir_ui value) + { + AllocateStruct(); + MP(init_set_ui)(_value, value); + } + + MPTYPE::MPTYPE(double value) + { + AllocateStruct(); + MP(init_set_d)(_value, value); + } + + #pragma endregion + + #pragma region object overrides + + String^ MPTYPE::ToString(int base, bool lowercase, int maxDigits) + { +auto result = gcnew StringBuilder(); +//result->Append(this->Numerator->ToString(base, lowercase, maxDigits)); +//result->Append((wchar_t)'/'); +//result->Append(this->Denominator->ToString(base, lowercase, maxDigits)); +return result->ToString(); + } + + int MPEXPR_NAME::GetHashCode() + { + IN_CONTEXT(this); + + mp_limb_t hash = CTXT(0)->_mp_exp; + mp_limb_t* ptr = CTXT(0)->_mp_d; + for(int i = abs(CTXT(0)->_mp_size); i > 0; i--) + hash ^= *ptr++; + + if(CTXT(0)->_mp_size < 0) + hash = (mp_limb_t)-(mpir_si)hash; + + return hash.GetHashCode(); + } + + #pragma endregion + + #pragma region Interface implementations + + int MPEXPR_NAME::CompareTo(Object^ a, bool& valid) + { + valid = true; + + if (IS_NULL(a)) + return 1; + + MPEXPR_NAME^ expr = dynamic_cast(a); + if(!IS_NULL(expr)) + return CompareTo(expr); + + EvaluationContext context; + + if(a->GetType() == mpir_ui::typeid) + { + ASSIGN_TO(context); + return MP(cmp_ui)(CTXT(0), (mpir_ui)a); + } + + if(a->GetType() == mpir_si::typeid) + { + ASSIGN_TO(context); + return MP(cmp_si)(CTXT(0), (mpir_si)a); + } + + if(a->GetType() == double::typeid) + { + ASSIGN_TO(context); + return MP(cmp_d)(CTXT(0), (double)a); + } + + valid = false; + return 0; + } + + int MPEXPR_NAME::CompareTo(Object^ a) + { + bool valid; + auto result = CompareTo(a, valid); + + if (valid) + return result; + + throw gcnew ArgumentException("Invalid argument type", "a"); + } + + int MPEXPR_NAME::CompareTo(MPEXPR_NAME^ a) + { + if (IS_NULL(a)) + return 1; + + IN_CONTEXT(this, a); + return MP(cmp)(CTXT(0), CTXT(1)); + } + + bool MPEXPR_NAME::Equals(Object^ a) + { + bool valid; + auto result = CompareTo(a, valid); + + return valid && result == 0; + } + + bool MPEXPR_NAME::Equals(MPEXPR_NAME^ a) + { + return CompareTo(a) == 0; + } + + #pragma endregion + + #pragma region Arithmetic + + MAKE_BINARY_OPERATOR_STANDARD (MPEXPR_NAME, DEFINE, +, Add, Flt, Flt) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, +, Add, Flt, Ui) + MAKE_BINARY_OPERATOR_LLIMB_R (MPEXPR_NAME, DEFINE, +, Add, Flt, Ui) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, +, Add, Flt, Si) + MAKE_BINARY_OPERATOR_LLIMB_R (MPEXPR_NAME, DEFINE, +, Add, Flt, Si) + + MAKE_BINARY_OPERATOR_STANDARD (MPEXPR_NAME, DEFINE, -, Subtract, Flt, Flt) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, -, Subtract, Flt, Ui) + MAKE_BINARY_OPERATOR_LLIMB (MPEXPR_NAME, DEFINE, -, Subtract, Flt, Ui) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, -, Subtract, Flt, Si) + MAKE_BINARY_OPERATOR_LLIMB (MPEXPR_NAME, DEFINE, -, Subtract, Flt, Si) + + MAKE_BINARY_OPERATOR_STANDARD (MPEXPR_NAME, DEFINE, *, Multiply, Flt, Flt) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, *, Multiply, Flt, Ui) + MAKE_BINARY_OPERATOR_LLIMB_R (MPEXPR_NAME, DEFINE, *, Multiply, Flt, Ui) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, *, Multiply, Flt, Si) + MAKE_BINARY_OPERATOR_LLIMB_R (MPEXPR_NAME, DEFINE, *, Multiply, Flt, Si) + + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, <<, ShiftLeft, Flt, Bits) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, >>, ShiftRight, Flt, Bits) + + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, ^, Power, Flt, Ui) + + MAKE_UNARY_OPERATOR (MPEXPR_NAME, DEFINE, -, Negate, Flt) + MAKE_VOID_FUNCTION (MPEXPR_NAME, DEFINE, Abs, Flt) + + MAKE_BINARY_OPERATOR_STANDARD (MPEXPR_NAME, DEFINE, /, Divide, Flt, Flt) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, /, Divide, Flt, Ui) + MAKE_BINARY_OPERATOR_LLIMB (MPEXPR_NAME, DEFINE, /, Divide, Flt, Ui) + MAKE_BINARY_OPERATOR_RLIMB (MPEXPR_NAME, DEFINE, /, Divide, Flt, Si) + MAKE_BINARY_OPERATOR_LLIMB (MPEXPR_NAME, DEFINE, /, Divide, Flt, Si) + + DEFINE_UNARY_ASSIGNMENT_REF(Negate, Flt, MP(neg)) + DEFINE_UNARY_ASSIGNMENT_REF(Abs, Flt, MP(abs)) + + DEFINE_BINARY_ASSIGNMENT_REF_REF(Add, Flt, MP(add)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Add, Flt, Ui, MP(add)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Add, Flt, Si, MP(add)) + + DEFINE_BINARY_ASSIGNMENT_REF_REF(Subtract, Flt, MP(sub)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Subtract, Flt, Ui, MP(sub)) + DEFINE_BINARY_ASSIGNMENT_RATVAL_REF(Subtract, Ui, Flt, MP(sub)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Subtract, Flt, Si, MP(sub)) + DEFINE_BINARY_ASSIGNMENT_RATVAL_REF(Subtract, Si, Flt, MP(sub)) + + DEFINE_BINARY_ASSIGNMENT_REF_REF(Multiply, Flt, MP(mul)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Multiply, Flt, Ui, MP(mul)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Multiply, Flt, Si, MP(mul)) + + DEFINE_BINARY_ASSIGNMENT_REF_REF(Divide, Flt, MP(div)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Divide, Flt, Ui, MP(div)) + DEFINE_BINARY_ASSIGNMENT_RATVAL_REF(Divide, Ui, Flt, MP(div)) + DEFINE_BINARY_ASSIGNMENT_REF_RATVAL(Divide, Flt, Si, MP(div)) + DEFINE_BINARY_ASSIGNMENT_RATVAL_REF(Divide, Si, Flt, MP(div)) + + DEFINE_BINARY_ASSIGNMENT_REF_VAL(ShiftLeft, Flt, Bits, MP(mul_2exp)) + DEFINE_BINARY_ASSIGNMENT_REF_VAL(ShiftRight, Flt, Bits, MP(div_2exp)) + + DEFINE_BINARY_ASSIGNMENT_REF_VAL(Power, Flt, Ui, MP(pow_ui)) + + #pragma endregion + + #pragma region IO + + #define chunkSize 1024 + + size_t MPTYPE::Write(Stream^ stream) + { + auto writtenNumerator = Numerator->Write(stream); + if(writtenNumerator == 0) + return 0; + + auto writtenDenominator = Denominator->Write(stream); + if(writtenDenominator == 0) + return 0; + + return writtenNumerator + writtenDenominator; + } + + size_t MPTYPE::Read(Stream^ stream) + { + auto readNumerator = Numerator->Read(stream); + if(readNumerator == 0) + return 0; + + auto readDenominator = Denominator->Read(stream); + if(readDenominator == 0) + return 0; + + return readNumerator + readDenominator; + } + + size_t MPTYPE::Write(TextWriter^ writer, int base, bool lowercase) + { + auto str = ToString(base, lowercase); + writer->Write(str); + return str->Length; + } + + size_t MPTYPE::Read(TextReader^ reader, int base) + { + auto readNumerator = Numerator->Read(reader, base); + if(readNumerator == 0) + return 0; + + size_t readDenominator = 0; + char c = reader->Peek(); + if (c == '/') + { + reader->Read(); + readDenominator = 1 + Denominator->Read(reader, base); + if(readDenominator == 1) + return 0; + } + + return readNumerator + readDenominator; + } + + #pragma endregion + + #pragma region methods in other classes with rational parameters + + void HugeInt::SetTo(MPEXPR_NAME^ value) + { + IN_CONTEXT(value); + mpz_set_f(_value, CTXT(0)); + } + + #pragma endregion +}; \ No newline at end of file diff --git a/mpir.net/mpir.net/HugeFloat.h b/mpir.net/mpir.net/HugeFloat.h new file mode 100644 index 00000000..e18f02bc --- /dev/null +++ b/mpir.net/mpir.net/HugeFloat.h @@ -0,0 +1,1228 @@ +/* +Copyright 2014 Alex Dyachenko + +This file is part of the MPIR Library. + +The MPIR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation; either version 3 of the License, or (at +your option) any later version. + +The MPIR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the MPIR Library. If not, see http://www.gnu.org/licenses/. +*/ + +#pragma once + +using namespace System; +using namespace System::IO; +using namespace System::Runtime::InteropServices; + +#ifdef SPECIALIZE_EXPRESSIONS +#undef SPECIALIZE_EXPRESSIONS +#undef MP +#undef CUSTOM_MP +#undef MPSTRUCT +#undef MPTYPE +#undef MPTYPE_NAME +#undef MPEXPR_NAME +#undef MPEXPR +#undef CTXT +#undef CTXTI +#undef ASSIGN_TO +#undef Mpt +#endif +#define SPECIALIZE_EXPRESSIONS +#define Mpt Flt +#define CUSTOM_MP(x) custom_mpf_##x +#define MPSTRUCT __mpf_struct +#define MP(x) mpf_##x +#define MPTYPE HugeFloat +#define MPTYPE_NAME Float +#define MPEXPR_NAME LIT(MPTYPE_NAME)Expression +#define MPEXPR(x) LIT(MPTYPE_NAME)##x##Expression +#define CTXT(x) context.FloatArgs[x] +#define CTXTI(x) context.IntArgs[x] +#define ASSIGN_TO CONCAT(AssignTo, LIT(MPTYPE_NAME)) +#include "ExpressionMacros.h" + +namespace MPIR +{ + ref class MpirRandom; + ref class MPTYPE; + ref class MPEXPR(Divide); + ref class MPEXPR(DivideUi); + ref class MPEXPR(Mod); + ref class MPEXPR(DivMod); + ref class MPEXPR(ModUi); + ref class MPEXPR(ShiftRight); + ref class MPEXPR(Root); + ref class MPEXPR(SquareRoot); + ref class MPEXPR(Gcd); + ref class MPEXPR(RemoveFactors); + ref class MPEXPR(Sequence); + + #pragma region FloatExpression + + /// + /// Base class for all float expressions resulting from many float operations on MPIR types. + /// Expressions can be arbitrarily nested, and are lazily evaluated + /// when they are either assigned to the Value property of an MPIR object, or are consumed by a function or operator that returns a primitive type. + /// Assignment to the Value property is necessary because .Net does not support overloading the assignment operator. + /// + public ref class MPEXPR_NAME abstract : public IComparable, IComparable, IEquatable + { + internal: + MPEXPR_NAME() { } + virtual void AssignTo(MP(ptr) destination) abstract; + virtual void ASSIGN_TO(EvaluationContext& context) + { + context.Initialized(FloatInitialized); + auto ptr = &context.Temp[context.Index].MPTYPE_NAME; + CTXT(context.Index++) = ptr; + MP(init)(ptr); + AssignTo(ptr); + } + + private: + int CompareTo(Object^ a, bool& valid); + + public: + #pragma region Arithmetic + + /// Adds two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to add to + /// Source value to add + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator + (MPEXPR_NAME^ a, MPEXPR_NAME^ b); + + /// Adds two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to add to + /// Source value to add + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator + (MPEXPR_NAME^ a, mpir_ui b); + + /// Adds two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to add to + /// Source value to add + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator + (mpir_ui a, MPEXPR_NAME^ b); + + /// Adds two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to add to + /// Source value to add + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator + (MPEXPR_NAME^ a, mpir_si b); + + /// Adds two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to add to + /// Source value to add + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator + (mpir_si a, MPEXPR_NAME^ b); + + /// Subtracts two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to subtract from + /// Source value to subtract + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator - (MPEXPR_NAME^ a, MPEXPR_NAME^ b); + + /// Subtracts two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to subtract from + /// Source value to subtract + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator - (MPEXPR_NAME^ a, mpir_ui b); + + /// Subtracts two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to subtract from + /// Source value to subtract + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator - (mpir_ui a, MPEXPR_NAME^ b); + + /// Subtracts two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to subtract from + /// Source value to subtract + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator - (MPEXPR_NAME^ a, mpir_si b); + + /// Subtracts two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to subtract from + /// Source value to subtract + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator - (mpir_si a, MPEXPR_NAME^ b); + + /// Multiplies two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to multiply + /// Source value to multiply by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator * (MPEXPR_NAME^ a, MPEXPR_NAME^ b); + + /// Multiplies two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to multiply + /// Source value to multiply by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator * (MPEXPR_NAME^ a, mpir_ui b); + + /// Multiplies two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to multiply + /// Source value to multiply by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator * (mpir_ui a, MPEXPR_NAME^ b); + + /// Multiplies two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to multiply + /// Source value to multiply by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator * (MPEXPR_NAME^ a, mpir_si b); + + /// Multiplies two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to multiply + /// Source value to multiply by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator * (mpir_si a, MPEXPR_NAME^ b); + + /// Shifts the source operand to the left by , i.e. multiplies by 2^. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to multiply + /// Number of bits to shift by, i.e. power of 2 to multiply by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator << (MPEXPR_NAME^ a, mp_bitcnt_t bits); + + /// Shifts the source operand to the right by , i.e. divides by 2^. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to divide + /// Number of bits to shift by, i.e. power of 2 to divide by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation. + /// + static MPEXPR_NAME^ operator >> (MPEXPR_NAME^ a, mp_bitcnt_t bits); + + /// Negates the source value. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to negate + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator - (MPEXPR_NAME^ a); + + /// Divides two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to divide + /// Source value to divide by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation. + /// + static MPEXPR_NAME^ operator / (MPEXPR_NAME^ a, MPEXPR_NAME^ b); + + /// Divides two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to divide + /// Source value to divide by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation. + /// + static MPEXPR_NAME^ operator / (MPEXPR_NAME^ a, mpir_ui b); + + /// Divides two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to divide + /// Source value to divide by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation. + /// + static MPEXPR_NAME^ operator / (mpir_ui a, MPEXPR_NAME^ b); + + /// Divides two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to divide + /// Source value to divide by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation. + /// + static MPEXPR_NAME^ operator / (MPEXPR_NAME^ a, mpir_si b); + + /// Divides two numbers. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to divide + /// Source value to divide by + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation. + /// + static MPEXPR_NAME^ operator / (mpir_si a, MPEXPR_NAME^ b); + + /// Raises the source value to the specified power. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// Source value to multiply + /// Power to raise to + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + static MPEXPR_NAME^ operator ^ (MPEXPR_NAME^ a, mpir_ui power); + + /// Computes the absolute value of the source number. + /// As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method. + /// + /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation + MPEXPR_NAME^ Abs(); + + #pragma endregion + + #pragma region Comparisons + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Value to compare the source with + /// A positive number if the source is greater than , negative if less, and zero if they are equal. + virtual int CompareTo(Object^ a) sealed; + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Value to compare the source with + /// A positive number if the source is greater than , negative if less, and zero if they are equal. + virtual int CompareTo(MPEXPR_NAME^ a) sealed; + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Value to compare the source with + /// true if the values of the source and are equal, false otherwise. + virtual bool Equals(MPEXPR_NAME^ a) sealed; + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Value to compare the source with. This can be a multi-precision number, an expression, or a supported primitive type (long, ulong, or double). + /// true if the values of the source and are equal, false otherwise. + virtual bool Equals(Object^ a) override sealed; + + /// Computes the hash code of the source value. + /// If called on an expression, it is evaluated into a temporary variable before the comparison is performed. + /// Multi-precision classes are mutable with value semantics. The hash code is based on the value, and will change if the value changes. + /// For this reason, the value of an object must not be modified while the object is contained in a hash table. + /// a signed integer hash code for the value. + virtual int GetHashCode() override sealed; + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator < (MPEXPR_NAME^ a, MPEXPR_NAME^ b) { return IS_NULL(a) ? !IS_NULL(b) : a->CompareTo(b) < 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator >= (MPEXPR_NAME^ a, MPEXPR_NAME^ b) { return IS_NULL(a) ? IS_NULL(b) : a->CompareTo(b) >= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator == (MPEXPR_NAME^ a, MPEXPR_NAME^ b) { return IS_NULL(a) ? IS_NULL(b) : a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator != (MPEXPR_NAME^ a, MPEXPR_NAME^ b) { return IS_NULL(a) ? !IS_NULL(b) : !a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator > (MPEXPR_NAME^ a, MPEXPR_NAME^ b) { return !IS_NULL(a) && a->CompareTo(b) > 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator <= (MPEXPR_NAME^ a, MPEXPR_NAME^ b) { return IS_NULL(a) || a->CompareTo(b) <= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator < (MPEXPR_NAME^ a, mpir_ui b) { return IS_NULL(a) || a->CompareTo(b) < 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator >= (MPEXPR_NAME^ a, mpir_ui b) { return !IS_NULL(a) && a->CompareTo(b) >= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator > (MPEXPR_NAME^ a, mpir_ui b) { return !IS_NULL(a) && a->CompareTo(b) > 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator <= (MPEXPR_NAME^ a, mpir_ui b) { return IS_NULL(a) || a->CompareTo(b) <= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator != (MPEXPR_NAME^ a, mpir_ui b) { return IS_NULL(a) || !a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator == (MPEXPR_NAME^ a, mpir_ui b) { return !IS_NULL(a) && a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator < (mpir_ui b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->CompareTo(b) > 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator >= (mpir_ui b, MPEXPR_NAME^ a) { return IS_NULL(a) || a->CompareTo(b) <= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator > (mpir_ui b, MPEXPR_NAME^ a) { return IS_NULL(a) || a->CompareTo(b) < 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator <= (mpir_ui b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->CompareTo(b) >= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator != (mpir_ui b, MPEXPR_NAME^ a) { return IS_NULL(a) || !a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator == (mpir_ui b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator < (MPEXPR_NAME^ a, mpir_si b) { return IS_NULL(a) || a->CompareTo(b) < 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator >= (MPEXPR_NAME^ a, mpir_si b) { return !IS_NULL(a) && a->CompareTo(b) >= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator > (MPEXPR_NAME^ a, mpir_si b) { return !IS_NULL(a) && a->CompareTo(b) > 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator <= (MPEXPR_NAME^ a, mpir_si b) { return IS_NULL(a) || a->CompareTo(b) <= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator != (MPEXPR_NAME^ a, mpir_si b) { return IS_NULL(a) || !a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator == (MPEXPR_NAME^ a, mpir_si b) { return !IS_NULL(a) && a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator < (mpir_si b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->CompareTo(b) > 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator >= (mpir_si b, MPEXPR_NAME^ a) { return IS_NULL(a) || a->CompareTo(b) <= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator > (mpir_si b, MPEXPR_NAME^ a) { return IS_NULL(a) || a->CompareTo(b) < 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator <= (mpir_si b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->CompareTo(b) >= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator != (mpir_si b, MPEXPR_NAME^ a) { return IS_NULL(a) || !a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator == (mpir_si b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator < (MPEXPR_NAME^ a, double b) { return IS_NULL(a) || a->CompareTo(b) < 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator >= (MPEXPR_NAME^ a, double b) { return !IS_NULL(a) && a->CompareTo(b) >= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator > (MPEXPR_NAME^ a, double b) { return !IS_NULL(a) && a->CompareTo(b) > 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator <= (MPEXPR_NAME^ a, double b) { return IS_NULL(a) || a->CompareTo(b) <= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator != (MPEXPR_NAME^ a, double b) { return IS_NULL(a) || !a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator == (MPEXPR_NAME^ a, double b) { return !IS_NULL(a) && a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator < (double b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->CompareTo(b) > 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator >= (double b, MPEXPR_NAME^ a) { return IS_NULL(a) || a->CompareTo(b) <= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator > (double b, MPEXPR_NAME^ a) { return IS_NULL(a) || a->CompareTo(b) < 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator <= (double b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->CompareTo(b) >= 0; } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator != (double b, MPEXPR_NAME^ a) { return IS_NULL(a) || !a->Equals(b); } + + /// Compares two numbers. + /// If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed. + /// + /// Source value to compare + /// Source value to compare with + /// A boolean result of the comparison. + static bool operator == (double b, MPEXPR_NAME^ a) { return !IS_NULL(a) && a->Equals(b); } + + /// Calculates the sign (+1, 0, or -1) of the source value. + /// If the source is an expression, it is evaluated into a temporary variable before the sign is computed. + /// + /// +1 if the source is positive, -1 if negative, and 0 if zero. + int Sign() { IN_CONTEXT(this); return MP(sgn)(CTXT(0)); } + + #pragma endregion + }; + + #pragma endregion + + #pragma region concrete expressions + + DEFINE_BINARY_EXPRESSION_WITH_TWO (MPEXPR_NAME, Add, Flt) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Add, Flt, Ui) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Add, Flt, Si) + + DEFINE_BINARY_EXPRESSION_WITH_TWO (MPEXPR_NAME, Subtract, Flt) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Subtract, Flt, Ui) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_LEFT (MPEXPR_NAME, Subtract, Ui, Flt) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Subtract, Flt, Si) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_LEFT (MPEXPR_NAME, Subtract, Si, Flt) + + DEFINE_BINARY_EXPRESSION_WITH_TWO (MPEXPR_NAME, Multiply, Flt) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Multiply, Flt, Ui) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Multiply, Flt, Si) + + DEFINE_BINARY_EXPRESSION_WITH_TWO (MPEXPR_NAME, Divide, Flt) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Divide, Flt, Ui) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_LEFT (MPEXPR_NAME, Divide, Ui, Flt) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Divide, Flt, Si) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_LEFT (MPEXPR_NAME, Divide, Si, Flt) + + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, ShiftLeft, Flt, Bits) + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, ShiftRight, Flt, Bits) + + DEFINE_BINARY_EXPRESSION_WITH_BUILT_IN_RIGHT (MPEXPR_NAME, Power, Flt, Ui) + + DEFINE_UNARY_EXPRESSION_WITH_ONE (MPEXPR_NAME, Negate, Flt) + DEFINE_UNARY_EXPRESSION_WITH_ONE (MPEXPR_NAME, Abs, Flt) + + #pragma endregion + + #pragma region HugeFloat class + + /// + /// Multi-precision Float class. + /// + public ref class MPTYPE : MPEXPR_NAME + { + internal: + //fields + MP(ptr) _value; + + private: + //construction + void AllocateStruct() + { + _value = (MP(ptr))((*__gmp_allocate_func)(sizeof(MPSTRUCT))); + } + void FromString(String^ value, int base); + MPTYPE(bool initialize); + String^ ToString(int base, bool lowercase, int maxDigits); + + internal: + virtual void DeallocateStruct() + { + MP(clear)(_value); + (*__gmp_free_func)(_value, sizeof(MPSTRUCT)); + _value = nullptr; + } + + //assignment + virtual void AssignTo(MP(ptr) destination) override + { + if(destination != _value) + MP(set)(destination, _value); + } + virtual void ASSIGN_TO(EvaluationContext& context) override + { + CTXT(context.Index++) = _value; + } + + public: + #pragma region construction and disposal + + /// + /// Initializes a new float instance and sets its value to 0/1 + /// + MPTYPE(); + + /// + /// Initializes a new float instance, allocating enough memory to hold at least bits, and sets its value to 0. + /// All float operations are performed to the precision of the destination. + /// + /// Minimum number of bits the initially allocated memory should hold for the mantissa + /// the newly constructed instance + static MPTYPE^ Allocate(mp_bitcnt_t precision); + + /// + /// Initializes a new float instance and sets its value from the specified string, using leading characters to recognize the base: + /// 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise. + /// + /// string representing the initial value for the new instance. Whitespace in the string is ignored. + MPTYPE(String^ value) { FromString(value, 0); } + + /// + /// Initializes a new float instance and sets its value from the specified string + /// + /// string representing the initial value for the new instance. Whitespace in the string is ignored. + /// base the string is in. + /// The base may vary from 2 to 62, or if base is 0, then the leading characters are used: 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise. + /// For bases up to 36, case is ignored; upper-case and lower-case letters have the same value. + /// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61. + MPTYPE(String^ value, int base) { FromString(value, base); } + + /// + /// Initializes a new float instance and sets its value to the result of computing the source expression. + /// + /// the expression that will be computed, and the result set as the initial value of the new instance. + MPTYPE(MPEXPR_NAME^ value); + + /// + /// Initializes a new float instance and sets its value to the result of computing the source expression. + /// + /// the expression that will be computed, and the result set as the initial value of the new instance. + MPTYPE(IntegerExpression^ value); + + /// + /// Constructs and returns a new float instance with its value set to . + /// If the fraction is not in canonical form, Canonicalize() must be called. + /// + /// value for the initial value for the new float instance + MPTYPE(mpir_si value); + + /// + /// Constructs and returns a new float instance with its value set to . + /// If the fraction is not in canonical form, Canonicalize() must be called. + /// + /// value for the initial value for the new float instance + MPTYPE(mpir_ui value); + + /// + /// Constructs and returns a new float instance with its value set to the parameter. + /// There is no rounding, this conversion is exact. + /// + /// Initial value for the new float instance. This is an exact conversion. + MPTYPE(double value); + + //disposal + + //creating a destructor in C++ implements IDisposable. + + /// + /// Frees all memory allocated by the instance. + /// To minimize memory footprint, multi-precision objects should be disposed of when no longer used, instead of relying on the garbage collector to free the memory. + /// + ~MPTYPE() { this->!MPTYPE(); } + + /// + /// Frees all memory allocated by the instance. + /// To minimize memory footprint, multi-precision objects should be disposed of when no longer used, instead of relying on the garbage collector to free the memory. + /// + !MPTYPE() { if(_value != 0) DeallocateStruct(); } + + #pragma endregion + + #pragma region conversions + + /// + /// Converts the number to a string. + /// To avoid debugging performance problems, this method outputs at most the number of digits specified in MpirSettings.ToStringDigits. + /// If the number is larger, the least significant digits are shown with a leading ellipsis (i.e., [-]...NNNNN) + /// Setting MpirSettings.ToStringDigits to 0 removes the upper limit. + /// + /// A string representation of the number in decimal, possibly cut off if the number has more digits than MpirSettings.ToStringDigits. + virtual String^ ToString() override { return ToString(10, false, MpirSettings::ToStringDigits); } + + /// + /// Converts the number to a string in the specified base. + /// This method always produces the complete output regardless of the MpirSettings.ToStringDigits setting. + /// + /// The base to use for the output. The base can be from 2 to 62; uppercase letters represent digits 10-35 and lowercase letters represent digits 36-61. + /// A string representation of the number in the specified base. + String^ ToString(int base) { return ToString(base, false, 0); } + + /// + /// Converts the number to a string in the specified base. + /// This method always produces the complete output regardless of the MpirSettings.ToStringDigits setting. + /// + /// The base to use for the output. + /// The base can be from 2 to 62; Bases up to 36 use uppercase or lowercase letters based on the argument. + /// For bases larger than 36, the argument is ignored and uppercase letters represent digits 10-35 while lowercase letters represent digits 36-61. + /// Indicates if lowercase or uppercase letters should be used for the output. + /// This argument is ignored for bases larger than 36, where both uppercase and lowercase letters are used. + /// A string representation of the number in the specified base. + String^ ToString(int base, bool lowercase) { return ToString(base, lowercase, 0); } + +///// +///// Returns the absolute value of the number as a ulong. +///// If the number is too big, then just the least significant bits that do fit are returned. +///// The sign of the number is ignored, only the absolute value is used. +///// +///// The absolute value as a ulong, possibly truncated to the least significant bits only. +//mpir_ui ToUlong() { return MP(get_ui)(_value); } + +///// +///// Returns the value of the number as a long. +///// If the number is too big, then just the least significant bits that do fit are returned, with the same sign as the number. +///// When truncation occurs, the result is propobly not very useful. Call FitsLong() to check if the number will fit. +///// +///// The value as a ulong, possibly truncated to the least significant bits only. +//mpir_si ToLong() { return MP(get_si)(_value); } + + /// + /// Returns the value of the number as a double, truncating if necessary (rounding towards zero). + /// If the exponent from the conversion is too big, the result is system dependent. An infinity is returned where available. /// A hardware overflow trap may or may not occur. + /// + /// The value as a double, possibly truncated. + double ToDouble() { return MP(get_d)(_value); } + +///// +///// Returns the value of the number as a double, truncating if necessary (rounding towards zero), and returning the exponent separately. +///// The return is the mantissa, its absolute value will be in the range [0.5 - 1). ///// If the source value is zero, both mantissa and exponent are returned as 0. +///// +///// variable to store the exponent in. +///// The mantissa of the value as a double, possibly truncated. +//double ToDouble([Out] mpir_si% exp) +//{ +// mpir_si x; +// auto result = MP(get_d_2exp)(&x, _value); +// exp = x; +// return result; +//} + + #pragma endregion + + #pragma region assignment + + /// + /// When getting, returns this float. + /// When setting, sets the value of the float object to the value resulting from computing the supplied expression. + /// The getter is a no-op and never needs to be invoked directly, but makes compound operators such as +=, *=, etc. possible. + /// Do not set the Value of an object while it is contained in a hash table, because that changes its hash code. + /// + /// + /// MPIR types are implemented as reference types with value semantics. + /// Like Strings, the objects themselves are just lightweight pointers to data allocated elsewhere. + /// Unlike Strings, MPIR types are mutable. + /// Value semantics requires you to be able to code, a = b + c. + /// However, .Net (outside of C++) does not allow overloading the assignment operator, + /// and assigning references would necessitate some unnecessary duplication and extra memory allocations. + /// To solve this problem, MPIR.Net uses the property assignment. + /// The setter of the Value property does what an overloaded assignment operator would do in C++. + /// The syntax is a little different: a.Value = b + c, but it is fluent enough to become a quick habit, + /// and additionally reinforces the concept that an existing object can change its value while reusing internally allocated memory. + /// To this end, all overloaded operators and most functions that operate on MPIR types, + /// instead of eagerly computing a result, produce and return an expression that is basically a formula for the computation. + /// Expressions can then be composed using additional operators to achieve expression trees of arbitrary complexity. + /// All computations are deferred until an expression is assigned to the Value property of an MPIR object, + /// consumed by a method or operator that returns a primitive type, + /// or supplied as an argument to an MPIR type constructor. + /// The getter is a no-op defined to make possible constructs such as a.Value += 5, a.Value *= 10, etc. + /// Direct assignments such as a = b + c, a *= 10 will not compile because there is no implicit conversion from an expression. + /// Even if an implicit conversion were defined, such code would incur an extra allocation plus garbage collection, + /// and would not perform as well as doing the same operations on a.Value. + /// It would also not compile if the source were a "using" variable, as all method-local floats should be. + /// + property MPEXPR_NAME^ Value + { + void set(MPEXPR_NAME^ expr) { expr->AssignTo(_value); } + MPEXPR_NAME^ get() { return this; } + } + + /// + /// Sets the value of the float object. + /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code. + /// If the fraction is not in canonical form, Canonicalize() must be called. + /// + /// value for the new value for the object + void SetTo(mpir_ui value) { MP(set_ui)(_value, value); } + + /// + /// Sets the value of the float object. + /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code. + /// If the fraction is not in canonical form, Canonicalize() must be called. + /// + /// value for the new value for the object + void SetTo(mpir_si value) { MP(set_si)(_value, value); } + + /// + /// Sets the value of the float object. This is an exact conversion, there is no rounting. + /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code. + /// + /// new value for the object + void SetTo(double value) { MP(set_d)(_value, value); } + + /// + /// Sets the value of the float object. + /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code. + /// If the fraction is not in canonical form, Canonicalize() must be called. + /// + /// new value for the object. + /// May be an float or a pair of floats separated by a slash. + /// The string's leading characters may indicate base: + /// 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise + void SetTo(String^ value) { SetTo(value, 0); } + + /// + /// Sets the value of the float object. + /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code. + /// If the fraction is not in canonical form, Canonicalize() must be called. + /// + /// new value for the object + /// base the string is in. + /// The base may vary from 2 to 62, or if base is 0, then the leading characters are used: 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise. + /// For bases up to 36, case is ignored; upper-case and lower-case letters have the same value. + /// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61. + void SetTo(String^ value, int base); + + /// + /// Sets the value of the raitonal object. + /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code. + /// + /// new value for the object + void SetTo(IntegerExpression^ value) + { + EvaluationContext context; + value->AssignToInteger(context); + MP(set_z)(_value, CTXTI(0)); + } + + /// + /// Swaps the values of two floats. + /// This operation is a pointer swap and doesn't affect allocated memory. + /// Do not call this method while either object is contained in a hash table, because this would change their hash codes. + /// + /// Source number to swap this instance's value with + void Swap(MPTYPE^ a) + { + MP(ptr) temp = a->_value; + a->_value = _value; + _value = temp; + } + + #pragma endregion + + #pragma region Size checks + +///// +///// Returns the number of digits the number would take if written in the specified base. +///// The sign of the number is ignored, just the absolute value is used. +///// The result will be either exact or at most 2 characters too big. +///// If is a power of 2, the result will always be exact. +///// If the number is 0, the result is always 3. +///// This function can be used to estimate the space required when converting to a string. +///// The right amount of allocation is normally two more than the value returned, +///// one extra for a minus sign and one for the null-terminator. +///// A slash between numerator and denominator is accounted for. +///// Numeric base for the would-be string conversion, in the range from 2 to 62. +///// The number of digits the number would take written in the specified base, possibly 1 or 2 too big, not counting a leading minus. +//mp_size_t ApproximateSizeInBase(int base) { return mpz_sizeinbase(&_value->_mp_num, base) + mpz_sizeinbase(&_value->_mp_den, base) + 1; } + + #pragma endregion + + #pragma region IO + + /// + /// Outputs the float to the in raw binary format. + /// The number's numerator and denominator are written in sequence, each in a portable format, + /// with 4 bytes of size information, and that many bytes of limbs. + /// Both the size and the limbs are written in decreasing significance order (i.e., in big-endian). + /// The output can be read with Read(Stream). + /// The output cannot be read by MP(inp_raw) from GMP 1, because of changes necessary + /// for compatibility between 32-bit and 64-bit machines. + /// + /// Stream to output the number to + /// the number of bytes written, or 0 if an error occurs. + size_t Write(Stream^ stream); + + /// + /// Reads the float value from the in raw binary format, as it would have been written by Write(Stream). + /// The number's numerator and denominator are read in sequence, each in a portable format, + /// with 4 bytes of size information, and that many bytes of limbs. + /// Both the size and the limbs are written in decreasing significance order (i.e., in big-endian). + /// This routine can read the output from MP(out_raw) also from GMP 1, in spite of changes + /// necessary for compatibility between 32-bit and 64-bit machines. + /// + /// Stream to input the number from + /// the number of bytes read, or 0 if an error occurs. + size_t Read(Stream^ stream); + + /// + /// Outputs the float to the as a string of digits in decimal. + /// When writing multiple numbers that are to be read back with the Read(TextReader) method, + /// it is useful to separate the numbers with a character that is not a valid decimal digit. + /// This is because the Read method stops reading when it encounters a character that cannot represent a digit. + /// + /// Text writer to output the number to + /// the number of characters written + size_t Write(TextWriter^ writer) { return Write(writer, 0, false); } + + /// + /// Outputs the float to the as a string of digits in base . + /// When writing multiple numbers that are to be read back with the Read(TextReader) method, + /// it is useful to separate the numbers with a character that is not a valid digit in base . + /// This is because the Read method stops reading when it encounters a character that cannot represent a digit. + /// For hexadecimal, binary, or octal, no leading base indication is written. + /// Therefore, for bases other than 10, use the Read(reader, base) overload rather than Read(reader) to read the number back. + /// + /// Text writer to output the number to + /// The base to use for the output. + /// The base can be from 2 to 62; uppercase letters represent digits 10-35 while lowercase letters represent digits 36-61. + /// the number of characters written + size_t Write(TextWriter^ writer, int base) { return Write(writer, base, false); } + + /// + /// Outputs the float to the as a string of digits in base . + /// When writing multiple numbers that are to be read back with the Read(TextReader) method, + /// it is useful to separate the numbers with a character that is not a valid digit in base . + /// This is because the Read method stops reading when it encounters a character that cannot represent a digit. + /// For hexadecimal, binary, or octal, no leading base indication is written. + /// Therefore, for bases other than 10, use the Read(reader, base) overload rather than Read(reader) to read the number back. + /// + /// Text writer to output the number to + /// The base to use for the output. + /// The base can be from 2 to 62; Bases up to 36 use uppercase or lowercase letters based on the argument. + /// For bases larger than 36, the argument is ignored and uppercase letters represent digits 10-35 while lowercase letters represent digits 36-61. + /// Indicates if lowercase or uppercase letters should be used for the output. + /// This argument is ignored for bases larger than 36, where both uppercase and lowercase letters are used. + /// the number of characters written + size_t Write(TextWriter^ writer, int base, bool lowercase); + + /// + /// Inputs the number as a possibly white-space preceeded string. + /// The base of the number is determined from the leading characters: 0x or 0X for hexadecimal, 0b or 0B for binary, 0 for octal, decimal otherwise. + /// Reading terminates at end-of-stream, or up to but not including a character that is not a valid digit. + /// This method reads the output of a Write(TextWriter) when decimal base is used. + /// For hexadecimal, binary, or octal, because Write(TextWriter) doesn't write leading base indication characters, + /// using this overload of Read will fail to recognize the correct base. + /// Text reader to input the number from + /// the number of characters read + size_t Read(TextReader^ reader) { return Read(reader, 0); } + + /// + /// Inputs the number as a possibly white-space preceeded string in base from the . + /// Reading terminates at end-of-stream, or up to but not including a character that is not a valid digit. + /// This method reads the output of a Write(TextWriter) method. + /// + /// Text reader to input the number from + /// The base to use for the input. + /// The base can be from 2 to 62; For bases up to 36 case is ignored. + /// For bases larger than 36, uppercase letters represent digits 10-35 while lowercase letters represent digits 36-61. + /// If 0, the base of the number is determined from the leading characters: 0x or 0X for hexadecimal, 0b or 0B for binary, 0 for octal, decimal otherwise. + /// Note that the leading base characters are not written by the Write method. + /// the number of characters read + size_t Read(TextReader^ reader, int base); + +///// +///// Imports the number from arbitrary words of binary data. +///// No sign information is taken from the data, the imported number will be positive or zero. +///// +///// Type of element in the data array. This must be a value type, but does not need to represent a single limb. Data is interpreted as a flat byte array. +///// Array of binary "limbs" to import from. +///// Elements don't necessarily need to be of the size; the data is interpreted as a flat byte array. +///// Number of "limbs" to import +///// Number of bytes per "limb." +///// Specifies the order of the "limbs." +///// Specifies the byte order within each "limb." +///// The number of most-significant bits to ignore in each "limb." +//generic where T : value class void Import(array^ data, size_t limbCount, int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails) +//{ +// if(limbCount == 0) +// { +// MP(set_ui)(_value, 0); +// return; +// } + +// PIN(data); +// MP(import)(_value, limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, pinned_data); +//} + +///// +///// Exports the absolute value of the number to arbitrary words of binary data. +///// The sign of op is ignored. +///// +///// Type of element in the data array. This must be a value type, but does not need to represent a single limb. Data is interpreted as a flat byte array. +///// Array of binary "limbs" to export to. +///// Elements don't necessarily need to be of the size; the data is interpreted as a flat byte array. +///// The total size of the array in bytes must be sufficient for the export. +///// Number of bytes per "limb." +///// Specifies the order of the "limbs." +///// Specifies the byte order within each "limb." +///// The number of most-significant bits to reserve, and set to zero, in each "limb." +///// The number of limbs exported. +///// If the number is non-zero, then the most significant word produced will be non-zero. +///// If the number is zero, then the count returned will be zero and nothing written to the data. +//generic where T : value class size_t Export(array^ data, int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails) +//{ +// PIN(data); +// size_t limbCount; +// MP(export)(pinned_data, &limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, _value); +// return limbCount; +//} + +// /// +// /// Exports the absolute value of the number to arbitrary words of binary data. An array of type T is allocated for the export. +// /// The sign of op is ignored. +// /// +// /// Type of element in the data array. This must be a value type, but does not need to represent a single limb. Data is interpreted as a flat byte array. +// /// Number of bytes per "limb." +// /// Specifies the order of the "limbs." +// /// Specifies the byte order within each "limb." +// /// The number of most-significant bits to reserve, and set to zero, in each "limb." +// /// An array of type T containing the exported limb data. +// /// If the number is non-zero, then the most significant word produced will be non-zero. +// /// If the number is zero, then a zero-length array is returned. +// generic where T : value class array^ Export(int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails) +// { +// if(this->Sign() == 0) +// return gcnew array(0); + +// auto bitsPerLimb = 8 * bytesPerLimb - nails; +// auto limbCount = (MP(sizeinbase)(_value, 2) - 1) / bitsPerLimb + 1; +// auto arrayCount = (limbCount * bytesPerLimb - 1) / sizeof(T) + 1; +// auto data = gcnew array(arrayCount); + +// PIN(data); +// MP(export)(pinned_data, &limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, _value); +// return data; +// } + +//internal: +// size_t ReadNoWhite(TextReader^ reader, int base, size_t nread); + +//public: + +// /// +// /// Returns the specified limb of the number. +// /// The least significant limb is zero. +// /// The sign of the number is ignored. +// /// +// /// The index of the limb to return. +// /// The least significant limb is zero. +// /// If the index is outside the range 0 to Size()-1, zero is returned. +// /// The specified limb, or zero if is outside of the valid range. +// size_t GetLimb(mp_size_t index) { return MP(getlimbn)(_value, index); } + + #pragma endregion + }; + + #pragma endregion +}; diff --git a/mpir.net/mpir.net/HugeInt.h b/mpir.net/mpir.net/HugeInt.h index 384ecad7..bab4cb8b 100644 --- a/mpir.net/mpir.net/HugeInt.h +++ b/mpir.net/mpir.net/HugeInt.h @@ -55,6 +55,7 @@ namespace MPIR { ref class MpirRandom; ref class RationalExpression; + ref class FloatExpression; ref class MPTYPE; ref class MPEXPR(Divide); ref class MPEXPR(DivideUi); @@ -1650,6 +1651,13 @@ namespace MPIR /// new value for the object void SetTo(RationalExpression^ value); + /// + /// Sets the value of the integer object. Any fractional portion is truncated. + /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code. + /// + /// new value for the object + void SetTo(FloatExpression^ value); + /// /// Swaps the values of two integers. /// This operation is a pointer swap and doesn't affect allocated memory.