From d74453427c36b44fc241dd030aee2e1f4430313e Mon Sep 17 00:00:00 2001 From: Alex Dyachenko Date: Wed, 19 Nov 2014 12:51:21 -0500 Subject: [PATCH] Float construction/disposal tests. Implemented float ToString(). --- .../mpir.net-tests/mpir.net-tests.csproj | 7 +- .../HugeFloatTests/ConstructionAndDisposal.cs | 251 +++++------------- .../mpir.net-tests/Utilities/Accessors.cs | 52 ++++ mpir.net/mpir.net/HugeFloat.cpp | 50 +++- mpir.net/mpir.net/HugeFloat.h | 14 +- 5 files changed, 177 insertions(+), 197 deletions(-) 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 65a8c1c6..87dd371e 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 @@ -94,6 +94,9 @@ + + HugeFloatTests\ConstructionAndDisposal.cs + HugeIntTests\Arithmetic.cs @@ -164,9 +167,7 @@ mpir.net - - - + diff --git a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs index da55ceb7..8094258a 100644 --- a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs +++ b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs @@ -20,267 +20,160 @@ 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.AreNotEqual(0, a.NumberOfLimbsAllocated()); + Assert.AreEqual(0, a.NumberOfLimbsUsed()); + Assert.AreEqual(0, a.Exponent()); + Assert.AreNotEqual(IntPtr.Zero, a.Limbs()); + 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.NumberOfLimbsAllocated()); + Assert.AreEqual(0, a.NumberOfLimbsUsed()); + 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))) + using (var a = new HugeFloat(long.Parse(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(2, a.NumberOfLimbsAllocated()); + Assert.AreEqual(1, a.NumberOfLimbsUsed()); + Assert.IsTrue(a.Exponent() > 0); + Assert.AreEqual("0." + n + "@15", a.ToString()); } } [TestMethod] - public void RationalConstructorFromLongNegative() + public void FloatConstructorFromLongNegative() { var n = "-123456789123456"; - var d = "12764787846358441471"; - using (var a = new HugeRational(long.Parse(n), ulong.Parse(d))) + using (var a = new HugeFloat(long.Parse(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(2, a.NumberOfLimbsAllocated()); + Assert.AreEqual(-1, a.NumberOfLimbsUsed()); + Assert.IsTrue(a.Exponent() > 0); + Assert.AreEqual("-0." + n.Substring(1) + "@15", a.ToString()); } } [TestMethod] - public void RationalConstructorFromULong() + public void FloatConstructorFromULong() { - var d = "12764787846358441471"; - using (var a = new HugeRational(ulong.MaxValue, ulong.Parse(d))) + using (var a = new HugeFloat(ulong.MaxValue)) { - 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(2, a.NumberOfLimbsAllocated()); + Assert.AreEqual(1, a.NumberOfLimbsUsed()); + Assert.IsTrue(a.Exponent() > 0); + var n = ulong.MaxValue.ToString(); + Assert.AreEqual("0." + n + "@" + n.Length, a.ToString()); } } [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()); + Assert.AreEqual("0.12345678912345675@15", a.ToString()); } } [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()); + Assert.AreEqual("-0.12345678912345675@15", a.ToString()); } } [TestMethod] - public void RationalAllocate() + public void FloatAllocate() { - using (var a = HugeRational.Allocate(129, 193)) + using (var a = HugeFloat.Allocate(129)) { - 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(4, a.NumberOfLimbsAllocated()); + Assert.AreEqual(0, a.NumberOfLimbsUsed()); + Assert.AreEqual("0", a.ToString()); + + var n = "234095827340957823409582587"; + a.SetTo(n); + Assert.AreEqual("0." + n + "@" + n.Length, a.ToString()); } } [TestMethod] - public void RationalCanonicalize() + public void FloatStringConstructor() { - using (var a = new HugeRational(198, 15)) + var n = "0.54321098765432123457@28"; + 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(2, a.NumberOfLimbsAllocated()); Assert.AreEqual(n, a.ToString()); } } [TestMethod] - public void RationalStringConstructorNumeratorOnly() + [ExpectedException(typeof(ArgumentException))] + public void FloatStringConstructorInvalid() { - var n = "5432109876543212345789023245987"; - using(var a = new HugeRational(n)) + var a = new HugeFloat("12345A"); + } + + [TestMethod] + public void FloatStringConstructorHex() + { + var n = "143210ABCDEF321234"; + using (var a = new HugeFloat(n, 16)) { - Assert.AreEqual(2, a.NumeratorNumberOfLimbsUsed()); - Assert.AreEqual(n + "/1", a.ToString()); + Assert.AreEqual("0." + n + "@18", a.ToString(16)); } } [TestMethod] [ExpectedException(typeof(ArgumentException))] - public void RationalStringConstructorInvalid() + public void FloatStringConstructorHexPrefix() { - var a = new HugeRational("12345A"); + var n = "0x143210ABCDEF32123457ACDB324598799"; + var a = new HugeFloat(n); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void RationalStringConstructorInvalid2() + public void FloatConstructorFromExpression() { - var a = new HugeRational("12345/54321A"); - } - - [TestMethod] - public void RationalStringConstructorHex() - { - using (var i = new HugeInt("362736035870515331128527330659")) - { - 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); - } - } - } - - [TestMethod] - public void RationalStringConstructorHexPrefix() - { - 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("2340958273409578234095823045.5")) + 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 a = new HugeInt("234095827340957823409582587")) + 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); + Assert.AreEqual("0.23409582734095782341@27", b.ToString()); } } } diff --git a/mpir.net/mpir.net-tests/Utilities/Accessors.cs b/mpir.net/mpir.net-tests/Utilities/Accessors.cs index b11b464d..65506600 100644 --- a/mpir.net/mpir.net-tests/Utilities/Accessors.cs +++ b/mpir.net/mpir.net-tests/Utilities/Accessors.cs @@ -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 NumberOfLimbsAllocated(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**)_value(x).ToPointer())[2]); + } + } + } } diff --git a/mpir.net/mpir.net/HugeFloat.cpp b/mpir.net/mpir.net/HugeFloat.cpp index 1c3fedf8..2ec593fe 100644 --- a/mpir.net/mpir.net/HugeFloat.cpp +++ b/mpir.net/mpir.net/HugeFloat.cpp @@ -113,11 +113,51 @@ namespace MPIR 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(); + size_t allocated; + mp_exp_t exponent; + bool negative = false; + bool truncated = false; + char* allocatedStr = NULL; + EvaluationContext context; + auto result = gcnew StringBuilder(maxDigits + 20); + + ASSIGN_TO(context); + + if(maxDigits > 0) + { + allocated = maxDigits + 2; + allocatedStr = (char*)(*__gmp_allocate_func)(allocated); + } + else + { + allocated = 0; + } + + allocatedStr = MP(get_str)(allocatedStr, &exponent, (base <= 36 && !lowercase) ? -base : base, maxDigits, CTXT(0)); + + char* str = allocatedStr; + + if(*str == '-') + result->Append((wchar_t)*str++); + + result->Append((wchar_t)'0'); + if (*str != 0) + { + result->Append((wchar_t)'.'); + + while (*str != 0) + result->Append((wchar_t)*str++); + } + + if (exponent != 0) + result->Append((wchar_t)'@')->Append(exponent); + + if (allocated == 0) + allocated = str - allocatedStr + 1; + + (*__gmp_free_func)(allocatedStr, allocated); + + return result->ToString(); } int MPEXPR_NAME::GetHashCode() diff --git a/mpir.net/mpir.net/HugeFloat.h b/mpir.net/mpir.net/HugeFloat.h index 785e8b18..10c34f0a 100644 --- a/mpir.net/mpir.net/HugeFloat.h +++ b/mpir.net/mpir.net/HugeFloat.h @@ -803,14 +803,12 @@ namespace MPIR /// /// 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); @@ -950,16 +948,14 @@ namespace MPIR /// /// 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); } @@ -973,8 +969,7 @@ namespace MPIR /// /// 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: @@ -984,8 +979,7 @@ namespace MPIR /// /// 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.