diff --git a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs index da55ceb7..f3d38693 100644 --- a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs +++ b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs @@ -20,267 +20,148 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/. using System; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace MPIR.Tests.HugeRationalTests +namespace MPIR.Tests.HugeFloatTests { [TestClass] public class ConstructionAndDisposal { [TestMethod] - public void RationalDefaultConstructor() + public void FloatDefaultConstructor() { - using (var a = new HugeRational()) + using (var a = new HugeFloat()) { - Assert.AreNotEqual(0, a.NumeratorNumberOfLimbsAllocated()); - Assert.AreEqual(0, a.NumeratorNumberOfLimbsUsed()); - Assert.AreNotEqual(IntPtr.Zero, a.NumeratorLimbs()); - Assert.AreEqual("0", a.Numerator.ToString()); - - Assert.AreNotEqual(0, a.DenominatorNumberOfLimbsAllocated()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsUsed()); - Assert.AreNotEqual(IntPtr.Zero, a.DenominatorLimbs()); - Assert.AreEqual("1", a.Denominator.ToString()); + Assert.AreEqual(0, a.NumberOfLimbsUsed()); + Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(128UL, a._allocatedPrecision); + Assert.AreNotEqual(IntPtr.Zero, a.Limbs()); + Assert.AreEqual(0, a.Exponent()); + Assert.AreEqual("0", a.ToString()); } } [TestMethod] - public void RationalNumerator() + public void FloatDispose() { - using (var a = new HugeRational()) - { - a.Numerator.Dispose(); - Assert.AreNotEqual(0, a.Numerator.NumberOfLimbsAllocated()); - Assert.AreEqual("0", a.Numerator.ToString()); - } - } - - [TestMethod] - public void RationalDenominator() - { - using (var a = new HugeRational()) - { - a.Denominator.Dispose(); - Assert.AreNotEqual(0, a.Denominator.NumberOfLimbsAllocated()); - Assert.AreEqual("1", a.Denominator.ToString()); - } - } - - [TestMethod] - public void RationalDispose() - { - var a = new HugeRational(); + var a = new HugeFloat(); a.Dispose(); - - Assert.AreEqual(0, a.NumeratorNumberOfLimbsAllocated()); - Assert.AreEqual(0, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(IntPtr.Zero, a.NumeratorLimbs()); - Assert.AreEqual(0, a.DenominatorNumberOfLimbsAllocated()); - Assert.AreEqual(0, a.DenominatorNumberOfLimbsUsed()); - Assert.AreEqual(IntPtr.Zero, a.DenominatorLimbs()); + Assert.AreEqual(0, a.NumberOfLimbsUsed()); + Assert.AreEqual(0, a.Precision()); + Assert.AreEqual(IntPtr.Zero, a.Limbs()); } [TestMethod] - public void RationalConstructorFromLong() + public void FloatConstructorFromLong() { - var n = "123456789123456"; - var d = "12764787846358441471"; - using (var a = new HugeRational(long.Parse(n), ulong.Parse(d))) + var n = 0x3123456789123456L; + using (var a = new HugeFloat(n)) { - Assert.AreEqual(1, a.NumeratorNumberOfLimbsAllocated()); - Assert.AreEqual(1, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsAllocated()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsUsed()); - Assert.AreEqual(n + "/" + d, a.ToString()); + Assert.AreEqual(128UL, a._allocatedPrecision); + Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(1, a.Exponent()); + Assert.AreEqual("0." + n.ToString("X") + "@16", a.ToString(16)); } } [TestMethod] - public void RationalConstructorFromLongNegative() + public void FloatConstructorFromLongNegative() { - var n = "-123456789123456"; - var d = "12764787846358441471"; - using (var a = new HugeRational(long.Parse(n), ulong.Parse(d))) + var n = 0x3123456789123456L; + using(var a = new HugeFloat(-n)) { - Assert.AreEqual(1, a.NumeratorNumberOfLimbsAllocated()); - Assert.AreEqual(-1, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsAllocated()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsUsed()); - Assert.AreEqual(n + "/" + d, a.ToString()); + Assert.AreEqual(128UL, a._allocatedPrecision); + Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(1, a.Exponent()); + Assert.AreEqual("-0." + n.ToString("X") + "@16", a.ToString(16)); } } [TestMethod] - public void RationalConstructorFromULong() + public void FloatConstructorFromULong() { - var d = "12764787846358441471"; - using (var a = new HugeRational(ulong.MaxValue, ulong.Parse(d))) + var n = ulong.MaxValue; + using(var a = new HugeFloat(n)) { - Assert.AreEqual(1, a.NumeratorNumberOfLimbsAllocated()); - Assert.AreEqual(1, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsAllocated()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsUsed()); - Assert.AreEqual(ulong.MaxValue.ToString(), a.Numerator.ToString()); - Assert.AreEqual(ulong.MaxValue.ToString() + "/" + d, a.ToString()); + Assert.AreEqual(128UL, a._allocatedPrecision); + Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(1, a.Exponent()); + Assert.AreEqual("0." + n.ToString("X") + "@16", a.ToString(16)); } } [TestMethod] - public void RationalConstructorFromDouble() + public void FloatConstructorFromDouble() { - using (var a = new HugeRational(123456789123456.75)) + using (var a = new HugeFloat(123456789123456.75)) { - Assert.AreEqual("493827156493827/4", a.ToString()); + FloatAssert.AreEqual("123456789123456.75", a); } } [TestMethod] - public void RationalConstructorFromDoubleNegative() + public void FloatConstructorFromDoubleNegative() { - using (var a = new HugeRational(-123456789123456.75)) + using (var a = new HugeFloat(-123456789123456.75)) { - Assert.AreEqual("-493827156493827/4", a.ToString()); + FloatAssert.AreEqual("-123456789123456.75", a); } } [TestMethod] - public void RationalAllocate() + public void FloatAllocate() { - using (var a = HugeRational.Allocate(129, 193)) + using (var a = HugeFloat.Allocate(193)) { - Assert.AreEqual(3, a.NumeratorNumberOfLimbsAllocated()); - Assert.AreEqual(0, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(4, a.DenominatorNumberOfLimbsAllocated()); - Assert.AreEqual(1, a.DenominatorNumberOfLimbsUsed()); - Assert.AreEqual("0/1", a.ToString()); + Assert.AreEqual(5, a.Precision()); + Assert.AreEqual(256UL, a._allocatedPrecision); + Assert.AreEqual("0", a.ToString()); } } [TestMethod] - public void RationalCanonicalize() + public void FloatStringConstructor() { - using (var a = new HugeRational(198, 15)) + var n = "5432109876543212345789.70515331128527330659"; + using (var a = new HugeFloat(n)) { - a.Denominator.Value = -a.Denominator; - Assert.AreEqual("198/-15", a.ToString()); - a.Canonicalize(); - Assert.AreEqual("-66/5", a.ToString()); - } - } - - [TestMethod] - public void RationalStringConstructor() - { - var n = "5432109876543212345789023245987/362736035870515331128527330659"; - using (var a = new HugeRational(n)) - { - Assert.AreEqual(2, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(n, a.ToString()); - } - } - - [TestMethod] - public void RationalStringConstructorNumeratorOnly() - { - var n = "5432109876543212345789023245987"; - using(var a = new HugeRational(n)) - { - Assert.AreEqual(2, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(n + "/1", a.ToString()); + FloatAssert.AreEqual(n, a); } } [TestMethod] [ExpectedException(typeof(ArgumentException))] - public void RationalStringConstructorInvalid() + public void FloatStringConstructorInvalid() { - var a = new HugeRational("12345A"); + var a = new HugeFloat("12345A"); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void RationalStringConstructorInvalid2() + public void FloatStringConstructorHex() { - var a = new HugeRational("12345/54321A"); - } - - [TestMethod] - public void RationalStringConstructorHex() - { - using (var i = new HugeInt("362736035870515331128527330659")) + var n = "143210ABCDEF32123457ACDB324.59879"; + using (var a = new HugeFloat(n, 16)) { - var d = i.ToString(16); - var n = "143210ABCDEF32123457ACDB324598799"; - using (var a = new HugeRational(n + "/" + d, 16)) - { - Assert.AreEqual(n, a.Numerator.ToString(16)); - Assert.AreEqual(3, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(i, a.Denominator); - } + Assert.AreEqual("0.143210ABCDEF32123457ACDB32459879@27", a.ToString(16)); } } [TestMethod] - public void RationalStringConstructorHexPrefix() + public void FloatConstructorFromExpression() { - using (var i = new HugeInt("362736035870515331128527330659")) - { - var d = i.ToString(16); - var n = "143210ABCDEF32123457ACDB324598799"; - using (var a = new HugeRational("0x" + n + "/0x" + d)) - { - Assert.AreEqual(n + "/" + d, a.ToString(16)); - Assert.AreEqual(i, a.Denominator); - } - } - } - - [TestMethod] - public void RationalStringAssignmentHexPrefix() - { - using (var i = new HugeInt("362736035870515331128527330659")) - { - var d = i.ToString(16); - var n = "143210ABCDEF32123457ACDB324598799"; - using (var a = new HugeRational("0x" + n + "/0x" + d)) - { - Assert.AreEqual(n + "/" + d, a.ToString(16)); - Assert.AreEqual(n + "/" + d, a.ToString(16, false)); - Assert.AreEqual((n + "/" + d).ToLower(), a.ToString(16, true)); - a.SetTo("-0x" + n + "/0x17"); - Assert.AreEqual("-" + n + "/17", a.ToString(16)); - } - } - } - - [TestMethod] - public void RationalConstructorFromExpression() - { - using (var a = new HugeRational("2340958273409578234095823045723490587/362736035870515331128527330659")) - using (var b = new HugeRational(a + 1)) + using (var a = new HugeFloat("29340273582305894258424059.2345293574")) + using (var b = new HugeFloat(a + 1)) { Assert.AreEqual(a + 1, b); } } [TestMethod] - public void RationalConstructorFromIntExpression() + public void FloatConstructorFromIntExpression() { using (var a = new HugeInt("2340958273409578234095823045723490587")) - using (var b = new HugeRational(a + 1)) + using (var b = new HugeFloat(a + 1)) { - Assert.AreEqual("2340958273409578234095823045723490588/1", b.ToString()); - } - } - - [TestMethod] - public void RationalConstructorFromIntExpression2() - { - using (var a = new HugeInt("2340958273409578234095823045723490587")) - using (var d = new HugeInt("362736035870515331128527330659")) - using (var b = new HugeRational(a + 2, d * 2)) - { - Assert.AreEqual(a + 2, b.Numerator); - Assert.AreEqual(d * 2, b.Denominator); + FloatAssert.AreEqual("2340958273409578234095823045723490588.", b); } } } diff --git a/mpir.net/mpir.net-tests/Utilities/Accessors.cs b/mpir.net/mpir.net-tests/Utilities/Accessors.cs index b11b464d..15825bb8 100644 --- a/mpir.net/mpir.net-tests/Utilities/Accessors.cs +++ b/mpir.net/mpir.net-tests/Utilities/Accessors.cs @@ -38,7 +38,7 @@ namespace MPIR.Tests _intPtrConstructor = typeof(IntPtr).GetConstructor(new[] { Type.GetType("System.Void*") }); } - private static FieldInfo GetAccessor(string name) + internal static FieldInfo GetAccessor(string name) { return typeof(T).GetField(name, BindingFlags.NonPublic | BindingFlags.Instance); } @@ -163,4 +163,56 @@ namespace MPIR.Tests } } } + + internal static class FloatAccessors + { + internal static IntPtr _value(this HugeFloat x) + { + return Accessors._value(x); + } + + internal static int Precision(this HugeFloat x) + { + if(_value(x) == IntPtr.Zero) + return 0; + + unsafe + { + return ((int*)_value(x).ToPointer())[0]; + } + } + + internal static int NumberOfLimbsUsed(this HugeFloat x) + { + if(_value(x) == IntPtr.Zero) + return 0; + + unsafe + { + return ((int*)_value(x).ToPointer())[1]; + } + } + + internal static int Exponent(this HugeFloat x) + { + if(_value(x) == IntPtr.Zero) + return 0; + + unsafe + { + return ((int*)_value(x).ToPointer())[2]; + } + } + + internal static IntPtr Limbs(this HugeFloat x) + { + if(_value(x) == IntPtr.Zero) + return IntPtr.Zero; + + unsafe + { + return new IntPtr((void**)((int*)_value(x).ToPointer() + 3)); + } + } + } } diff --git a/mpir.net/mpir.net/HugeFloat.cpp b/mpir.net/mpir.net/HugeFloat.cpp index 4ab277c3..c57ca194 100644 --- a/mpir.net/mpir.net/HugeFloat.cpp +++ b/mpir.net/mpir.net/HugeFloat.cpp @@ -33,19 +33,24 @@ namespace MPIR { AllocateStruct(); MP(init)(_value); + _allocatedPrecision = MP(get_prec)(_value); } MPTYPE::MPTYPE(bool initialize) { AllocateStruct(); if(initialize) + { MP(init)(_value); + _allocatedPrecision = MP(get_prec)(_value); + } } MPTYPE::MPTYPE(MPEXPR_NAME^ value) { AllocateStruct(); MP(init)(_value); + _allocatedPrecision = MP(get_prec)(_value); value->AssignTo(_value); } @@ -53,6 +58,7 @@ namespace MPIR { AllocateStruct(); MP(init)(_value); + _allocatedPrecision = MP(get_prec)(_value); SetTo(value); } @@ -60,6 +66,7 @@ namespace MPIR { auto result = gcnew MPTYPE(false); MP(init2)(result->_value, precision); + result->_allocatedPrecision = MP(get_prec)(result->_value); return result; } @@ -67,6 +74,7 @@ namespace MPIR { AllocateStruct(); MP(init)(_value); + _allocatedPrecision = MP(get_prec)(_value); IntPtr ptr = Marshal::StringToHGlobalAnsi(value); bool success = 0 == MP(set_str)(_value, (char*)(void*)ptr, base); @@ -93,18 +101,21 @@ namespace MPIR { AllocateStruct(); MP(init_set_si)(_value, value); + _allocatedPrecision = MP(get_prec)(_value); } MPTYPE::MPTYPE(mpir_ui value) { AllocateStruct(); MP(init_set_ui)(_value, value); + _allocatedPrecision = MP(get_prec)(_value); } MPTYPE::MPTYPE(double value) { AllocateStruct(); MP(init_set_d)(_value, value); + _allocatedPrecision = MP(get_prec)(_value); } #pragma endregion diff --git a/mpir.net/mpir.net/HugeFloat.h b/mpir.net/mpir.net/HugeFloat.h index 78f064a0..cafb4e77 100644 --- a/mpir.net/mpir.net/HugeFloat.h +++ b/mpir.net/mpir.net/HugeFloat.h @@ -759,8 +759,6 @@ namespace MPIR void AllocateStruct() { _value = (MP(ptr))((*__gmp_allocate_func)(sizeof(MPSTRUCT))); - //todo: move this to wherever init is called - _allocatedPrecision = MP(get_prec)(_value); } void FromString(String^ value, int base); MPTYPE(bool initialize); @@ -794,6 +792,12 @@ namespace MPIR DefaultPrecision = sizeof(mpir_ui) * 8 * 2; //2 limbs } + /// + /// Gets or sets the default precision of a float variable in bits. + /// The actual precision may be slightly greater if the value is not a whole limb multiple. + /// All subsequently constructed variables will use this precision, but previously constructed variables are unaffected. + /// The initial default value is 2 limbs. + /// static property mp_bitcnt_t DefaultPrecision { mp_bitcnt_t get() { return MP(get_default_prec)(); } @@ -801,8 +805,9 @@ namespace MPIR } /// - /// Initializes a new float instance and sets its value to 0/1 - /// + /// Initializes a new float instance and sets its value to 0/1. + /// The precision of the new variable's mantissa is set from the static DefaultPrecision property. + /// MPTYPE(); /// @@ -1271,6 +1276,7 @@ namespace MPIR /// Computes the square root 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. /// + /// source number to take the square root of /// An expression object that, when assigned to the Value property or consumed by a primitive-returning method, computes the requested operation static MPEXPR_NAME^ SquareRoot(mpir_ui a) { return gcnew MPEXPR(SquareRootUi)(a); }