aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-04-01 18:08:14 -0700
committerAlon Zakai <alonzakai@gmail.com>2012-04-01 18:08:14 -0700
commit18a02098377c1f8a3b309f7415d10789a602eb40 (patch)
treecb3c262d5696d088be8ccc47c4d95bfd7095c2c8 /src
parente9cc64df79f9de9793ed74ade92dbd02c790f678 (diff)
use bignum for unsigned i64 precise division
Diffstat (limited to 'src')
-rw-r--r--src/long.js67
-rw-r--r--src/parseTools.js7
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')));