diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-04-01 18:08:14 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-04-01 18:08:14 -0700 |
commit | 18a02098377c1f8a3b309f7415d10789a602eb40 (patch) | |
tree | cb3c262d5696d088be8ccc47c4d95bfd7095c2c8 /src | |
parent | e9cc64df79f9de9793ed74ade92dbd02c790f678 (diff) |
use bignum for unsigned i64 precise division
Diffstat (limited to 'src')
-rw-r--r-- | src/long.js | 67 | ||||
-rw-r--r-- | src/parseTools.js | 7 |
2 files changed, 53 insertions, 21 deletions
diff --git a/src/long.js b/src/long.js index 42ea5fa9..63d82fb9 100644 --- a/src/long.js +++ b/src/long.js @@ -1529,58 +1529,89 @@ BigInteger.prototype.addTo = bnpAddTo; //======= end jsbn ======= // Emscripten wrapper -return { +var Wrapper = { result: [0, 0], // return result stored here add: function(xl, xh, yl, yh) { var x = new goog.math.Long(xl, xh); var y = new goog.math.Long(yl, yh); var ret = x.add(y); - this.result[0] = ret.low_; - this.result[1] = ret.high_; + Wrapper.result[0] = ret.low_; + Wrapper.result[1] = ret.high_; }, subtract: function(xl, xh, yl, yh) { var x = new goog.math.Long(xl, xh); var y = new goog.math.Long(yl, yh); var ret = x.subtract(y); - this.result[0] = ret.low_; - this.result[1] = ret.high_; + Wrapper.result[0] = ret.low_; + Wrapper.result[1] = ret.high_; }, multiply: function(xl, xh, yl, yh) { var x = new goog.math.Long(xl, xh); var y = new goog.math.Long(yl, yh); var ret = x.multiply(y); - this.result[0] = ret.low_; - this.result[1] = ret.high_; + Wrapper.result[0] = ret.low_; + Wrapper.result[1] = ret.high_; }, - divide: function(xl, xh, yl, yh) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.div(y); - this.result[0] = ret.low_; - this.result[1] = ret.high_; + divide: function(xl, xh, yl, yh, unsigned) { + if (!Wrapper.two32) { + Wrapper.two32 = new BigInteger(); + Wrapper.two32.fromString('4294967296', 10); + } + function lh2bignum(l, h) { + var a = new BigInteger(); + a.fromString(h.toString(), 10); + var b = new BigInteger(); + a.multiplyTo(Wrapper.two32, b); + var c = new BigInteger(); + c.fromString(l.toString(), 10); + var d = new BigInteger(); + c.addTo(b, d); + return d; + } + if (!unsigned) { + var x = new goog.math.Long(xl, xh); + var y = new goog.math.Long(yl, yh); + var ret = x.div(y); + Wrapper.result[0] = ret.low_; + Wrapper.result[1] = ret.high_; + } else { + // slow precise bignum division + var x = lh2bignum(xl >>> 0, xh >>> 0); + var y = lh2bignum(yl >>> 0, yh >>> 0); + var z = new BigInteger(); + x.divRemTo(y, z, null); + var l = new BigInteger(); + var h = new BigInteger(); + z.divRemTo(Wrapper.two32, h, l); + Wrapper.result[0] = parseInt(l.toString()) | 0; + Wrapper.result[1] = parseInt(h.toString()) | 0; + } }, modulo: function(xl, xh, yl, yh) { var x = new goog.math.Long(xl, xh); var y = new goog.math.Long(yl, yh); var ret = x.modulo(y); - this.result[0] = ret.low_; - this.result[1] = ret.high_; + Wrapper.result[0] = ret.low_; + Wrapper.result[1] = ret.high_; }, stringify: function(l, h, unsigned) { var ret = new goog.math.Long(l, h).toString(); if (unsigned && ret[0] == '-') { // unsign slowly using jsbn bignums - var two64 = new BigInteger(); - two64.fromString('18446744073709551616', 10); // TODO: only do this once and only if needed + if (!Wrapper.two64) { + Wrapper.two64 = new BigInteger(); + Wrapper.two64.fromString('18446744073709551616', 10); + } var bignum = new BigInteger(); bignum.fromString(ret, 10); ret = new BigInteger(); - two64.addTo(bignum, ret); + Wrapper.two64.addTo(bignum, ret); ret = ret.toString(10); } return ret; } }; +return Wrapper; })(); //======= end closure i64 code ======= diff --git a/src/parseTools.js b/src/parseTools.js index 436b496e..a37a7c54 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1618,8 +1618,9 @@ function processMathop(item) { return result; } } - function i64PreciseOp(type) { - return finish(['(i64Math.' + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + '),i64Math.result[0])', 'i64Math.result[1]']); + function i64PreciseOp(type, lastArg) { + return finish(['(i64Math.' + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + + (lastArg ? ',' + lastArg : '') + '),i64Math.result[0])', 'i64Math.result[1]']); } switch (op) { // basic integer ops @@ -1724,7 +1725,7 @@ function processMathop(item) { } case 'sdiv': case 'udiv': { if (PRECISE_I64_MATH) { - return i64PreciseOp('divide'); + return i64PreciseOp('divide', op[0] === 'u'); } else { warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's'))); |