/* * Copyright 2018 Alexey Andreev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ "use strict"; var Long_divRem; var Long_udivRem; var Long_shiftLeft16; var Long_shiftRight16; var LongInt; var LongInt_mul; var LongInt_sub; var LongInt_add; var LongInt_inc; var LongInt_dec; var LongInt_ucompare; var LongInt_numOfLeadingZeroBits; var LongInt_shl; var LongInt_shr; var LongInt_copy; var LongInt_div; var Long_eq; var Long_ne; var Long_gt; var Long_ge; var Long_lt; var Long_le; var Long_compare; var Long_ucompare; var Long_add; var Long_sub; var Long_inc; var Long_dec; var Long_mul; var Long_div; var Long_rem; var Long_udiv; var Long_urem; var Long_neg; var Long_and; var Long_or; var Long_xor; var Long_shl; var Long_shr; var Long_shru; var Long_not; if (typeof BigInt !== 'function') { Long_eq = function(a, b) { return a.hi === b.hi && a.lo === b.lo; } Long_ne = function(a, b) { return a.hi !== b.hi || a.lo !== b.lo; } Long_gt = function(a, b) { if (a.hi < b.hi) { return false; } if (a.hi > b.hi) { return true; } var x = a.lo >>> 1; var y = b.lo >>> 1; if (x !== y) { return x > y; } return (a.lo & 1) > (b.lo & 1); } Long_ge = function(a, b) { if (a.hi < b.hi) { return false; } if (a.hi > b.hi) { return true; } var x = a.lo >>> 1; var y = b.lo >>> 1; if (x !== y) { return x >= y; } return (a.lo & 1) >= (b.lo & 1); } Long_lt = function(a, b) { if (a.hi > b.hi) { return false; } if (a.hi < b.hi) { return true; } var x = a.lo >>> 1; var y = b.lo >>> 1; if (x !== y) { return x < y; } return (a.lo & 1) < (b.lo & 1); } Long_le = function(a, b) { if (a.hi > b.hi) { return false; } if (a.hi < b.hi) { return true; } var x = a.lo >>> 1; var y = b.lo >>> 1; if (x !== y) { return x <= y; } return (a.lo & 1) <= (b.lo & 1); } Long_add = function(a, b) { if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { return Long_fromNumber(a.lo + b.lo); } else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b)); } var a_lolo = a.lo & 0xFFFF; var a_lohi = a.lo >>> 16; var a_hilo = a.hi & 0xFFFF; var a_hihi = a.hi >>> 16; var b_lolo = b.lo & 0xFFFF; var b_lohi = b.lo >>> 16; var b_hilo = b.hi & 0xFFFF; var b_hihi = b.hi >>> 16; var lolo = (a_lolo + b_lolo) | 0; var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0; var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0; var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0; return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); } Long_inc = function(a) { var lo = (a.lo + 1) | 0; var hi = a.hi; if (lo === 0) { hi = (hi + 1) | 0; } return new Long(lo, hi); } Long_dec = function(a) { var lo = (a.lo - 1) | 0; var hi = a.hi; if (lo === -1) { hi = (hi - 1) | 0; } return new Long(lo, hi); } Long_neg = function(a) { return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF)); } Long_sub = function(a, b) { if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { return Long_fromNumber(a.lo - b.lo); } var a_lolo = a.lo & 0xFFFF; var a_lohi = a.lo >>> 16; var a_hilo = a.hi & 0xFFFF; var a_hihi = a.hi >>> 16; var b_lolo = b.lo & 0xFFFF; var b_lohi = b.lo >>> 16; var b_hilo = b.hi & 0xFFFF; var b_hihi = b.hi >>> 16; var lolo = (a_lolo - b_lolo) | 0; var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0; var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0; var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0; return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); } Long_compare = function(a, b) { var r = a.hi - b.hi; if (r !== 0) { return r; } r = (a.lo >>> 1) - (b.lo >>> 1); if (r !== 0) { return r; } return (a.lo & 1) - (b.lo & 1); } Long_ucompare = function(a, b) { var r = $rt_ucmp(a.hi, b.hi); if (r !== 0) { return r; } r = (a.lo >>> 1) - (b.lo >>> 1); if (r !== 0) { return r; } return (a.lo & 1) - (b.lo & 1); } Long_mul = function(a, b) { var positive = Long_isNegative(a) === Long_isNegative(b); if (Long_isNegative(a)) { a = Long_neg(a); } if (Long_isNegative(b)) { b = Long_neg(b); } var a_lolo = a.lo & 0xFFFF; var a_lohi = a.lo >>> 16; var a_hilo = a.hi & 0xFFFF; var a_hihi = a.hi >>> 16; var b_lolo = b.lo & 0xFFFF; var b_lohi = b.lo >>> 16; var b_hilo = b.hi & 0xFFFF; var b_hihi = b.hi >>> 16; var lolo = 0; var lohi = 0; var hilo = 0; var hihi = 0; lolo = (a_lolo * b_lolo) | 0; lohi = lolo >>> 16; lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0; hilo = (hilo + (lohi >>> 16)) | 0; lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0; hilo = (hilo + (lohi >>> 16)) | 0; hihi = hilo >>> 16; hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0; hihi = (hihi + (hilo >>> 16)) | 0; hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0; hihi = (hihi + (hilo >>> 16)) | 0; hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0; hihi = (hihi + (hilo >>> 16)) | 0; hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0; var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16)); return positive ? result : Long_neg(result); } Long_div = function(a, b) { if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); } return Long_divRem(a, b)[0]; } Long_udiv = function(a, b) { if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) { return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); } return Long_udivRem(a, b)[0]; } Long_rem = function(a, b) { if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b)); } return Long_divRem(a, b)[1]; } Long_urem = function(a, b) { if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) { return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); } return Long_udivRem(a, b)[1]; } Long_divRem = function(a, b) { if (b.lo === 0 && b.hi === 0) { throw new Error("Division by zero"); } var positive = Long_isNegative(a) === Long_isNegative(b); if (Long_isNegative(a)) { a = Long_neg(a); } if (Long_isNegative(b)) { b = Long_neg(b); } a = new LongInt(a.lo, a.hi, 0); b = new LongInt(b.lo, b.hi, 0); var q = LongInt_div(a, b); a = new Long(a.lo, a.hi); q = new Long(q.lo, q.hi); return positive ? [q, a] : [Long_neg(q), Long_neg(a)]; }; Long_udivRem = function(a, b) { if (b.lo === 0 && b.hi === 0) { throw new Error("Division by zero"); } a = new LongInt(a.lo, a.hi, 0); b = new LongInt(b.lo, b.hi, 0); var q = LongInt_div(a, b); a = new Long(a.lo, a.hi); q = new Long(q.lo, q.hi); return [q, a]; }; Long_shiftLeft16 = function(a) { return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16)); }; Long_shiftRight16 = function(a) { return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16); }; Long_and = function(a, b) { return new Long(a.lo & b.lo, a.hi & b.hi); } Long_or = function(a, b) { return new Long(a.lo | b.lo, a.hi | b.hi); } Long_xor = function(a, b) { return new Long(a.lo ^ b.lo, a.hi ^ b.hi); } Long_shl = function(a, b) { b &= 63; if (b === 0) { return a; } else if (b < 32) { return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b)); } else if (b === 32) { return new Long(0, a.lo); } else { return new Long(0, a.lo << (b - 32)); } } Long_shr = function(a, b) { b &= 63; if (b === 0) { return a; } else if (b < 32) { return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b); } else if (b === 32) { return new Long(a.hi, a.hi >> 31); } else { return new Long((a.hi >> (b - 32)), a.hi >> 31); } } Long_shru = function(a, b) { b &= 63; if (b === 0) { return a; } else if (b < 32) { return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b); } else if (b === 32) { return new Long(a.hi, 0); } else { return new Long((a.hi >>> (b - 32)), 0); } } Long_not = function(a) { return new Long(~a.hi, ~a.lo); } // Represents a mutable 80-bit unsigned integer LongInt = function(lo, hi, sup) { this.lo = lo; this.hi = hi; this.sup = sup; }; LongInt_mul = function(a, b) { var a_lolo = ((a.lo & 0xFFFF) * b) | 0; var a_lohi = ((a.lo >>> 16) * b) | 0; var a_hilo = ((a.hi & 0xFFFF) * b) | 0; var a_hihi = ((a.hi >>> 16) * b) | 0; var sup = (a.sup * b) | 0; a_lohi = (a_lohi + (a_lolo >>> 16)) | 0; a_hilo = (a_hilo + (a_lohi >>> 16)) | 0; a_hihi = (a_hihi + (a_hilo >>> 16)) | 0; sup = (sup + (a_hihi >>> 16)) | 0; a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); a.sup = sup & 0xFFFF; }; LongInt_sub = function(a, b) { var a_lolo = a.lo & 0xFFFF; var a_lohi = a.lo >>> 16; var a_hilo = a.hi & 0xFFFF; var a_hihi = a.hi >>> 16; var b_lolo = b.lo & 0xFFFF; var b_lohi = b.lo >>> 16; var b_hilo = b.hi & 0xFFFF; var b_hihi = b.hi >>> 16; a_lolo = (a_lolo - b_lolo) | 0; a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0; a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0; a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0; var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0; a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); a.sup = sup; }; LongInt_add = function(a, b) { var a_lolo = a.lo & 0xFFFF; var a_lohi = a.lo >>> 16; var a_hilo = a.hi & 0xFFFF; var a_hihi = a.hi >>> 16; var b_lolo = b.lo & 0xFFFF; var b_lohi = b.lo >>> 16; var b_hilo = b.hi & 0xFFFF; var b_hihi = b.hi >>> 16; a_lolo = (a_lolo + b_lolo) | 0; a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0; a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0; a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0; var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0; a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); a.sup = sup; }; LongInt_inc = function(a) { a.lo = (a.lo + 1) | 0; if (a.lo === 0) { a.hi = (a.hi + 1) | 0; if (a.hi === 0) { a.sup = (a.sup + 1) & 0xFFFF; } } }; LongInt_dec = function(a) { a.lo = (a.lo - 1) | 0; if (a.lo === -1) { a.hi = (a.hi - 1) | 0; if (a.hi === -1) { a.sup = (a.sup - 1) & 0xFFFF; } } }; LongInt_ucompare = function(a, b) { var r = (a.sup - b.sup); if (r !== 0) { return r; } r = (a.hi >>> 1) - (b.hi >>> 1); if (r !== 0) { return r; } r = (a.hi & 1) - (b.hi & 1); if (r !== 0) { return r; } r = (a.lo >>> 1) - (b.lo >>> 1); if (r !== 0) { return r; } return (a.lo & 1) - (b.lo & 1); }; LongInt_numOfLeadingZeroBits = function(a) { var n = 0; var d = 16; while (d > 0) { if ((a >>> d) !== 0) { a >>>= d; n = (n + d) | 0; } d = (d / 2) | 0; } return 31 - n; }; LongInt_shl = function(a, b) { if (b === 0) { return; } if (b < 32) { a.sup = ((a.hi >>> (32 - b)) | (a.sup << b)) & 0xFFFF; a.hi = (a.lo >>> (32 - b)) | (a.hi << b); a.lo <<= b; } else if (b === 32) { a.sup = a.hi & 0xFFFF; a.hi = a.lo; a.lo = 0; } else if (b < 64) { a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF; a.hi = a.lo << b; a.lo = 0; } else if (b === 64) { a.sup = a.lo & 0xFFFF; a.hi = 0; a.lo = 0; } else { a.sup = (a.lo << (b - 64)) & 0xFFFF; a.hi = 0; a.lo = 0; } }; LongInt_shr = function(a, b) { if (b === 0) { return; } if (b === 32) { a.lo = a.hi; a.hi = a.sup; a.sup = 0; } else if (b < 32) { a.lo = (a.lo >>> b) | (a.hi << (32 - b)); a.hi = (a.hi >>> b) | (a.sup << (32 - b)); a.sup >>>= b; } else if (b === 64) { a.lo = a.sup; a.hi = 0; a.sup = 0; } else if (b < 64) { a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b)); a.hi = a.sup >>> (b - 32); a.sup = 0; } else { a.lo = a.sup >>> (b - 64); a.hi = 0; a.sup = 0; } }; LongInt_copy = function(a) { return new LongInt(a.lo, a.hi, a.sup); }; LongInt_div = function(a, b) { // Normalize divisor var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32; var sz = 1 + ((bits / 16) | 0); var dividentBits = bits % 16; LongInt_shl(b, bits); LongInt_shl(a, dividentBits); var q = new LongInt(0, 0, 0); while (sz-- > 0) { LongInt_shl(q, 16); // Calculate approximate q var digitA = (a.hi >>> 16) + (0x10000 * a.sup); var digitB = b.hi >>> 16; var digit = (digitA / digitB) | 0; var t = LongInt_copy(b); LongInt_mul(t, digit); // Adjust q either down or up if (LongInt_ucompare(t, a) >= 0) { while (LongInt_ucompare(t, a) > 0) { LongInt_sub(t, b); --digit; } } else { while (true) { var nextT = LongInt_copy(t); LongInt_add(nextT, b); if (LongInt_ucompare(nextT, a) > 0) { break; } t = nextT; ++digit; } } LongInt_sub(a, t); q.lo |= digit; LongInt_shl(a, 16); } LongInt_shr(a, bits + 16); return q; }; } else { Long_eq = function(a, b) { return a === b; } Long_ne = function(a, b) { return a !== b; } Long_gt = function(a, b) { return a > b; } Long_ge = function(a, b) { return a >= b; } Long_lt = function(a, b) { return a < b; } Long_le = function(a, b) { return a <= b; } Long_add = function(a, b) { return BigInt.asIntN(64, a + b); } Long_inc = function(a) { return BigInt.asIntN(64, a + 1); } Long_dec = function(a) { return BigInt.asIntN(64, a - 1); } Long_neg = function(a) { return BigInt.asIntN(64, -a); } Long_sub = function(a, b) { return BigInt.asIntN(64, a - b); } Long_compare = function(a, b) { return a < b ? -1 : a > b ? 1 : 0; } Long_ucompare = function(a, b) { a = BigInt.asUintN(64, a); b = BigInt.asUintN(64, b); return a < b ? -1 : a > b ? 1 : 0; } Long_mul = function(a, b) { return BigInt.asIntN(64, a * b); } Long_div = function(a, b) { return BigInt.asIntN(64, a / b); } Long_udiv = function(a, b) { return BigInt.asIntN(64, BigInt.asUintN(64, a) / BigInt.asUintN(64, b)); } Long_rem = function(a, b) { return BigInt.asIntN(64, a % b); } Long_urem = function(a, b) { return BigInt.asIntN(64, BigInt.asUintN(64, a) % BigInt.asUintN(64, b)); } Long_and = function(a, b) { return BigInt.asIntN(64, a & b); } Long_or = function(a, b) { return BigInt.asIntN(64, a | b); } Long_xor = function(a, b) { return BigInt.asIntN(64, a ^ b); } Long_shl = function(a, b) { return BigInt.asIntN(64, a << BigInt(b & 63)); } Long_shr = function(a, b) { return BigInt.asIntN(64, a >> BigInt(b & 63)); } Long_shru = function(a, b) { return BigInt.asIntN(64, BigInt.asUintN(64, a) >> BigInt(b & 63)); } Long_not = function(a) { return BigInt.asIntN(64, ~a); } }