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/long.js | |
parent | e9cc64df79f9de9793ed74ade92dbd02c790f678 (diff) |
use bignum for unsigned i64 precise division
Diffstat (limited to 'src/long.js')
-rw-r--r-- | src/long.js | 67 |
1 files changed, 49 insertions, 18 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 ======= |