diff --git a/README.md b/README.md index ec38ca1..863bb43 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,6 @@ var b:BigInt = 7; trace(a + b); // 10 // increment and decrement -// This works not with haxes operationoverloads yet if argument or result is 0 (because of 'null') ! trace(++a); // 3 trace(a++); // 4 trace( a ); // 5 @@ -195,8 +194,6 @@ Let me know if something's mising ~^ ## Todo -- fixing increment and decrement (++,--) problem with zero value/result - or replace this by .inc() and .dec() functions - `haxelib run` command for invoking hxp testscripts - fixing output with leading zeros - optional exponential notation for decimals diff --git a/benchmarks/CalcPi.hx b/benchmarks/CalcPi.hx index e28a61b..ff13a21 100644 --- a/benchmarks/CalcPi.hx +++ b/benchmarks/CalcPi.hx @@ -3,28 +3,29 @@ import haxe.Timer; // calculate Pi with https://en.wikipedia.org/wiki/Machin-like_formula class CalcPi { static public function main():Void { - var digits:BigInt = 300; + var digits:Int = 300; var time = Timer.stamp(); var pi:BigInt = calc(digits); haxe.Log.trace('Pi = 3.${pi.toString().substr(1)}\n\t\t\t' + Std.int((Timer.stamp() - time)*1000) + "\tms" , #if (haxe_ver >= "4.0.0") null #else {fileName:"",lineNumber:0,className:"",methodName:"",customParams:[]} #end); } - static public function calc(digits:BigInt):BigInt { - var calcdigits:BigInt = digits + 10; - var calcpi:BigInt = 4 * ( 4 * arctanbyd(5, calcdigits) - arctanbyd(239, calcdigits) ); + static public function calc(digits:Int):BigInt { + digits += 10; + var calcpi:BigInt = 4 * ( 4 * arctanbyd(5, digits) - arctanbyd(239, digits) ); calcpi = calcpi / ("10000000000":BigInt); return(calcpi); } - static public function arctanbyd(d:Int, digits:BigInt):BigInt { + static public function arctanbyd(d:Int, digits:Int):BigInt { // calculate arctan(1/d) = 1/d - 1/(3*d^3) + 1/(5*d^5) - 1/(7*d^7) + ... var arc:BigInt = (10:BigInt).pow(digits) / d; var part:BigInt = arc; var n:BigInt = 0; + var dd:Int = -d * d; while (part != 0) { - n = n + 1; - part = part / (-d * d); - arc = arc + part / (2 * n + 1); + n++; + part = part / dd; + arc = arc + part / (n*2 + 1); } return(arc); } diff --git a/haxelib.json b/haxelib.json index 5dede10..fd67afb 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,9 +4,9 @@ "license": "MIT", "tags": ["math", "arbitrary", "precision", "integer", "bigint"], "description": "pure haxe implementation for arbitrary-precision integer", - "version": "0.1.1", + "version": "0.1.2", "classPath": "src/", - "releasenote": "fixing multiplication, adding pi-benchmark", + "releasenote": "fixing multiplication and inc-/decrement, adding pi-benchmark", "contributors": ["maitag"], "dependencies": {} } \ No newline at end of file diff --git a/src/BigInt.hx b/src/BigInt.hx index 55f703e..a0745d8 100644 --- a/src/BigInt.hx +++ b/src/BigInt.hx @@ -225,31 +225,39 @@ abstract BigInt(LittleIntChunks) from LittleIntChunks { //@:op(A + B) @:commutative function opAddInt(b:Int):BigInt return _add(this, b); @:op(A + B) static function opAddInt(a:Int, b:BigInt):BigInt return _add(a, b); // haxe 3.4.4 compatible! - @:op(A++) static function opIncrementAfter(a:BigInt):BigInt { - if (a == null) { - a = BigInt.fromInt(1); // TODO: Can't do "++" for 0 (null can not be changed) + @:op(A++) inline function opIncrementAfter():BigInt { + if (this == null) { + this = LittleIntChunks.createFromLittleInt(1); return null; } - var ret = a.copy(); - if (a.isNegative) { - if (a == -1) a = null; // TODO: Can't do "++" for 0 (null can not be changed) - else subtractLittle(a, 1, 0); + var ret = copy(); + if (isNegative) { + if (length == 1 && get(0) == 1) this = null; + else subtractLittle(this, 1, 0); } - else addLittle(a, 1, 0); + else addLittle(this, 1, 0); return ret; } - @:op(++A) static function opIncrementBefore(a:BigInt):BigInt { - if (a == null) { - a = BigInt.fromInt(1); // TODO: Can't do "++" for 0 (null can not be changed) - return BigInt.fromInt(1); + @:op(++A) inline function opIncrementBefore():BigInt { + if (this == null) { + this = LittleIntChunks.createFromLittleInt(1); + return LittleIntChunks.createFromLittleInt(1); } - if (a.isNegative) { - if (a == -1) a = null; // TODO: Can't do "++" for 0 (null can not be changed) - subtractLittle(a, 1, 0); + if (isNegative) { + if (length == 1 && get(0) == 1) { + this = null; + return null; + } + else { + subtractLittle(this, 1, 0); + return copy(); + } + } + else { + addLittle(this, 1, 0); + return copy(); } - else addLittle(a, 1, 0); - return a.copy(); } static inline function _add(a:BigInt, b:BigInt):BigInt { @@ -303,34 +311,39 @@ abstract BigInt(LittleIntChunks) from LittleIntChunks { //@:op(A - B) static function opSubtractInt(a:BigInt, b:Int):BigInt return _subtract(a, b); @:op(A - B) static function opIntSubtract(a:Int, b:BigInt):BigInt return _subtract(a, b); - @:op(A--) static function opDecrementAfter(a:BigInt):BigInt { - if (a == null) { - a = BigInt.fromInt(-1); // TODO: Can't do "--" for 0 (null can not be changed) + @:op(A--) inline function opDecrementAfter():BigInt { + if (this == null) { + this = LittleIntChunks.createFromLittleInt(-1); return null; } - var ret = a.copy(); - if (a.isNegative) addLittle(a, 1, 0); + var ret = copy(); + if (isNegative) addLittle(this, 1, 0); else { - if (a == 1) a = null; // TODO: Can't do "--" for 0 (null can not be changed) - else subtractLittle(a, 1, 0); + if (length == 1 && get(0) == 1) this = null; + else subtractLittle(this, 1, 0); } return ret; } - @:op(--A) static function opDecrementBefore(a:BigInt):BigInt { - if (a == null) { - a = BigInt.fromInt(-1); // TODO: Can't do "--" for 0 (null can not be changed) - return BigInt.fromInt(-1); + @:op(--A) inline function opDecrementBefore():BigInt { + if (this == null) { + this = LittleIntChunks.createFromLittleInt(-1); + return LittleIntChunks.createFromLittleInt(-1); + } + if (isNegative) { + addLittle(this, 1, 0); + return copy(); } - if (a.isNegative) addLittle(a, 1, 0); else { - if (a == 1) { - a = null; // TODO: Can't do "--" for 0 (null can not be changed) + if (length == 1 && get(0) == 1) { + this = null; return null; } - else subtractLittle(a, 1, 0); - } - return a.copy(); + else { + subtractLittle(this, 1, 0); + return copy(); + } + } } static inline function _subtract(a:BigInt, b:BigInt):BigInt { diff --git a/unit-tests/TestBigInt.hx b/unit-tests/TestBigInt.hx index 3e15a72..21f9894 100644 --- a/unit-tests/TestBigInt.hx +++ b/unit-tests/TestBigInt.hx @@ -258,12 +258,23 @@ class TestBigInt extends haxe.unit.TestCase } public function testIncrement() { - var a:BigInt = "0x 1 1234 5678 abcd efff"; - var b:BigInt = a++; + var a:BigInt; + var b:BigInt; + var c:BigInt; + a = "0x 1 1234 5678 abcd efff"; + b = a++; assertTrue( b == ("0x 1 1234 5678 abcd efff" : BigInt) ); assertTrue( a == ("0x 1 1234 5678 abcd f000" : BigInt) ); - var c:BigInt = ++a; + c = ++a; assertTrue( (a == c) && (c == ("0x 1 1234 5678 abcd f001" : BigInt)) ); + a = 0; assertTrue(a++ == 0); assertTrue(a == 1); + a =-1; assertTrue(a++ ==-1); assertTrue(a == 0); + a = 0; assertTrue(++a == 1); assertTrue(a == 1); + a =-1; assertTrue(++a == 0); assertTrue(a == 0); + a = 0; assertTrue(a-- == 0); assertTrue(a ==-1); + a = 1; assertTrue(a-- == 1); assertTrue(a == 0); + a = 0; assertTrue(--a ==-1); assertTrue(a ==-1); + a = 1; assertTrue(--a == 0); assertTrue(a == 0); } public function testSubtraction() { @@ -382,6 +393,12 @@ class TestBigInt extends haxe.unit.TestCase b = "-333333333333333333333"; c = "-37037037037037037036999999999999999999962962962962962962963"; assertTrue(a * b == c); + + // check optimization bug + a = "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000195193276309135075023284912102116616768613765187463511927839869094134045055764247"; + b = "10000000000"; + c = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001951932763091350750232849121021166167686137651874635119278398690941340450557642470000000000"; + assertTrue(a * b == c); } public function testMultiplicationWithInt() {