diff --git a/build.vc11/mpir.net/mpir.net-tests/HugeFloatTests/Arithmetic.cs b/build.vc11/mpir.net/mpir.net-tests/HugeFloatTests/Arithmetic.cs new file mode 100644 index 00000000..ec308aac --- /dev/null +++ b/build.vc11/mpir.net/mpir.net-tests/HugeFloatTests/Arithmetic.cs @@ -0,0 +1,347 @@ +/* +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/. +*/ + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MPIR.Tests.HugeFloatTests +{ + public static class FloatAssert + { + public static void AreEqual(string expected, HugeFloat actual) + { + var actualStr = actual.ToString(); + if(expected[0] == '-') + { + Assert.AreEqual(expected[0], actualStr[0]); + actualStr = actualStr.TrimStart('-'); + expected = expected.TrimStart('-'); + } + + var exponent = expected.IndexOf('.'); + expected = expected.Replace(".", ""); + + var exponentStr = "@" + exponent; + + Assert.IsTrue(actualStr.StartsWith("0.")); + actualStr = actualStr.Substring(2); + + Assert.IsTrue(actualStr.EndsWith(exponentStr)); + actualStr = actualStr.Substring(0, actualStr.Length - exponentStr.Length); + + if (expected.Length > actualStr.Length) + { + var roundedUp = expected[actualStr.Length] >= '5'; + expected = expected.Substring(0, actualStr.Length); + if(roundedUp) + { + using (var a = new HugeInt(expected)) + { + a.Value += 1; + expected = a.ToString(10); + } + } + } + Assert.AreEqual(expected, actualStr); + } + } + + [TestClass] + public class Arithmetic + { + #region Add + + [TestMethod] + public void FloatAddHugeFloat() + { + using (var a = new HugeFloat("22250983250345029834502983.5740293845720")) + using (var b = new HugeFloat("2229874359879827.30594288574029879874539")) + using (var c = new HugeFloat(a + b)) + { + FloatAssert.AreEqual("22250983252574904194382810.87997227031229879874539", c); + c.Value = a + (b + 1); + FloatAssert.AreEqual("22250983252574904194382811.87997227031229879874539", c); + } + } + + [TestMethod] + public void FloatAddLimb() + { + using (var a = new HugeFloat("22250983250345029834502983.5740293845720")) + using (var c = new HugeFloat()) + { + var b = 4288574029879874539UL; + c.Value = a + b; + FloatAssert.AreEqual("22250987538919059714377522.5740293845720", c); + c.Value = b + a; + FloatAssert.AreEqual("22250987538919059714377522.5740293845720", c); + } + } + + [TestMethod] + public void FloatAddSignedLimb() + { + using (var a = new HugeFloat("22250983250345029834502983.5740293845720")) + using (var c = new HugeFloat()) + { + var b = -4288574029879874539; + c.Value = a + b; + FloatAssert.AreEqual("22250978961770999954628444.5740293845720", c); + c.Value = b + a; + FloatAssert.AreEqual("22250978961770999954628444.5740293845720", c); + } + } + + #endregion + + #region Subtract + + [TestMethod] + public void FloatSubtractHugeFloat() + { + using (var a = new HugeFloat("22250983250345029834502983.5740293845720")) + using (var b = new HugeFloat("2229874359879827.30594288574029879874539")) + using (var c = new HugeFloat(a - b)) + { + FloatAssert.AreEqual("22250983248115155474623156.26808649883170120125461", c); + c.Value = b - (a + 1); + FloatAssert.AreEqual("-22250983248115155474623157.26808649883170120125461", c); + } + } + + [TestMethod] + public void FloatSubtractLimb() + { + using(var a = new HugeFloat("22250983250345029834502983.5740293845720")) + using(var c = new HugeFloat()) + { + var b = 4288574029879874539UL; + c.Value = a - b; + FloatAssert.AreEqual("22250978961770999954628444.5740293845720", c); + c.Value = b - a; + FloatAssert.AreEqual("-22250978961770999954628444.5740293845720", c); + } + } + + [TestMethod] + public void FloatSubtractSignedLimb() + { + using(var a = new HugeFloat("22250983250345029834502983.5740293845720")) + using(var c = new HugeFloat()) + { + var b = -4288574029879874539; + c.Value = a - b; + FloatAssert.AreEqual("22250987538919059714377522.5740293845720", c); + c.Value = b - a; + FloatAssert.AreEqual("-22250987538919059714377522.5740293845720", c); + } + } + + #endregion + + #region Multiply + + [TestMethod] + public void FloatMultiplyByHugeFloat() + { + using (var a = new HugeFloat("90234098723098475098479385.345098345")) + using (var b = new HugeFloat("78594873598734.59872354987610987897")) + using (var c = new HugeFloat(a * b)) + { + FloatAssert.AreEqual("7091937583437663707014199538801620613535.95657143399816050772069730465", c); + c.Value = b * (a + 1); + FloatAssert.AreEqual("7091937583437663707014199617396494212270.55529498387427038669069730465", c); + } + } + + [TestMethod] + public void FloatMultiplyByLimb() + { + using (var a = new HugeFloat("9023409872309847509847.9385345098345")) + using (var c = new HugeFloat()) + { + ulong b = 17390538260286101342; + c.Value = a * b; + FloatAssert.AreEqual("156921954622647727368660197878904460649174.746962647899", c); + c.Value = b * -a; + FloatAssert.AreEqual("-156921954622647727368660197878904460649174.746962647899", c); + } + } + + [TestMethod] + public void FloatMultiplyBySignedLimb() + { + using (var a = new HugeFloat("9023409872309847509847.9385345098345")) + using (var c = new HugeFloat()) + { + long b = -7390538260286101342; + c.Value = a * b; + FloatAssert.AreEqual("-66687855899549252270180812533806115649174.746962647899", c); + c.Value = b * -a; + FloatAssert.AreEqual("66687855899549252270180812533806115649174.746962647899", c); + } + } + + #endregion + + #region Shift Left + + [TestMethod] + public void FloatShiftLeft() + { + using (var a = new HugeFloat("-12345700987ABA245230948.17607EF", 16)) + using (var e = new HugeFloat("-12345700987ABA24523094817607.EF", 16)) + { + ulong b = 20; + a.Value = a << b; + Assert.AreEqual(e, a); + } + } + + #endregion + + #region Shift Right + + [TestMethod] + public void FloatShiftRight() + { + using (var a = new HugeFloat("-12345700987ABA24523094817607.EF", 16)) + using (var e = new HugeFloat("-12345700987ABA245230948.17607EF", 16)) + { + ulong b = 20; + a.Value = a >> b; + Assert.AreEqual(e, a); + } + } + + #endregion + + #region Negate + + [TestMethod] + public void FloatNegate() + { + using(var a = new HugeFloat("9023409872309847509847.9385345098345")) + { + a.Value = -a; + FloatAssert.AreEqual("-9023409872309847509847.9385345098345", a); + a.Value = -a; + FloatAssert.AreEqual("9023409872309847509847.9385345098345", a); + } + } + + #endregion + + #region Abs + + [TestMethod] + public void FloatMakeAbsolute() + { + using(var a = new HugeFloat("-9023409872309847509847.9385345098345")) + { + a.Value = a.Abs(); + FloatAssert.AreEqual("9023409872309847509847.9385345098345", a); + a.Value = a.Abs(); + FloatAssert.AreEqual("9023409872309847509847.9385345098345", a); + } + } + + #endregion + + #region Power + + [TestMethod] + public void FloatPower() + { + using(var a = new HugeFloat("-902340.945098345")) + { + a.Value = a ^ 5; + FloatAssert.AreEqual("-598209523815275040074985233466.4619735146023546465747916785912044", a); + } + } + + #endregion + + #region Divide + + #region Int + + [TestMethod] + public void FloatDivideHugeFloat() + { + using (var a = new HugeFloat("1157569866683036578989624354347957.394580293847")) + using (var b = new HugeFloat("593169091750307653294.549782395235784")) + { + a.Value = a / b; + FloatAssert.AreEqual("1951500647593.2689953514865540344827449639493356367018584357", a); + } + } + + #endregion + + #region Limb + + [TestMethod] + public void FloatDivideLimb() + { + using (var a = new HugeFloat("1157569866683036578989624354347957.394580293847")) + { + ulong b = 5931690917503076532; + a.Value = a / b; + FloatAssert.AreEqual("195150064759326.89956625512472902395197480398952074748799190", a); + } + } + + [TestMethod] + public void FloatDivideSignedLimb() + { + using(var a = new HugeFloat("1157569866683036578989624354347957.394580293847")) + { + long b = -5931690917503076532; + a.Value = a / b; + FloatAssert.AreEqual("-195150064759326.89956625512472902395197480398952074748799190", a); + } + } + + [TestMethod] + public void FloatDivideLimbBy() + { + using(var a = new HugeFloat("11575698666830.39458029384723405203984572")) + { + ulong b = 5931690917503076532; + a.Value = b / a; + FloatAssert.AreEqual("512426.16866833708737257760720580856722540469109813901673959", a); + } + } + + [TestMethod] + public void FloatDivideSignedLimbBy() + { + using(var a = new HugeFloat("11575698666830.39458029384723405203984572")) + { + long b = -5931690917503076532; + a.Value = b / a; + FloatAssert.AreEqual("-512426.16866833708737257760720580856722540469109813901673959", a); + } + } + + #endregion + + #endregion + } +} diff --git a/build.vc11/mpir.net/mpir.net-tests/HugeFloatTests/Comparisons.cs b/build.vc11/mpir.net/mpir.net-tests/HugeFloatTests/Comparisons.cs new file mode 100644 index 00000000..f91e46dc --- /dev/null +++ b/build.vc11/mpir.net/mpir.net-tests/HugeFloatTests/Comparisons.cs @@ -0,0 +1,615 @@ +/* +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/. +*/ + +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MPIR.Tests.HugeFloatTests +{ + [TestClass] + public class Comparisons + { + #region CompareTo + + [TestMethod] + public void FloatCompareToHugeFloat() + { + using (var a = new HugeFloat("-22250983250345029834503.9835740293845721345345354")) + using (var b = new HugeFloat("22250983250345029834502.9835740293845721345345354")) + { + Assert.AreEqual(1, Math.Sign(b.CompareTo(a))); + Assert.AreEqual(-1,Math.Sign(a.CompareTo(b + 1))); + Assert.AreEqual(0, Math.Sign((a + 1).CompareTo(-b))); + Assert.AreEqual(1, Math.Sign(a.CompareTo(null))); + } + } + + [TestMethod] + public void FloatCompareToObject() + { + using (var a = new HugeFloat("-22250983250345029834503.9835740293845721345345354")) + using (var b = new HugeFloat("22250983250345029834502.9835740293845721345345354")) + { + Assert.AreEqual(1, Math.Sign(((IComparable)b).CompareTo((object)a))); + Assert.AreEqual(-1,Math.Sign(((IComparable)a).CompareTo((object)b))); + Assert.AreEqual(1, Math.Sign(((IComparable)a).CompareTo(null))); + Assert.AreEqual(0, Math.Sign(((IComparable)(a + 1)).CompareTo((object)-b))); + } + } + + [TestMethod] + public void FloatCompareToExpression() + { + using (var a = new HugeFloat("-22250983250345029834503.9835740293845721345345354")) + using (var b = new HugeFloat("22250983250345029834502.9835740293845721345345354")) + { + Assert.AreEqual(1, Math.Sign(((IComparable)b).CompareTo(a))); + Assert.AreEqual(-1,Math.Sign(((IComparable)a).CompareTo(b))); + Assert.AreEqual(1, Math.Sign(((IComparable)a).CompareTo(null))); + Assert.AreEqual(0, Math.Sign(((IComparable)(a + 1)).CompareTo(-b))); + } + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void FloatCompareToNonExpression() + { + using (var a = new HugeFloat("-222509832503450298345029835740293845721.57898962467957")) + { + a.CompareTo("abc"); + } + } + + [TestMethod] + public void FloatCompareToLimb() + { + using (var a = new HugeFloat("-222509821")) + { + ulong b = 222509820; + Assert.AreEqual(-1,Math.Sign(a.CompareTo(b))); + Assert.AreEqual(-1,Math.Sign(a.CompareTo(b + 1))); + Assert.AreEqual(0, Math.Sign((-(a + 1)).CompareTo(b))); + Assert.AreEqual(0, Math.Sign((-a).CompareTo(b + 1))); + Assert.AreEqual(1, Math.Sign((-a).CompareTo(b))); + } + } + + [TestMethod] + public void FloatCompareToSignedLimb() + { + using (var a = new HugeFloat("-222509821")) + { + long b = -222509820; + Assert.AreEqual(-1,Math.Sign(a.CompareTo(b))); + Assert.AreEqual(-1,Math.Sign(a.CompareTo(b + 1))); + Assert.AreEqual(0, Math.Sign((a + 1).CompareTo(b))); + Assert.AreEqual(0, Math.Sign(a.CompareTo(b - 1))); + Assert.AreEqual(1, Math.Sign(a.CompareTo(b - 2))); + } + } + + [TestMethod] + public void FloatCompareToSignedDouble() + { + using (var a = new HugeFloat("-222509821")) + { + double b = -222509820; + Assert.AreEqual(-1,Math.Sign(a.CompareTo(b))); + Assert.AreEqual(-1,Math.Sign(a.CompareTo(b + 1))); + Assert.AreEqual(0, Math.Sign((a + 1).CompareTo(b))); + Assert.AreEqual(0, Math.Sign(a.CompareTo(b - 1))); + Assert.AreEqual(1, Math.Sign(a.CompareTo(b - 1.1))); + } + } + + #endregion + + #region comparison operators with expr + + [TestMethod] + public void FloatOperatorLessThan() + { + using (var a = new HugeFloat("-2225098325034502983450.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + using (var c = new HugeFloat()) + { + c.Value = a; + Assert.IsTrue(a < b); + Assert.IsFalse(b < a); + Assert.IsFalse(a < c); + Assert.IsFalse(a > c); + Assert.IsFalse(a < null); + Assert.IsTrue(null < a); + } + } + + [TestMethod] + public void FloatOperatorLessThanOrEqual() + { + using (var a = new HugeFloat("-2225098325034502983451.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + using (var c = new HugeFloat()) + { + c.Value = a; + Assert.IsTrue(a <= b); + Assert.IsFalse(b <= a); + Assert.IsTrue(a <= c); + Assert.IsFalse(a <= null); + Assert.IsTrue(null <= a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThan() + { + using (var a = new HugeFloat("-2225098325034502983451.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + using (var c = new HugeFloat()) + { + c.Value = a; + Assert.IsFalse(a > b); + Assert.IsTrue(b > a); + Assert.IsFalse(a > c); + Assert.IsTrue(a > null); + Assert.IsFalse(null > a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThanOrEqual() + { + using (var a = new HugeFloat("-2225098325034502983451.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + using (var c = new HugeFloat()) + { + c.Value = a; + Assert.IsFalse(a >= b); + Assert.IsTrue(b >= a); + Assert.IsTrue(a >= c); + Assert.IsTrue(a >= null); + Assert.IsFalse(null >= a); + } + } + + #endregion + + #region comparison operators with limb + + [TestMethod] + public void FloatOperatorLessThanLimb() + { + using (var a = new HugeFloat("3845721")) + { + ulong c = 5432; + ulong b = 5432349587; + Assert.IsTrue(a < b); + Assert.IsFalse(b < a); + Assert.IsFalse(a < c); + Assert.IsTrue(c < a); + } + } + + [TestMethod] + public void FloatOperatorLessThanOrEqualLimb() + { + using (var a = new HugeFloat("3845721")) + { + ulong c = 5432; + ulong b = 5432349587; + ulong d = 3845721; + Assert.IsTrue(a <= b); + Assert.IsFalse(b <= a); + Assert.IsFalse(a <= c); + Assert.IsTrue(c <= a); + Assert.IsTrue(a <= d); + Assert.IsTrue(d <= a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThanLimb() + { + using (var a = new HugeFloat("3845721")) + { + ulong c = 5432; + ulong b = 5432349587; + Assert.IsFalse(a > b); + Assert.IsTrue(b > a); + Assert.IsTrue(a > c); + Assert.IsFalse(c > a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThanOrEqualLimb() + { + using (var a = new HugeFloat("3845721")) + { + ulong c = 5432; + ulong b = 5432349587; + ulong d = 3845721; + Assert.IsFalse(a >= b); + Assert.IsTrue(b >= a); + Assert.IsTrue(a >= c); + Assert.IsFalse(c >= a); + Assert.IsTrue(a >= d); + Assert.IsTrue(d >= a); + } + } + + #endregion + + #region comparison operators with signed limb + + [TestMethod] + public void FloatOperatorLessThanSignedLimb() + { + using (var a = new HugeFloat("-3845721")) + { + long c = -543254325432; + long b = -9587; + Assert.IsTrue(a < b); + Assert.IsFalse(b < a); + Assert.IsFalse(a < c); + Assert.IsTrue(c < a); + } + } + + [TestMethod] + public void FloatOperatorLessThanOrEqualSignedLimb() + { + using (var a = new HugeFloat("-3845721")) + { + long c = -543254325432; + long b = -9587; + long d = -3845721; + Assert.IsTrue(a <= b); + Assert.IsFalse(b <= a); + Assert.IsFalse(a <= c); + Assert.IsTrue(c <= a); + Assert.IsTrue(a <= d); + Assert.IsTrue(d <= a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThanSignedLimb() + { + using (var a = new HugeFloat("-3845721")) + { + long c = -543254325432; + long b = -9587; + Assert.IsFalse(a > b); + Assert.IsTrue(b > a); + Assert.IsTrue(a > c); + Assert.IsFalse(c > a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThanOrEqualSignedLimb() + { + using (var a = new HugeFloat("-3845721")) + { + long c = -543254325432; + long b = -9587; + long d = -3845721; + Assert.IsFalse(a >= b); + Assert.IsTrue(b >= a); + Assert.IsTrue(a >= c); + Assert.IsFalse(c >= a); + Assert.IsTrue(a >= d); + Assert.IsTrue(d >= a); + } + } + + #endregion + + #region comparison operators with double + + [TestMethod] + public void FloatOperatorLessThanDouble() + { + using (var a = new HugeFloat("-3845721")) + { + double c = -543254325432; + double b = -9587; + Assert.IsTrue(a < b); + Assert.IsFalse(b < a); + Assert.IsFalse(a < c); + Assert.IsTrue(c < a); + } + } + + [TestMethod] + public void FloatOperatorLessThanOrEqualDouble() + { + using (var a = new HugeFloat("-3845721")) + { + double c = -543254325432; + double b = -9587; + double d = -3845721; + Assert.IsTrue(a <= b); + Assert.IsFalse(b <= a); + Assert.IsFalse(a <= c); + Assert.IsTrue(c <= a); + Assert.IsTrue(a <= d); + Assert.IsTrue(d <= a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThanDouble() + { + using (var a = new HugeFloat("-3845721")) + { + double c = -543254325432; + double b = -9587; + Assert.IsFalse(a > b); + Assert.IsTrue(b > a); + Assert.IsTrue(a > c); + Assert.IsFalse(c > a); + } + } + + [TestMethod] + public void FloatOperatorGreaterThanOrEqualDouble() + { + using (var a = new HugeFloat("-3845721")) + { + double c = -543254325432; + double b = -9587; + double d = -3845721; + Assert.IsFalse(a >= b); + Assert.IsTrue(b >= a); + Assert.IsTrue(a >= c); + Assert.IsFalse(c >= a); + Assert.IsTrue(a >= d); + Assert.IsTrue(d >= a); + Assert.IsFalse(d - 0.1 >= a); + } + } + + #endregion + + #region Equals + + [TestMethod] + public void FloatEqualsHugeFloat() + { + using (var a = new HugeFloat("-2225098325034502983451.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + { + Assert.IsFalse(b.Equals(a)); + Assert.IsFalse(a.Equals(b + 1)); + Assert.IsTrue((a + 1).Equals(-b)); + Assert.IsFalse(a.Equals(null)); + Assert.IsTrue(Equals(a + 1, -b)); + } + } + + [TestMethod] + public void FloatEqualsExpression() + { + using (var a = new HugeFloat("-2225098325034502983451.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + { + Assert.IsFalse(((IEquatable)b).Equals(a)); + Assert.IsFalse(((IEquatable)a).Equals(b)); + Assert.IsFalse(((IEquatable)a).Equals(null)); + Assert.IsTrue(((IEquatable)(a + 1)).Equals(-b)); + } + } + + [TestMethod] + public void FloatEqualsNonExpression() + { + using (var a = new HugeFloat("-2225098325034502983450.29835740293845721")) + { + Assert.IsFalse(a.Equals("abc")); + } + } + + [TestMethod] + public void FloatEqualsLimb() + { + using (var a = new HugeFloat("222509832503")) + { + ulong b = 222509832504; + Assert.IsFalse(a.Equals(b + 1)); + Assert.IsTrue(a.Equals(b - 1)); + Assert.IsTrue((a + 1).Equals(b)); + } + } + + [TestMethod] + public void FloatEqualsSignedLimb() + { + using (var a = new HugeFloat("-222509832505")) + { + long b = -222509832504; + Assert.IsFalse(a.Equals(b + 1)); + Assert.IsTrue(a.Equals(b - 1)); + Assert.IsTrue((a + 1).Equals(b)); + } + } + + [TestMethod] + public void FloatEqualsDouble() + { + using (var a = new HugeFloat("-222509832505")) + { + double b = -222509832504; + Assert.IsFalse(a.Equals(b + 1)); + Assert.IsTrue(a.Equals(b - 1)); + Assert.IsTrue((a + 1).Equals(b)); + Assert.IsFalse((a + 1).Equals(b + 0.1)); + } + } + + #endregion + + #region Equality operators with expr + + [TestMethod] + public void FloatEqualsOperatorHugeFloat() + { + using (var a = new HugeFloat("-2225098325034502983451.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + { + Assert.IsFalse(b == a); + Assert.IsFalse(a == b + 1); + Assert.IsTrue(a + 1 == -b); + Assert.IsFalse(a == null); + } + } + + [TestMethod] + public void FloatNotEqualOperatorHugeFloat() + { + using (var a = new HugeFloat("-2225098325034502983451.29835740293845721")) + using (var b = new HugeFloat("2225098325034502983450.29835740293845721")) + { + Assert.IsTrue(b != a); + Assert.IsTrue(a != b + 1); + Assert.IsFalse(a + 1 != -b); + Assert.IsTrue(a != null); + } + } + + #endregion + + #region Equality operators with Limb + + [TestMethod] + public void FloatEqualsOperatorLimb() + { + using (var a = new HugeFloat("-835740293845721")) + { + ulong b = 835740293845720; + Assert.IsFalse(b == a); + Assert.IsFalse(a == b + 1); + Assert.IsTrue(-(a + 1) == b); + } + } + + [TestMethod] + public void FloatNotEqualOperatorLimb() + { + using (var a = new HugeFloat("-835740293845721")) + { + ulong b = 835740293845720; + Assert.IsTrue(b != a); + Assert.IsTrue(a != b + 1); + Assert.IsFalse(-(a + 1) != b); + } + } + + #endregion + + #region Equality operators with Signed Limb + + [TestMethod] + public void FloatEqualsOperatorSignedLimb() + { + using (var a = new HugeFloat("-835740293845721")) + { + long b = -835740293845720; + Assert.IsFalse(b == a); + Assert.IsFalse(a == b + 1); + Assert.IsTrue(a + 1 == b); + } + } + + [TestMethod] + public void FloatNotEqualOperatorSignedLimb() + { + using (var a = new HugeFloat("-835740293845721")) + { + long b = -835740293845720; + Assert.IsTrue(b != a); + Assert.IsTrue(a != b + 1); + Assert.IsFalse(a + 1 != b); + } + } + + #endregion + + #region Equality operators with Double + + [TestMethod] + public void FloatEqualsOperatorDouble() + { + using (var a = new HugeFloat("-835740293845721")) + { + double b = -835740293845720; + Assert.IsFalse(b == a); + Assert.IsFalse(a == b + 1); + Assert.IsTrue(a + 1 == b); + Assert.IsFalse(a + 1 == b + 0.1); + } + } + + [TestMethod] + public void FloatNotEqualOperatorDouble() + { + using (var a = new HugeFloat("-835740293845721")) + { + double b = -835740293845720; + Assert.IsTrue(b != a); + Assert.IsTrue(a != b + 1); + Assert.IsFalse(a + 1 != b); + Assert.IsTrue(a + 1 != b + 0.1); + } + } + + #endregion + + #region GetHashCode + + [TestMethod] + public void FloatGetHashCodeTest() + { + using (var a = new HugeFloat("-2225098325034502983450298357.40293845721")) + { + Assert.AreNotEqual(0, a.GetHashCode()); + Assert.AreEqual(a.GetHashCode(), (a + 0).GetHashCode()); + Assert.AreNotEqual(a.GetHashCode(), (-a).GetHashCode()); + } + } + + #endregion + + #region Sign + + [TestMethod] + public void FloatSign() + { + using (var a = new HugeFloat("-22250983250345029834.502983574029384572134354")) + { + Assert.AreEqual(-1, a.Sign()); + Assert.AreEqual(1, (-a).Sign()); + Assert.AreEqual(0, (a-a).Sign()); + } + } + + #endregion + //more tests coming here + } +} 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..27a8f911 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 @@ -157,6 +157,8 @@ Properties\AssemblyInfo.cs + + @@ -164,9 +166,7 @@ mpir.net - - - + diff --git a/mpir.net/mpir.net-tests/RandomTests/Random.cs b/mpir.net/mpir.net-tests/RandomTests/Random.cs index ab0d93e9..8e1d3d8e 100644 --- a/mpir.net/mpir.net-tests/RandomTests/Random.cs +++ b/mpir.net/mpir.net-tests/RandomTests/Random.cs @@ -54,7 +54,7 @@ namespace MPIR.Tests.RandomTests break; case 4: - r.Seed(seed); //r = copy; temporarily disabled copy tests due to MPIR bug + r.Seed(seed); //todo r = copy; temporarily disabled copy tests due to MPIR bug break; } diff --git a/mpir.net/mpir.net/HugeFloat.cpp b/mpir.net/mpir.net/HugeFloat.cpp index 1c3fedf8..b0ef3306 100644 --- a/mpir.net/mpir.net/HugeFloat.cpp +++ b/mpir.net/mpir.net/HugeFloat.cpp @@ -113,11 +113,40 @@ 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(); + if(base < 2 || base > 62) + throw gcnew ArgumentOutOfRangeException("base", "Invalid base"); + + mp_exp_t exponent; + auto allocatedStr = MP(get_str)(NULL, &exponent, (!lowercase && base <= 36) ? -base : base, maxDigits, _value); + auto str = allocatedStr; + + auto result = maxDigits > 0 ? gcnew StringBuilder(maxDigits + 70) : gcnew StringBuilder(); + + size_t allocated = 1; + if (*str == '-') + { + result->Append((wchar_t)'-'); + allocated++; + str++; + } + result->Append((wchar_t)'0'); + + if (*str != 0) + { + result->Append((wchar_t)'.'); + while (*str != 0) + { + result->Append((wchar_t)*str); + allocated++; + str++; + } + result->Append((wchar_t)'@'); + result->Append(exponent); + } + + (*__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..2ead99c4 100644 --- a/mpir.net/mpir.net/HugeFloat.h +++ b/mpir.net/mpir.net/HugeFloat.h @@ -1,1228 +1,1245 @@ -/* -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->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) && 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->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 < (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->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 < (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->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 < (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->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 < (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->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 < (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->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; } - - /// 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 -}; +/* +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->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) && 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->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 < (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->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 < (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->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 < (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->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 < (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->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 < (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->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; } + + /// 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; + mp_bitcnt_t _allocatedPrecision; + + private: + //construction + 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); + String^ ToString(int base, bool lowercase, int maxDigits); + + internal: + virtual void DeallocateStruct() + { + MP(set_prec_raw)(_value, _allocatedPrecision); + 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 + + static MPTYPE() + { + DefaultPrecision = sizeof(mpir_ui) * 8 * 2; //2 limbs + } + + static property mp_bitcnt_t DefaultPrecision + { + mp_bitcnt_t get() { return MP(get_default_prec)(); } + void set(mp_bitcnt_t value) { MP(set_default_prec)(value); } + } + + /// + /// 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 +};