diff --git a/lib/utils/util.js b/lib/utils/util.js index aebb15f5..0aee3480 100644 --- a/lib/utils/util.js +++ b/lib/utils/util.js @@ -200,14 +200,6 @@ if (Object.assign) util.MAX_SAFE_INTEGER = 0x1fffffffffffff; -/** - * Max safe addition (52 bits). - * @const {Number} - * @default - */ - -util.MAX_SAFE_ADDITION = 0xfffffffffffff; - /** * Test whether a number is below MAX_SAFE_INTEGER. * @param {Number} value @@ -226,9 +218,44 @@ util.isSafeInteger = function isSafeInteger(value) { */ util.isSafeAddition = function isSafeAddition(a, b) { + var hi, lo, ahi, alo, bhi, blo; + var as, bs, s, c; + + // We only work on positive numbers. assert(a >= 0); assert(b >= 0); - return a <= util.MAX_SAFE_ADDITION && b <= util.MAX_SAFE_ADDITION; + + // Fast case. + if (a <= 0xfffffffffffff && b <= 0xfffffffffffff) + return true; + + // Do a 64 bit addition and check the top 11 bits. + ahi = (a * (1 / 0x100000000)) | 0; + alo = a | 0; + + bhi = (b * (1 / 0x100000000)) | 0; + blo = b | 0; + + // Credit to @indutny for this method. + lo = (alo + blo) | 0; + + s = lo >> 31; + as = alo >> 31; + bs = blo >> 31; + + c = ((as & bs) | (~s & (as ^ bs))) & 1; + + hi = (((ahi + bhi) | 0) + c) | 0; + + hi >>>= 0; + ahi >>>= 0; + bhi >>>= 0; + + // Overflow? + if (hi < ahi || hi < bhi) + return false; + + return (hi & 0xffe00000) === 0; }; /**