diff --git a/mpir.net/mpir.net-tests/HugeIntTests/Arithmetic.cs b/mpir.net/mpir.net-tests/HugeIntTests/Arithmetic.cs index 7727fb99..53654687 100644 --- a/mpir.net/mpir.net-tests/HugeIntTests/Arithmetic.cs +++ b/mpir.net/mpir.net-tests/HugeIntTests/Arithmetic.cs @@ -263,6 +263,19 @@ namespace MPIR.Tests.HugeIntTests } } + [TestMethod] + public void IntAddProductHugeInt2() + { + using (var a = new HugeInt("98750293847520938457029384572093480498357")) + using (var c = new HugeInt("23094582093845093574093845093485039450934")) + using (var b = new HugeInt("-394580293847502987609283945873594873409587")) + { + var expr = c * b + a; + a.Value = expr; + Assert.AreEqual("-9112666988874677841199955832262586145147830205230375090322356322089362221491205901", a.ToString()); + } + } + [TestMethod] public void IntAddProductLimb() { @@ -369,6 +382,19 @@ namespace MPIR.Tests.HugeIntTests } } + [TestMethod] + public void IntAddProductSignedLimbTo4() + { + using (var a = new HugeInt("98750293847520938457029384572093480498357")) + using (var c = new HugeInt("23094582093845093574093845093485039450934")) + { + var b = Platform.Si(-498734523097853458, -2017853458); + var expr = b * c + a; + a.Value = expr; + Assert.AreEqual(Platform.Select("-11518065386718058599763388064972875060082210203928832731415", "-46601482240379908737297906081375735555240112731415"), a.ToString()); + } + } + #endregion #region Subtract Product @@ -386,6 +412,19 @@ namespace MPIR.Tests.HugeIntTests } } + [TestMethod] + public void IntSubtractProductHugeIntFrom() + { + using (var a = new HugeInt("98750293847520938457029384572093480498359")) + using (var c = new HugeInt("23094582093845093574093845093485039450934")) + using (var b = new HugeInt("394580293847502987609283945873594873409587")) + { + var expr = c * b - a; + a.Value = expr; + Assert.AreEqual("9112666988874677841199955832262586145147830205230375090322356322089362221491205899", a.ToString()); + } + } + [TestMethod] public void IntSubtractProductLimb() { @@ -399,6 +438,19 @@ namespace MPIR.Tests.HugeIntTests } } + [TestMethod] + public void IntSubtractProductLimbFrom() + { + using (var a = new HugeInt("98750293847520938457029384572093480498359")) + using (var c = new HugeInt("23094582093845093574093845093485039450934")) + { + var b = Platform.Ui(498734523097853458, 3997853458); + var expr = c * b - a; + a.Value = expr; + Assert.AreEqual(Platform.Select("11518065386718058599763388064972875060082210203928832731413", "92328754786193194014003719366476113668089432731413"), a.ToString()); + } + } + [TestMethod] public void IntSubtractProductSignedLimb() { @@ -412,6 +464,19 @@ namespace MPIR.Tests.HugeIntTests } } + [TestMethod] + public void IntSubtractProductSignedLimbFrom() + { + using (var a = new HugeInt("98750293847520938457029384572093480498359")) + using (var c = new HugeInt("-23094582093845093574093845093485039450934")) + { + var b = Platform.Si(-498734523097853458, -2017853458); + var expr = b * c - a; + a.Value = expr; + Assert.AreEqual(Platform.Select("11518065386718058599763388064972875060082210203928832731413", "46601482240379908737297906081375735555240112731413"), a.ToString()); + } + } + [TestMethod] public void IntSubtractProductSignedLimb2() { @@ -437,6 +502,30 @@ namespace MPIR.Tests.HugeIntTests } } + [TestMethod] + public void IntSubtractProductSignedLimbFrom3() + { + using (var a = new HugeInt("98750293847520938457029384572093480498359")) + using (var c = new HugeInt("-23094582093845093574093845093485039450934")) + { + var b = Platform.Si(498734523097853458, 2017853458); + a.Value = c * b - a; + Assert.AreEqual(Platform.Select("-11518065386718058797263975760014751974140979348115793728131", "-46601482437880496432339782995434504699427073728131"), a.ToString()); + } + } + + [TestMethod] + public void IntSubtractProductSignedLimb4() + { + using (var a = new HugeInt("98750293847520938457029384572093480498357")) + using (var c = new HugeInt("23094582093845093574093845093485039450934")) + { + var b = Platform.Si(498734523097853458, 2017853458); + a.Value = a - c * b; + Assert.AreEqual(Platform.Select("-11518065386718058599763388064972875060082210203928832731415", "-46601482240379908737297906081375735555240112731415"), a.ToString()); + } + } + #endregion #region Shift Left diff --git a/mpir.net/mpir.net/ExpressionMacros.h b/mpir.net/mpir.net/ExpressionMacros.h index a519f788..1bec7bc3 100644 --- a/mpir.net/mpir.net/ExpressionMacros.h +++ b/mpir.net/mpir.net/ExpressionMacros.h @@ -59,7 +59,7 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/. private ref class MPEXPR(name) : base \ { \ internal: \ - type Operand; \ + initonly type Operand; \ virtual void AssignTo(MP(ptr) destination) override; \ MPEXPR(name)(type operand) \ { \ @@ -72,8 +72,8 @@ private ref class MPEXPR(name) : base \ private ref class MPEXPR(name) : base \ { \ internal: \ - leftType Left; \ - rightType Right; \ + initonly leftType Left; \ + initonly rightType Right; \ virtual void AssignTo(MP(ptr) destination) override; \ MPEXPR(name)(leftType left, rightType right) \ { \ @@ -87,9 +87,9 @@ private ref class MPEXPR(name) : base \ private ref class MPEXPR(name) : base \ { \ internal: \ - leftType Left; \ - middleType Middle; \ - rightType Right; \ + initonly leftType Left; \ + initonly middleType Middle; \ + initonly rightType Right; \ virtual void AssignTo(MP(ptr) destination) override; \ MPEXPR(name)(leftType left, middleType middle, rightType right) \ { \ diff --git a/mpir.net/mpir.net/HugeInt.cpp b/mpir.net/mpir.net/HugeInt.cpp index e1d62f9f..0bd18dcb 100644 --- a/mpir.net/mpir.net/HugeInt.cpp +++ b/mpir.net/mpir.net/HugeInt.cpp @@ -435,11 +435,9 @@ namespace MPIR DEFINE_UNARY_ASSIGNMENT_REF(Negate, Int, MP(neg)) DEFINE_UNARY_ASSIGNMENT_REF(Abs, Int, MP(abs)) - DEFINE_BINARY_ASSIGNMENT_REF_REF(Add, Int, MP(add)) DEFINE_BINARY_ASSIGNMENT_REF_VAL(Add, Int, Ui, MP(add_ui)) DEFINE_BINARY_ASSIGNMENT_REF_SI (Add, Int, Si, MP(add_ui), MP(sub_ui)) - DEFINE_BINARY_ASSIGNMENT_REF_REF(Subtract, Int, MP(sub)) DEFINE_BINARY_ASSIGNMENT_REF_VAL(Subtract, Int, Ui, MP(sub_ui)) DEFINE_BINARY_ASSIGNMENT_VAL_REF(Subtract, Ui, Int, MP(ui_sub)) DEFINE_BINARY_ASSIGNMENT_REF_SI (Subtract, Int, Si, MP(sub_ui), MP(add_ui)) @@ -476,6 +474,131 @@ namespace MPIR DEFINE_TERNARY_ASSIGNMENT_REF_REF_REF(PowerMod, Int, MP(powm)); DEFINE_TERNARY_ASSIGNMENT_REF_VAL_REF(PowerMod, Int, Ui, Int, MP(powm_ui)) +#define WHEN_IS_DEST(i, a) \ + auto x##i = dynamic_cast(a); \ + if (!IS_NULL(x##i) && x##i->_value == destination) + +#define WHEN_IS(i, a, atype) \ + auto x##i = dynamic_cast(a); \ + if (!IS_NULL(x##i)) + + DEFINE_ASSIGNMENT_PROLOG(AddIntInt) + { + WHEN_IS_DEST(1, Left) + { + WHEN_IS(2, Right, MultiplyIntInt) + { + IN_CONTEXT(x2->Left, x2->Right); + MP(addmul)(destination, CTXT(0), CTXT(1)); + return; + } + WHEN_IS(3, Right, MultiplyIntUi) + { + IN_CONTEXT(x3->Left); + MP(addmul_ui)(destination, CTXT(0), x3->Right); + return; + } + WHEN_IS(4, Right, MultiplyIntSi) + { + IN_CONTEXT(x4->Left); + auto si = x4->Right; + if (si < 0) + MP(submul_ui)(destination, CTXT(0), (mpir_ui)-si); + else + MP(addmul_ui)(destination, CTXT(0), (mpir_ui)si); + return; + } + } + WHEN_IS_DEST(5, Right) + { + WHEN_IS(6, Left, MultiplyIntInt) + { + IN_CONTEXT(x6->Left, x6->Right); + MP(addmul)(destination, CTXT(0), CTXT(1)); + return; + } + WHEN_IS(7, Left, MultiplyIntUi) + { + IN_CONTEXT(x7->Left); + MP(addmul_ui)(destination, CTXT(0), x7->Right); + return; + } + WHEN_IS(8, Left, MultiplyIntSi) + { + IN_CONTEXT(x8->Left); + auto si = x8->Right; + if (si < 0) + MP(submul_ui)(destination, CTXT(0), (mpir_ui)-si); + else + MP(addmul_ui)(destination, CTXT(0), (mpir_ui)si); + return; + } + } + + IN_CONTEXT(Left, Right); + MP(add)(destination, CTXT(0), CTXT(1)); + } + + DEFINE_ASSIGNMENT_PROLOG(SubtractIntInt) + { + WHEN_IS_DEST(1, Left) + { + WHEN_IS(2, Right, MultiplyIntInt) + { + IN_CONTEXT(x2->Left, x2->Right); + MP(submul)(destination, CTXT(0), CTXT(1)); + return; + } + WHEN_IS(3, Right, MultiplyIntUi) + { + IN_CONTEXT(x3->Left); + MP(submul_ui)(destination, CTXT(0), x3->Right); + return; + } + WHEN_IS(4, Right, MultiplyIntSi) + { + IN_CONTEXT(x4->Left); + auto si = x4->Right; + if (si < 0) + MP(addmul_ui)(destination, CTXT(0), (mpir_ui)-si); + else + MP(submul_ui)(destination, CTXT(0), (mpir_ui)si); + return; + } + } + WHEN_IS_DEST(5, Right) + { + WHEN_IS(6, Left, MultiplyIntInt) + { + IN_CONTEXT(x6->Left, x6->Right); + MP(submul)(destination, CTXT(0), CTXT(1)); + MP(neg)(destination, destination); + return; + } + WHEN_IS(7, Left, MultiplyIntUi) + { + IN_CONTEXT(x7->Left); + MP(submul_ui)(destination, CTXT(0), x7->Right); + MP(neg)(destination, destination); + return; + } + WHEN_IS(8, Left, MultiplyIntSi) + { + IN_CONTEXT(x8->Left); + auto si = x8->Right; + if (si < 0) + MP(addmul_ui)(destination, CTXT(0), (mpir_ui)-si); + else + MP(submul_ui)(destination, CTXT(0), (mpir_ui)si); + MP(neg)(destination, destination); + return; + } + } + + IN_CONTEXT(Left, Right); + MP(sub)(destination, CTXT(0), CTXT(1)); + } + mpir_ui MPEXPR_NAME::Mod(mpir_ui d, RoundingModes rounding) { IN_CONTEXT(this);