From ef95a16dab64c6cd2871cebe8a374e98f155f4af Mon Sep 17 00:00:00 2001 From: Alex Dyachenko Date: Mon, 16 Jun 2014 16:46:14 -0400 Subject: [PATCH] Float Changing precision. MPIR 2.7.0 section 7.1 completed. --- .../HugeFloatTests/ConstructionAndDisposal.cs | 67 +++++++++++++++++-- .../mpir.net-tests/Utilities/Accessors.cs | 11 --- mpir.net/mpir.net/HugeFloat.h | 35 ++++++++++ 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs index f3d38693..8cf8df43 100644 --- a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs +++ b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs @@ -31,7 +31,7 @@ namespace MPIR.Tests.HugeFloatTests using (var a = new HugeFloat()) { Assert.AreEqual(0, a.NumberOfLimbsUsed()); - Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(128UL, a.Precision); Assert.AreEqual(128UL, a._allocatedPrecision); Assert.AreNotEqual(IntPtr.Zero, a.Limbs()); Assert.AreEqual(0, a.Exponent()); @@ -46,7 +46,6 @@ namespace MPIR.Tests.HugeFloatTests a.Dispose(); Assert.AreEqual(0, a.NumberOfLimbsUsed()); - Assert.AreEqual(0, a.Precision()); Assert.AreEqual(IntPtr.Zero, a.Limbs()); } @@ -57,7 +56,7 @@ namespace MPIR.Tests.HugeFloatTests using (var a = new HugeFloat(n)) { Assert.AreEqual(128UL, a._allocatedPrecision); - Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(128UL, a.Precision); Assert.AreEqual(1, a.Exponent()); Assert.AreEqual("0." + n.ToString("X") + "@16", a.ToString(16)); } @@ -70,7 +69,7 @@ namespace MPIR.Tests.HugeFloatTests using(var a = new HugeFloat(-n)) { Assert.AreEqual(128UL, a._allocatedPrecision); - Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(128UL, a.Precision); Assert.AreEqual(1, a.Exponent()); Assert.AreEqual("-0." + n.ToString("X") + "@16", a.ToString(16)); } @@ -83,7 +82,7 @@ namespace MPIR.Tests.HugeFloatTests using(var a = new HugeFloat(n)) { Assert.AreEqual(128UL, a._allocatedPrecision); - Assert.AreEqual(3, a.Precision()); + Assert.AreEqual(128UL, a.Precision); Assert.AreEqual(1, a.Exponent()); Assert.AreEqual("0." + n.ToString("X") + "@16", a.ToString(16)); } @@ -112,7 +111,7 @@ namespace MPIR.Tests.HugeFloatTests { using (var a = HugeFloat.Allocate(193)) { - Assert.AreEqual(5, a.Precision()); + Assert.AreEqual(256UL, a.Precision); Assert.AreEqual(256UL, a._allocatedPrecision); Assert.AreEqual("0", a.ToString()); } @@ -164,5 +163,61 @@ namespace MPIR.Tests.HugeFloatTests FloatAssert.AreEqual("2340958273409578234095823045723490588.", b); } } + + [TestMethod] + public void FloatSetPrecision() + { + using (var a = new HugeFloat(1)) + using (var b = new HugeFloat()) + { + a.Value = a/3; + b.Value = a; + Assert.AreEqual(128UL, a._allocatedPrecision); + Assert.AreEqual(128UL, a.Precision); + Assert.AreEqual("0.3333333333333333333333333333333333333333@0", a.ToString()); + + a.Precision = 64; + Assert.AreEqual(128UL, a._allocatedPrecision); + Assert.AreEqual(64UL, a.Precision); + Assert.AreEqual("0.333333333333333333333@0", a.ToString()); + Assert.AreEqual(a, b); + + a.Precision = 128; + Assert.AreEqual("0.3333333333333333333333333333333333333333@0", a.ToString()); + + a.Precision = 64; + a.SetTo(1); + a.Value = a / 3; + Assert.AreNotEqual(a, b); + Assert.AreEqual("0.333333333333333333333@0", a.ToString()); + + a.Precision = 128; + Assert.AreNotEqual(a, b); + } + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void FloatSettingPrecisionOverAllocated() + { + using (var a = new HugeFloat()) + { + a.Precision++; + } + } + + [TestMethod] + public void FloatReallocate() + { + using (var a = HugeFloat.Allocate(128)) + { + Assert.AreEqual(128UL, a._allocatedPrecision); + Assert.AreEqual(128UL, a.Precision); + + a.Reallocate(256); + Assert.AreEqual(256UL, a._allocatedPrecision); + Assert.AreEqual(256UL, a.Precision); + } + } } } diff --git a/mpir.net/mpir.net-tests/Utilities/Accessors.cs b/mpir.net/mpir.net-tests/Utilities/Accessors.cs index 15825bb8..76496b00 100644 --- a/mpir.net/mpir.net-tests/Utilities/Accessors.cs +++ b/mpir.net/mpir.net-tests/Utilities/Accessors.cs @@ -171,17 +171,6 @@ namespace MPIR.Tests 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) diff --git a/mpir.net/mpir.net/HugeFloat.h b/mpir.net/mpir.net/HugeFloat.h index cafb4e77..8e8962ca 100644 --- a/mpir.net/mpir.net/HugeFloat.h +++ b/mpir.net/mpir.net/HugeFloat.h @@ -1070,6 +1070,41 @@ namespace MPIR #pragma region Size checks + /// + /// Gets or sets the effective precision of the number without changing the memory allocated. + /// The number of bits cannot exceed the precision with which the variable was initialized or last reallocated. + /// The value of the number is unchanged, and in particular if it previously had a higher precision it will retain that higher precision. + /// New values assigned to the Value property will use the new precision. + /// This is an efficient way to use a float variable at different precisions during a calculation, + /// perhaps to gradually increase precision in an iteration, or just to use various different + /// precisions for different purposes during a calculation. + /// The number can be safely disposed after modifying its precision (this would not be the case in unmanaged MPIR). + /// + property mp_bitcnt_t Precision + { + mp_bitcnt_t get() { return MP(get_prec)(_value); } + void set(mp_bitcnt_t value) + { + if(value > _allocatedPrecision) + throw gcnew ArgumentException("Cannot set precision higher than allocated"); + + MP(set_prec_raw)(_value, value); + } + } + + /// + /// Set the precision of rop to be at least prec bits, reallocating its limbs data. + /// The value in rop will be truncated to the new precision. + /// This function requires a call to realloc, and so should not be used in a tight loop. + /// + /// Minimum number of bits the allocated memory should hold for the mantissa. + void Reallocate(mp_bitcnt_t precision) + { + MP(set_prec_raw)(_value, _allocatedPrecision); + MP(set_prec)(_value, precision); + _allocatedPrecision = precision; + } + ///// ///// 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.