mirror of
https://github.com/Wessel/Snowflakey.git
synced 2026-06-08 14:19:02 +02:00
748 lines
41 KiB
JavaScript
748 lines
41 KiB
JavaScript
var bigInt = function (undefined) {
|
|
"use strict";
|
|
var BASE = 1e7, LOG_BASE = 7, MAX_INT = 9007199254740992, MAX_INT_ARR = smallToArray(MAX_INT), DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
var supportsNativeBigInt = typeof BigInt === "function";
|
|
function Integer(v, radix, alphabet, caseSensitive) { if (typeof v === "undefined")
|
|
return Integer[0]; if (typeof radix !== "undefined")
|
|
return +radix === 10 && !alphabet ? parseValue(v) : parseBase(v, radix, alphabet, caseSensitive); return parseValue(v); }
|
|
function BigInteger(value, sign) { this.value = value; this.sign = sign; this.isSmall = false; }
|
|
BigInteger.prototype = Object.create(Integer.prototype);
|
|
function SmallInteger(value) { this.value = value; this.sign = value < 0; this.isSmall = true; }
|
|
SmallInteger.prototype = Object.create(Integer.prototype);
|
|
function NativeBigInt(value) { this.value = value; }
|
|
NativeBigInt.prototype = Object.create(Integer.prototype);
|
|
function isPrecise(n) { return -MAX_INT < n && n < MAX_INT; }
|
|
function smallToArray(n) { if (n < 1e7)
|
|
return [n]; if (n < 1e14)
|
|
return [n % 1e7, Math.floor(n / 1e7)]; return [n % 1e7, Math.floor(n / 1e7) % 1e7, Math.floor(n / 1e14)]; }
|
|
function arrayToSmall(arr) { trim(arr); var length = arr.length; if (length < 4 && compareAbs(arr, MAX_INT_ARR) < 0) {
|
|
switch (length) {
|
|
case 0: return 0;
|
|
case 1: return arr[0];
|
|
case 2: return arr[0] + arr[1] * BASE;
|
|
default: return arr[0] + (arr[1] + arr[2] * BASE) * BASE;
|
|
}
|
|
} return arr; }
|
|
function trim(v) { var i = v.length; while (v[--i] === 0)
|
|
; v.length = i + 1; }
|
|
function createArray(length) { var x = new Array(length); var i = -1; while (++i < length) {
|
|
x[i] = 0;
|
|
} return x; }
|
|
function truncate(n) { if (n > 0)
|
|
return Math.floor(n); return Math.ceil(n); }
|
|
function add(a, b) { var l_a = a.length, l_b = b.length, r = new Array(l_a), carry = 0, base = BASE, sum, i; for (i = 0; i < l_b; i++) {
|
|
sum = a[i] + b[i] + carry;
|
|
carry = sum >= base ? 1 : 0;
|
|
r[i] = sum - carry * base;
|
|
} while (i < l_a) {
|
|
sum = a[i] + carry;
|
|
carry = sum === base ? 1 : 0;
|
|
r[i++] = sum - carry * base;
|
|
} if (carry > 0)
|
|
r.push(carry); return r; }
|
|
function addAny(a, b) { if (a.length >= b.length)
|
|
return add(a, b); return add(b, a); }
|
|
function addSmall(a, carry) { var l = a.length, r = new Array(l), base = BASE, sum, i; for (i = 0; i < l; i++) {
|
|
sum = a[i] - base + carry;
|
|
carry = Math.floor(sum / base);
|
|
r[i] = sum - carry * base;
|
|
carry += 1;
|
|
} while (carry > 0) {
|
|
r[i++] = carry % base;
|
|
carry = Math.floor(carry / base);
|
|
} return r; }
|
|
BigInteger.prototype.add = function (v) { var n = parseValue(v); if (this.sign !== n.sign) {
|
|
return this.subtract(n.negate());
|
|
} var a = this.value, b = n.value; if (n.isSmall) {
|
|
return new BigInteger(addSmall(a, Math.abs(b)), this.sign);
|
|
} return new BigInteger(addAny(a, b), this.sign); };
|
|
BigInteger.prototype.plus = BigInteger.prototype.add;
|
|
SmallInteger.prototype.add = function (v) { var n = parseValue(v); var a = this.value; if (a < 0 !== n.sign) {
|
|
return this.subtract(n.negate());
|
|
} var b = n.value; if (n.isSmall) {
|
|
if (isPrecise(a + b))
|
|
return new SmallInteger(a + b);
|
|
b = smallToArray(Math.abs(b));
|
|
} return new BigInteger(addSmall(b, Math.abs(a)), a < 0); };
|
|
SmallInteger.prototype.plus = SmallInteger.prototype.add;
|
|
NativeBigInt.prototype.add = function (v) { return new NativeBigInt(this.value + parseValue(v).value); };
|
|
NativeBigInt.prototype.plus = NativeBigInt.prototype.add;
|
|
function subtract(a, b) { var a_l = a.length, b_l = b.length, r = new Array(a_l), borrow = 0, base = BASE, i, difference; for (i = 0; i < b_l; i++) {
|
|
difference = a[i] - borrow - b[i];
|
|
if (difference < 0) {
|
|
difference += base;
|
|
borrow = 1;
|
|
}
|
|
else
|
|
borrow = 0;
|
|
r[i] = difference;
|
|
} for (i = b_l; i < a_l; i++) {
|
|
difference = a[i] - borrow;
|
|
if (difference < 0)
|
|
difference += base;
|
|
else {
|
|
r[i++] = difference;
|
|
break;
|
|
}
|
|
r[i] = difference;
|
|
} for (; i < a_l; i++) {
|
|
r[i] = a[i];
|
|
} trim(r); return r; }
|
|
function subtractAny(a, b, sign) { var value; if (compareAbs(a, b) >= 0) {
|
|
value = subtract(a, b);
|
|
}
|
|
else {
|
|
value = subtract(b, a);
|
|
sign = !sign;
|
|
} value = arrayToSmall(value); if (typeof value === "number") {
|
|
if (sign)
|
|
value = -value;
|
|
return new SmallInteger(value);
|
|
} return new BigInteger(value, sign); }
|
|
function subtractSmall(a, b, sign) { var l = a.length, r = new Array(l), carry = -b, base = BASE, i, difference; for (i = 0; i < l; i++) {
|
|
difference = a[i] + carry;
|
|
carry = Math.floor(difference / base);
|
|
difference %= base;
|
|
r[i] = difference < 0 ? difference + base : difference;
|
|
} r = arrayToSmall(r); if (typeof r === "number") {
|
|
if (sign)
|
|
r = -r;
|
|
return new SmallInteger(r);
|
|
} return new BigInteger(r, sign); }
|
|
BigInteger.prototype.subtract = function (v) { var n = parseValue(v); if (this.sign !== n.sign) {
|
|
return this.add(n.negate());
|
|
} var a = this.value, b = n.value; if (n.isSmall)
|
|
return subtractSmall(a, Math.abs(b), this.sign); return subtractAny(a, b, this.sign); };
|
|
BigInteger.prototype.minus = BigInteger.prototype.subtract;
|
|
SmallInteger.prototype.subtract = function (v) { var n = parseValue(v); var a = this.value; if (a < 0 !== n.sign) {
|
|
return this.add(n.negate());
|
|
} var b = n.value; if (n.isSmall) {
|
|
return new SmallInteger(a - b);
|
|
} return subtractSmall(b, Math.abs(a), a >= 0); };
|
|
SmallInteger.prototype.minus = SmallInteger.prototype.subtract;
|
|
NativeBigInt.prototype.subtract = function (v) { return new NativeBigInt(this.value - parseValue(v).value); };
|
|
NativeBigInt.prototype.minus = NativeBigInt.prototype.subtract;
|
|
BigInteger.prototype.negate = function () { return new BigInteger(this.value, !this.sign); };
|
|
SmallInteger.prototype.negate = function () { var sign = this.sign; var small = new SmallInteger(-this.value); small.sign = !sign; return small; };
|
|
NativeBigInt.prototype.negate = function () { return new NativeBigInt(-this.value); };
|
|
BigInteger.prototype.abs = function () { return new BigInteger(this.value, false); };
|
|
SmallInteger.prototype.abs = function () { return new SmallInteger(Math.abs(this.value)); };
|
|
NativeBigInt.prototype.abs = function () { return new NativeBigInt(this.value >= 0 ? this.value : -this.value); };
|
|
function multiplyLong(a, b) { var a_l = a.length, b_l = b.length, l = a_l + b_l, r = createArray(l), base = BASE, product, carry, i, a_i, b_j; for (i = 0; i < a_l; ++i) {
|
|
a_i = a[i];
|
|
for (var j = 0; j < b_l; ++j) {
|
|
b_j = b[j];
|
|
product = a_i * b_j + r[i + j];
|
|
carry = Math.floor(product / base);
|
|
r[i + j] = product - carry * base;
|
|
r[i + j + 1] += carry;
|
|
}
|
|
} trim(r); return r; }
|
|
function multiplySmall(a, b) { var l = a.length, r = new Array(l), base = BASE, carry = 0, product, i; for (i = 0; i < l; i++) {
|
|
product = a[i] * b + carry;
|
|
carry = Math.floor(product / base);
|
|
r[i] = product - carry * base;
|
|
} while (carry > 0) {
|
|
r[i++] = carry % base;
|
|
carry = Math.floor(carry / base);
|
|
} return r; }
|
|
function shiftLeft(x, n) { var r = []; while (n-- > 0)
|
|
r.push(0); return r.concat(x); }
|
|
function multiplyKaratsuba(x, y) { var n = Math.max(x.length, y.length); if (n <= 30)
|
|
return multiplyLong(x, y); n = Math.ceil(n / 2); var b = x.slice(n), a = x.slice(0, n), d = y.slice(n), c = y.slice(0, n); var ac = multiplyKaratsuba(a, c), bd = multiplyKaratsuba(b, d), abcd = multiplyKaratsuba(addAny(a, b), addAny(c, d)); var product = addAny(addAny(ac, shiftLeft(subtract(subtract(abcd, ac), bd), n)), shiftLeft(bd, 2 * n)); trim(product); return product; }
|
|
function useKaratsuba(l1, l2) { return -.012 * l1 - .012 * l2 + 15e-6 * l1 * l2 > 0; }
|
|
BigInteger.prototype.multiply = function (v) { var n = parseValue(v), a = this.value, b = n.value, sign = this.sign !== n.sign, abs; if (n.isSmall) {
|
|
if (b === 0)
|
|
return Integer[0];
|
|
if (b === 1)
|
|
return this;
|
|
if (b === -1)
|
|
return this.negate();
|
|
abs = Math.abs(b);
|
|
if (abs < BASE) {
|
|
return new BigInteger(multiplySmall(a, abs), sign);
|
|
}
|
|
b = smallToArray(abs);
|
|
} if (useKaratsuba(a.length, b.length))
|
|
return new BigInteger(multiplyKaratsuba(a, b), sign); return new BigInteger(multiplyLong(a, b), sign); };
|
|
BigInteger.prototype.times = BigInteger.prototype.multiply;
|
|
function multiplySmallAndArray(a, b, sign) { if (a < BASE) {
|
|
return new BigInteger(multiplySmall(b, a), sign);
|
|
} return new BigInteger(multiplyLong(b, smallToArray(a)), sign); }
|
|
SmallInteger.prototype._multiplyBySmall = function (a) { if (isPrecise(a.value * this.value)) {
|
|
return new SmallInteger(a.value * this.value);
|
|
} return multiplySmallAndArray(Math.abs(a.value), smallToArray(Math.abs(this.value)), this.sign !== a.sign); };
|
|
BigInteger.prototype._multiplyBySmall = function (a) { if (a.value === 0)
|
|
return Integer[0]; if (a.value === 1)
|
|
return this; if (a.value === -1)
|
|
return this.negate(); return multiplySmallAndArray(Math.abs(a.value), this.value, this.sign !== a.sign); };
|
|
SmallInteger.prototype.multiply = function (v) { return parseValue(v)._multiplyBySmall(this); };
|
|
SmallInteger.prototype.times = SmallInteger.prototype.multiply;
|
|
NativeBigInt.prototype.multiply = function (v) { return new NativeBigInt(this.value * parseValue(v).value); };
|
|
NativeBigInt.prototype.times = NativeBigInt.prototype.multiply;
|
|
function square(a) { var l = a.length, r = createArray(l + l), base = BASE, product, carry, i, a_i, a_j; for (i = 0; i < l; i++) {
|
|
a_i = a[i];
|
|
carry = 0 - a_i * a_i;
|
|
for (var j = i; j < l; j++) {
|
|
a_j = a[j];
|
|
product = 2 * (a_i * a_j) + r[i + j] + carry;
|
|
carry = Math.floor(product / base);
|
|
r[i + j] = product - carry * base;
|
|
}
|
|
r[i + l] = carry;
|
|
} trim(r); return r; }
|
|
BigInteger.prototype.square = function () { return new BigInteger(square(this.value), false); };
|
|
SmallInteger.prototype.square = function () { var value = this.value * this.value; if (isPrecise(value))
|
|
return new SmallInteger(value); return new BigInteger(square(smallToArray(Math.abs(this.value))), false); };
|
|
NativeBigInt.prototype.square = function (v) { return new NativeBigInt(this.value * this.value); };
|
|
function divMod1(a, b) { var a_l = a.length, b_l = b.length, base = BASE, result = createArray(b.length), divisorMostSignificantDigit = b[b_l - 1], lambda = Math.ceil(base / (2 * divisorMostSignificantDigit)), remainder = multiplySmall(a, lambda), divisor = multiplySmall(b, lambda), quotientDigit, shift, carry, borrow, i, l, q; if (remainder.length <= a_l)
|
|
remainder.push(0); divisor.push(0); divisorMostSignificantDigit = divisor[b_l - 1]; for (shift = a_l - b_l; shift >= 0; shift--) {
|
|
quotientDigit = base - 1;
|
|
if (remainder[shift + b_l] !== divisorMostSignificantDigit) {
|
|
quotientDigit = Math.floor((remainder[shift + b_l] * base + remainder[shift + b_l - 1]) / divisorMostSignificantDigit);
|
|
}
|
|
carry = 0;
|
|
borrow = 0;
|
|
l = divisor.length;
|
|
for (i = 0; i < l; i++) {
|
|
carry += quotientDigit * divisor[i];
|
|
q = Math.floor(carry / base);
|
|
borrow += remainder[shift + i] - (carry - q * base);
|
|
carry = q;
|
|
if (borrow < 0) {
|
|
remainder[shift + i] = borrow + base;
|
|
borrow = -1;
|
|
}
|
|
else {
|
|
remainder[shift + i] = borrow;
|
|
borrow = 0;
|
|
}
|
|
}
|
|
while (borrow !== 0) {
|
|
quotientDigit -= 1;
|
|
carry = 0;
|
|
for (i = 0; i < l; i++) {
|
|
carry += remainder[shift + i] - base + divisor[i];
|
|
if (carry < 0) {
|
|
remainder[shift + i] = carry + base;
|
|
carry = 0;
|
|
}
|
|
else {
|
|
remainder[shift + i] = carry;
|
|
carry = 1;
|
|
}
|
|
}
|
|
borrow += carry;
|
|
}
|
|
result[shift] = quotientDigit;
|
|
} remainder = divModSmall(remainder, lambda)[0]; return [arrayToSmall(result), arrayToSmall(remainder)]; }
|
|
function divMod2(a, b) { var a_l = a.length, b_l = b.length, result = [], part = [], base = BASE, guess, xlen, highx, highy, check; while (a_l) {
|
|
part.unshift(a[--a_l]);
|
|
trim(part);
|
|
if (compareAbs(part, b) < 0) {
|
|
result.push(0);
|
|
continue;
|
|
}
|
|
xlen = part.length;
|
|
highx = part[xlen - 1] * base + part[xlen - 2];
|
|
highy = b[b_l - 1] * base + b[b_l - 2];
|
|
if (xlen > b_l) {
|
|
highx = (highx + 1) * base;
|
|
}
|
|
guess = Math.ceil(highx / highy);
|
|
do {
|
|
check = multiplySmall(b, guess);
|
|
if (compareAbs(check, part) <= 0)
|
|
break;
|
|
guess--;
|
|
} while (guess);
|
|
result.push(guess);
|
|
part = subtract(part, check);
|
|
} result.reverse(); return [arrayToSmall(result), arrayToSmall(part)]; }
|
|
function divModSmall(value, lambda) { var length = value.length, quotient = createArray(length), base = BASE, i, q, remainder, divisor; remainder = 0; for (i = length - 1; i >= 0; --i) {
|
|
divisor = remainder * base + value[i];
|
|
q = truncate(divisor / lambda);
|
|
remainder = divisor - q * lambda;
|
|
quotient[i] = q | 0;
|
|
} return [quotient, remainder | 0]; }
|
|
function divModAny(self, v) { var value, n = parseValue(v); if (supportsNativeBigInt) {
|
|
return [new NativeBigInt(self.value / n.value), new NativeBigInt(self.value % n.value)];
|
|
} var a = self.value, b = n.value; var quotient; if (b === 0)
|
|
throw new Error("Cannot divide by zero"); if (self.isSmall) {
|
|
if (n.isSmall) {
|
|
return [new SmallInteger(truncate(a / b)), new SmallInteger(a % b)];
|
|
}
|
|
return [Integer[0], self];
|
|
} if (n.isSmall) {
|
|
if (b === 1)
|
|
return [self, Integer[0]];
|
|
if (b == -1)
|
|
return [self.negate(), Integer[0]];
|
|
var abs = Math.abs(b);
|
|
if (abs < BASE) {
|
|
value = divModSmall(a, abs);
|
|
quotient = arrayToSmall(value[0]);
|
|
var remainder = value[1];
|
|
if (self.sign)
|
|
remainder = -remainder;
|
|
if (typeof quotient === "number") {
|
|
if (self.sign !== n.sign)
|
|
quotient = -quotient;
|
|
return [new SmallInteger(quotient), new SmallInteger(remainder)];
|
|
}
|
|
return [new BigInteger(quotient, self.sign !== n.sign), new SmallInteger(remainder)];
|
|
}
|
|
b = smallToArray(abs);
|
|
} var comparison = compareAbs(a, b); if (comparison === -1)
|
|
return [Integer[0], self]; if (comparison === 0)
|
|
return [Integer[self.sign === n.sign ? 1 : -1], Integer[0]]; if (a.length + b.length <= 200)
|
|
value = divMod1(a, b);
|
|
else
|
|
value = divMod2(a, b); quotient = value[0]; var qSign = self.sign !== n.sign, mod = value[1], mSign = self.sign; if (typeof quotient === "number") {
|
|
if (qSign)
|
|
quotient = -quotient;
|
|
quotient = new SmallInteger(quotient);
|
|
}
|
|
else
|
|
quotient = new BigInteger(quotient, qSign); if (typeof mod === "number") {
|
|
if (mSign)
|
|
mod = -mod;
|
|
mod = new SmallInteger(mod);
|
|
}
|
|
else
|
|
mod = new BigInteger(mod, mSign); return [quotient, mod]; }
|
|
BigInteger.prototype.divmod = function (v) { var result = divModAny(this, v); return { quotient: result[0], remainder: result[1] }; };
|
|
NativeBigInt.prototype.divmod = SmallInteger.prototype.divmod = BigInteger.prototype.divmod;
|
|
BigInteger.prototype.divide = function (v) { return divModAny(this, v)[0]; };
|
|
NativeBigInt.prototype.over = NativeBigInt.prototype.divide = SmallInteger.prototype.over = SmallInteger.prototype.divide = BigInteger.prototype.over = BigInteger.prototype.divide;
|
|
BigInteger.prototype.mod = function (v) { return divModAny(this, v)[1]; };
|
|
NativeBigInt.prototype.mod = NativeBigInt.prototype.remainder = SmallInteger.prototype.remainder = SmallInteger.prototype.mod = BigInteger.prototype.remainder = BigInteger.prototype.mod;
|
|
BigInteger.prototype.pow = function (v) { var n = parseValue(v), a = this.value, b = n.value, value, x, y; if (b === 0)
|
|
return Integer[1]; if (a === 0)
|
|
return Integer[0]; if (a === 1)
|
|
return Integer[1]; if (a === -1)
|
|
return n.isEven() ? Integer[1] : Integer[-1]; if (n.sign) {
|
|
return Integer[0];
|
|
} if (!n.isSmall)
|
|
throw new Error("The exponent " + n.toString() + " is too large."); if (this.isSmall) {
|
|
if (isPrecise(value = Math.pow(a, b)))
|
|
return new SmallInteger(truncate(value));
|
|
} x = this; y = Integer[1]; while (true) {
|
|
if (b & 1 === 1) {
|
|
y = y.times(x);
|
|
--b;
|
|
}
|
|
if (b === 0)
|
|
break;
|
|
b /= 2;
|
|
x = x.square();
|
|
} return y; };
|
|
SmallInteger.prototype.pow = BigInteger.prototype.pow;
|
|
var pow;
|
|
if (supportsNativeBigInt) {
|
|
pow = eval("(a,b)=>a**b");
|
|
}
|
|
NativeBigInt.prototype.pow = function (v) { var n = parseValue(v); var a = this.value, b = n.value; if (b === BigInt(0))
|
|
return Integer[1]; if (a === BigInt(0))
|
|
return Integer[0]; if (a === BigInt(1))
|
|
return Integer[1]; if (a === BigInt(-1))
|
|
return n.isEven() ? Integer[1] : Integer[-1]; if (n.isNegative())
|
|
return new NativeBigInt(BigInt(0)); return new NativeBigInt(pow(a, b)); };
|
|
BigInteger.prototype.modPow = function (exp, mod) { exp = parseValue(exp); mod = parseValue(mod); if (mod.isZero())
|
|
throw new Error("Cannot take modPow with modulus 0"); var r = Integer[1], base = this.mod(mod); while (exp.isPositive()) {
|
|
if (base.isZero())
|
|
return Integer[0];
|
|
if (exp.isOdd())
|
|
r = r.multiply(base).mod(mod);
|
|
exp = exp.divide(2);
|
|
base = base.square().mod(mod);
|
|
} return r; };
|
|
NativeBigInt.prototype.modPow = SmallInteger.prototype.modPow = BigInteger.prototype.modPow;
|
|
function compareAbs(a, b) { if (a.length !== b.length) {
|
|
return a.length > b.length ? 1 : -1;
|
|
} for (var i = a.length - 1; i >= 0; i--) {
|
|
if (a[i] !== b[i])
|
|
return a[i] > b[i] ? 1 : -1;
|
|
} return 0; }
|
|
BigInteger.prototype.compareAbs = function (v) { var n = parseValue(v), a = this.value, b = n.value; if (n.isSmall)
|
|
return 1; return compareAbs(a, b); };
|
|
SmallInteger.prototype.compareAbs = function (v) { var n = parseValue(v), a = Math.abs(this.value), b = n.value; if (n.isSmall) {
|
|
b = Math.abs(b);
|
|
return a === b ? 0 : a > b ? 1 : -1;
|
|
} return -1; };
|
|
NativeBigInt.prototype.compareAbs = function (v) { var a = this.value; var b = parseValue(v).value; a = a >= 0 ? a : -a; b = b >= 0 ? b : -b; return a === b ? 0 : a > b ? 1 : -1; };
|
|
BigInteger.prototype.compare = function (v) { if (v === Infinity) {
|
|
return -1;
|
|
} if (v === -Infinity) {
|
|
return 1;
|
|
} var n = parseValue(v), a = this.value, b = n.value; if (this.sign !== n.sign) {
|
|
return n.sign ? 1 : -1;
|
|
} if (n.isSmall) {
|
|
return this.sign ? -1 : 1;
|
|
} return compareAbs(a, b) * (this.sign ? -1 : 1); };
|
|
BigInteger.prototype.compareTo = BigInteger.prototype.compare;
|
|
SmallInteger.prototype.compare = function (v) { if (v === Infinity) {
|
|
return -1;
|
|
} if (v === -Infinity) {
|
|
return 1;
|
|
} var n = parseValue(v), a = this.value, b = n.value; if (n.isSmall) {
|
|
return a == b ? 0 : a > b ? 1 : -1;
|
|
} if (a < 0 !== n.sign) {
|
|
return a < 0 ? -1 : 1;
|
|
} return a < 0 ? 1 : -1; };
|
|
SmallInteger.prototype.compareTo = SmallInteger.prototype.compare;
|
|
NativeBigInt.prototype.compare = function (v) { if (v === Infinity) {
|
|
return -1;
|
|
} if (v === -Infinity) {
|
|
return 1;
|
|
} var a = this.value; var b = parseValue(v).value; return a === b ? 0 : a > b ? 1 : -1; };
|
|
NativeBigInt.prototype.compareTo = NativeBigInt.prototype.compare;
|
|
BigInteger.prototype.equals = function (v) { return this.compare(v) === 0; };
|
|
NativeBigInt.prototype.eq = NativeBigInt.prototype.equals = SmallInteger.prototype.eq = SmallInteger.prototype.equals = BigInteger.prototype.eq = BigInteger.prototype.equals;
|
|
BigInteger.prototype.notEquals = function (v) { return this.compare(v) !== 0; };
|
|
NativeBigInt.prototype.neq = NativeBigInt.prototype.notEquals = SmallInteger.prototype.neq = SmallInteger.prototype.notEquals = BigInteger.prototype.neq = BigInteger.prototype.notEquals;
|
|
BigInteger.prototype.greater = function (v) { return this.compare(v) > 0; };
|
|
NativeBigInt.prototype.gt = NativeBigInt.prototype.greater = SmallInteger.prototype.gt = SmallInteger.prototype.greater = BigInteger.prototype.gt = BigInteger.prototype.greater;
|
|
BigInteger.prototype.lesser = function (v) { return this.compare(v) < 0; };
|
|
NativeBigInt.prototype.lt = NativeBigInt.prototype.lesser = SmallInteger.prototype.lt = SmallInteger.prototype.lesser = BigInteger.prototype.lt = BigInteger.prototype.lesser;
|
|
BigInteger.prototype.greaterOrEquals = function (v) { return this.compare(v) >= 0; };
|
|
NativeBigInt.prototype.geq = NativeBigInt.prototype.greaterOrEquals = SmallInteger.prototype.geq = SmallInteger.prototype.greaterOrEquals = BigInteger.prototype.geq = BigInteger.prototype.greaterOrEquals;
|
|
BigInteger.prototype.lesserOrEquals = function (v) { return this.compare(v) <= 0; };
|
|
NativeBigInt.prototype.leq = NativeBigInt.prototype.lesserOrEquals = SmallInteger.prototype.leq = SmallInteger.prototype.lesserOrEquals = BigInteger.prototype.leq = BigInteger.prototype.lesserOrEquals;
|
|
BigInteger.prototype.isEven = function () { return (this.value[0] & 1) === 0; };
|
|
SmallInteger.prototype.isEven = function () { return (this.value & 1) === 0; };
|
|
NativeBigInt.prototype.isEven = function () { return (this.value & BigInt(1)) === BigInt(0); };
|
|
BigInteger.prototype.isOdd = function () { return (this.value[0] & 1) === 1; };
|
|
SmallInteger.prototype.isOdd = function () { return (this.value & 1) === 1; };
|
|
NativeBigInt.prototype.isOdd = function () { return (this.value & BigInt(1)) === BigInt(1); };
|
|
BigInteger.prototype.isPositive = function () { return !this.sign; };
|
|
SmallInteger.prototype.isPositive = function () { return this.value > 0; };
|
|
NativeBigInt.prototype.isPositive = SmallInteger.prototype.isPositive;
|
|
BigInteger.prototype.isNegative = function () { return this.sign; };
|
|
SmallInteger.prototype.isNegative = function () { return this.value < 0; };
|
|
NativeBigInt.prototype.isNegative = SmallInteger.prototype.isNegative;
|
|
BigInteger.prototype.isUnit = function () { return false; };
|
|
SmallInteger.prototype.isUnit = function () { return Math.abs(this.value) === 1; };
|
|
NativeBigInt.prototype.isUnit = function () { return this.abs().value === BigInt(1); };
|
|
BigInteger.prototype.isZero = function () { return false; };
|
|
SmallInteger.prototype.isZero = function () { return this.value === 0; };
|
|
NativeBigInt.prototype.isZero = function () { return this.value === BigInt(0); };
|
|
BigInteger.prototype.isDivisibleBy = function (v) { var n = parseValue(v); if (n.isZero())
|
|
return false; if (n.isUnit())
|
|
return true; if (n.compareAbs(2) === 0)
|
|
return this.isEven(); return this.mod(n).isZero(); };
|
|
NativeBigInt.prototype.isDivisibleBy = SmallInteger.prototype.isDivisibleBy = BigInteger.prototype.isDivisibleBy;
|
|
function isBasicPrime(v) { var n = v.abs(); if (n.isUnit())
|
|
return false; if (n.equals(2) || n.equals(3) || n.equals(5))
|
|
return true; if (n.isEven() || n.isDivisibleBy(3) || n.isDivisibleBy(5))
|
|
return false; if (n.lesser(49))
|
|
return true; }
|
|
function millerRabinTest(n, a) { var nPrev = n.prev(), b = nPrev, r = 0, d, t, i, x; while (b.isEven())
|
|
b = b.divide(2), r++; next: for (i = 0; i < a.length; i++) {
|
|
if (n.lesser(a[i]))
|
|
continue;
|
|
x = bigInt(a[i]).modPow(b, n);
|
|
if (x.isUnit() || x.equals(nPrev))
|
|
continue;
|
|
for (d = r - 1; d != 0; d--) {
|
|
x = x.square().mod(n);
|
|
if (x.isUnit())
|
|
return false;
|
|
if (x.equals(nPrev))
|
|
continue next;
|
|
}
|
|
return false;
|
|
} return true; }
|
|
BigInteger.prototype.isPrime = function (strict) { var isPrime = isBasicPrime(this); if (isPrime !== undefined)
|
|
return isPrime; var n = this.abs(); var bits = n.bitLength(); if (bits <= 64)
|
|
return millerRabinTest(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022]); var logN = Math.log(2) * bits.toJSNumber(); var t = Math.ceil(strict === true ? 2 * Math.pow(logN, 2) : logN); for (var a = [], i = 0; i < t; i++) {
|
|
a.push(bigInt(i + 2));
|
|
} return millerRabinTest(n, a); };
|
|
NativeBigInt.prototype.isPrime = SmallInteger.prototype.isPrime = BigInteger.prototype.isPrime;
|
|
BigInteger.prototype.isProbablePrime = function (iterations) { var isPrime = isBasicPrime(this); if (isPrime !== undefined)
|
|
return isPrime; var n = this.abs(); var t = iterations === undefined ? 5 : iterations; for (var a = [], i = 0; i < t; i++) {
|
|
a.push(bigInt.randBetween(2, n.minus(2)));
|
|
} return millerRabinTest(n, a); };
|
|
NativeBigInt.prototype.isProbablePrime = SmallInteger.prototype.isProbablePrime = BigInteger.prototype.isProbablePrime;
|
|
BigInteger.prototype.modInv = function (n) { var t = bigInt.zero, newT = bigInt.one, r = parseValue(n), newR = this.abs(), q, lastT, lastR; while (!newR.isZero()) {
|
|
q = r.divide(newR);
|
|
lastT = t;
|
|
lastR = r;
|
|
t = newT;
|
|
r = newR;
|
|
newT = lastT.subtract(q.multiply(newT));
|
|
newR = lastR.subtract(q.multiply(newR));
|
|
} if (!r.isUnit())
|
|
throw new Error(this.toString() + " and " + n.toString() + " are not co-prime"); if (t.compare(0) === -1) {
|
|
t = t.add(n);
|
|
} if (this.isNegative()) {
|
|
return t.negate();
|
|
} return t; };
|
|
NativeBigInt.prototype.modInv = SmallInteger.prototype.modInv = BigInteger.prototype.modInv;
|
|
BigInteger.prototype.next = function () { var value = this.value; if (this.sign) {
|
|
return subtractSmall(value, 1, this.sign);
|
|
} return new BigInteger(addSmall(value, 1), this.sign); };
|
|
SmallInteger.prototype.next = function () { var value = this.value; if (value + 1 < MAX_INT)
|
|
return new SmallInteger(value + 1); return new BigInteger(MAX_INT_ARR, false); };
|
|
NativeBigInt.prototype.next = function () { return new NativeBigInt(this.value + BigInt(1)); };
|
|
BigInteger.prototype.prev = function () { var value = this.value; if (this.sign) {
|
|
return new BigInteger(addSmall(value, 1), true);
|
|
} return subtractSmall(value, 1, this.sign); };
|
|
SmallInteger.prototype.prev = function () { var value = this.value; if (value - 1 > -MAX_INT)
|
|
return new SmallInteger(value - 1); return new BigInteger(MAX_INT_ARR, true); };
|
|
NativeBigInt.prototype.prev = function () { return new NativeBigInt(this.value - BigInt(1)); };
|
|
var powersOfTwo = [1];
|
|
while (2 * powersOfTwo[powersOfTwo.length - 1] <= BASE)
|
|
powersOfTwo.push(2 * powersOfTwo[powersOfTwo.length - 1]);
|
|
var powers2Length = powersOfTwo.length, highestPower2 = powersOfTwo[powers2Length - 1];
|
|
function shift_isSmall(n) { return Math.abs(n) <= BASE; }
|
|
BigInteger.prototype.shiftLeft = function (v) { var n = parseValue(v).toJSNumber(); if (!shift_isSmall(n)) {
|
|
throw new Error(String(n) + " is too large for shifting.");
|
|
} if (n < 0)
|
|
return this.shiftRight(-n); var result = this; if (result.isZero())
|
|
return result; while (n >= powers2Length) {
|
|
result = result.multiply(highestPower2);
|
|
n -= powers2Length - 1;
|
|
} return result.multiply(powersOfTwo[n]); };
|
|
NativeBigInt.prototype.shiftLeft = SmallInteger.prototype.shiftLeft = BigInteger.prototype.shiftLeft;
|
|
BigInteger.prototype.shiftRight = function (v) { var remQuo; var n = parseValue(v).toJSNumber(); if (!shift_isSmall(n)) {
|
|
throw new Error(String(n) + " is too large for shifting.");
|
|
} if (n < 0)
|
|
return this.shiftLeft(-n); var result = this; while (n >= powers2Length) {
|
|
if (result.isZero() || result.isNegative() && result.isUnit())
|
|
return result;
|
|
remQuo = divModAny(result, highestPower2);
|
|
result = remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0];
|
|
n -= powers2Length - 1;
|
|
} remQuo = divModAny(result, powersOfTwo[n]); return remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0]; };
|
|
NativeBigInt.prototype.shiftRight = SmallInteger.prototype.shiftRight = BigInteger.prototype.shiftRight;
|
|
function bitwise(x, y, fn) { y = parseValue(y); var xSign = x.isNegative(), ySign = y.isNegative(); var xRem = xSign ? x.not() : x, yRem = ySign ? y.not() : y; var xDigit = 0, yDigit = 0; var xDivMod = null, yDivMod = null; var result = []; while (!xRem.isZero() || !yRem.isZero()) {
|
|
xDivMod = divModAny(xRem, highestPower2);
|
|
xDigit = xDivMod[1].toJSNumber();
|
|
if (xSign) {
|
|
xDigit = highestPower2 - 1 - xDigit;
|
|
}
|
|
yDivMod = divModAny(yRem, highestPower2);
|
|
yDigit = yDivMod[1].toJSNumber();
|
|
if (ySign) {
|
|
yDigit = highestPower2 - 1 - yDigit;
|
|
}
|
|
xRem = xDivMod[0];
|
|
yRem = yDivMod[0];
|
|
result.push(fn(xDigit, yDigit));
|
|
} var sum = fn(xSign ? 1 : 0, ySign ? 1 : 0) !== 0 ? bigInt(-1) : bigInt(0); for (var i = result.length - 1; i >= 0; i -= 1) {
|
|
sum = sum.multiply(highestPower2).add(bigInt(result[i]));
|
|
} return sum; }
|
|
BigInteger.prototype.not = function () { return this.negate().prev(); };
|
|
NativeBigInt.prototype.not = SmallInteger.prototype.not = BigInteger.prototype.not;
|
|
BigInteger.prototype.and = function (n) { return bitwise(this, n, function (a, b) { return a & b; }); };
|
|
NativeBigInt.prototype.and = SmallInteger.prototype.and = BigInteger.prototype.and;
|
|
BigInteger.prototype.or = function (n) { return bitwise(this, n, function (a, b) { return a | b; }); };
|
|
NativeBigInt.prototype.or = SmallInteger.prototype.or = BigInteger.prototype.or;
|
|
BigInteger.prototype.xor = function (n) { return bitwise(this, n, function (a, b) { return a ^ b; }); };
|
|
NativeBigInt.prototype.xor = SmallInteger.prototype.xor = BigInteger.prototype.xor;
|
|
var LOBMASK_I = 1 << 30, LOBMASK_BI = (BASE & -BASE) * (BASE & -BASE) | LOBMASK_I;
|
|
function roughLOB(n) { var v = n.value, x = typeof v === "number" ? v | LOBMASK_I : typeof v === "bigint" ? v | BigInt(LOBMASK_I) : v[0] + v[1] * BASE | LOBMASK_BI; return x & -x; }
|
|
function integerLogarithm(value, base) { if (base.compareTo(value) <= 0) {
|
|
var tmp = integerLogarithm(value, base.square(base));
|
|
var p = tmp.p;
|
|
var e = tmp.e;
|
|
var t = p.multiply(base);
|
|
return t.compareTo(value) <= 0 ? { p: t, e: e * 2 + 1 } : { p: p, e: e * 2 };
|
|
} return { p: bigInt(1), e: 0 }; }
|
|
BigInteger.prototype.bitLength = function () { var n = this; if (n.compareTo(bigInt(0)) < 0) {
|
|
n = n.negate().subtract(bigInt(1));
|
|
} if (n.compareTo(bigInt(0)) === 0) {
|
|
return bigInt(0);
|
|
} return bigInt(integerLogarithm(n, bigInt(2)).e).add(bigInt(1)); };
|
|
NativeBigInt.prototype.bitLength = SmallInteger.prototype.bitLength = BigInteger.prototype.bitLength;
|
|
function max(a, b) { a = parseValue(a); b = parseValue(b); return a.greater(b) ? a : b; }
|
|
function min(a, b) { a = parseValue(a); b = parseValue(b); return a.lesser(b) ? a : b; }
|
|
function gcd(a, b) { a = parseValue(a).abs(); b = parseValue(b).abs(); if (a.equals(b))
|
|
return a; if (a.isZero())
|
|
return b; if (b.isZero())
|
|
return a; var c = Integer[1], d, t; while (a.isEven() && b.isEven()) {
|
|
d = min(roughLOB(a), roughLOB(b));
|
|
a = a.divide(d);
|
|
b = b.divide(d);
|
|
c = c.multiply(d);
|
|
} while (a.isEven()) {
|
|
a = a.divide(roughLOB(a));
|
|
} do {
|
|
while (b.isEven()) {
|
|
b = b.divide(roughLOB(b));
|
|
}
|
|
if (a.greater(b)) {
|
|
t = b;
|
|
b = a;
|
|
a = t;
|
|
}
|
|
b = b.subtract(a);
|
|
} while (!b.isZero()); return c.isUnit() ? a : a.multiply(c); }
|
|
function lcm(a, b) { a = parseValue(a).abs(); b = parseValue(b).abs(); return a.divide(gcd(a, b)).multiply(b); }
|
|
function randBetween(a, b) { a = parseValue(a); b = parseValue(b); var low = min(a, b), high = max(a, b); var range = high.subtract(low).add(1); if (range.isSmall)
|
|
return low.add(Math.floor(Math.random() * range)); var digits = toBase(range, BASE).value; var result = [], restricted = true; for (var i = 0; i < digits.length; i++) {
|
|
var top = restricted ? digits[i] : BASE;
|
|
var digit = truncate(Math.random() * top);
|
|
result.push(digit);
|
|
if (digit < top)
|
|
restricted = false;
|
|
} return low.add(Integer.fromArray(result, BASE, false)); }
|
|
var parseBase = function (text, base, alphabet, caseSensitive) { alphabet = alphabet || DEFAULT_ALPHABET; text = String(text); if (!caseSensitive) {
|
|
text = text.toLowerCase();
|
|
alphabet = alphabet.toLowerCase();
|
|
} var length = text.length; var i; var absBase = Math.abs(base); var alphabetValues = {}; for (i = 0; i < alphabet.length; i++) {
|
|
alphabetValues[alphabet[i]] = i;
|
|
} for (i = 0; i < length; i++) {
|
|
var c = text[i];
|
|
if (c === "-")
|
|
continue;
|
|
if (c in alphabetValues) {
|
|
if (alphabetValues[c] >= absBase) {
|
|
if (c === "1" && absBase === 1)
|
|
continue;
|
|
throw new Error(c + " is not a valid digit in base " + base + ".");
|
|
}
|
|
}
|
|
} base = parseValue(base); var digits = []; var isNegative = text[0] === "-"; for (i = isNegative ? 1 : 0; i < text.length; i++) {
|
|
var c = text[i];
|
|
if (c in alphabetValues)
|
|
digits.push(parseValue(alphabetValues[c]));
|
|
else if (c === "<") {
|
|
var start = i;
|
|
do {
|
|
i++;
|
|
} while (text[i] !== ">" && i < text.length);
|
|
digits.push(parseValue(text.slice(start + 1, i)));
|
|
}
|
|
else
|
|
throw new Error(c + " is not a valid character");
|
|
} return parseBaseFromArray(digits, base, isNegative); };
|
|
function parseBaseFromArray(digits, base, isNegative) { var val = Integer[0], pow = Integer[1], i; for (i = digits.length - 1; i >= 0; i--) {
|
|
val = val.add(digits[i].times(pow));
|
|
pow = pow.times(base);
|
|
} return isNegative ? val.negate() : val; }
|
|
function stringify(digit, alphabet) { alphabet = alphabet || DEFAULT_ALPHABET; if (digit < alphabet.length) {
|
|
return alphabet[digit];
|
|
} return "<" + digit + ">"; }
|
|
function toBase(n, base) { base = bigInt(base); if (base.isZero()) {
|
|
if (n.isZero())
|
|
return { value: [0], isNegative: false };
|
|
throw new Error("Cannot convert nonzero numbers to base 0.");
|
|
} if (base.equals(-1)) {
|
|
if (n.isZero())
|
|
return { value: [0], isNegative: false };
|
|
if (n.isNegative())
|
|
return { value: [].concat.apply([], Array.apply(null, Array(-n.toJSNumber())).map(Array.prototype.valueOf, [1, 0])), isNegative: false };
|
|
var arr = Array.apply(null, Array(n.toJSNumber() - 1)).map(Array.prototype.valueOf, [0, 1]);
|
|
arr.unshift([1]);
|
|
return { value: [].concat.apply([], arr), isNegative: false };
|
|
} var neg = false; if (n.isNegative() && base.isPositive()) {
|
|
neg = true;
|
|
n = n.abs();
|
|
} if (base.isUnit()) {
|
|
if (n.isZero())
|
|
return { value: [0], isNegative: false };
|
|
return { value: Array.apply(null, Array(n.toJSNumber())).map(Number.prototype.valueOf, 1), isNegative: neg };
|
|
} var out = []; var left = n, divmod; while (left.isNegative() || left.compareAbs(base) >= 0) {
|
|
divmod = left.divmod(base);
|
|
left = divmod.quotient;
|
|
var digit = divmod.remainder;
|
|
if (digit.isNegative()) {
|
|
digit = base.minus(digit).abs();
|
|
left = left.next();
|
|
}
|
|
out.push(digit.toJSNumber());
|
|
} out.push(left.toJSNumber()); return { value: out.reverse(), isNegative: neg }; }
|
|
function toBaseString(n, base, alphabet) { var arr = toBase(n, base); return (arr.isNegative ? "-" : "") + arr.value.map(function (x) { return stringify(x, alphabet); }).join(""); }
|
|
BigInteger.prototype.toArray = function (radix) { return toBase(this, radix); };
|
|
SmallInteger.prototype.toArray = function (radix) { return toBase(this, radix); };
|
|
NativeBigInt.prototype.toArray = function (radix) { return toBase(this, radix); };
|
|
BigInteger.prototype.toString = function (radix, alphabet) { if (radix === undefined)
|
|
radix = 10; if (radix !== 10)
|
|
return toBaseString(this, radix, alphabet); var v = this.value, l = v.length, str = String(v[--l]), zeros = "0000000", digit; while (--l >= 0) {
|
|
digit = String(v[l]);
|
|
str += zeros.slice(digit.length) + digit;
|
|
} var sign = this.sign ? "-" : ""; return sign + str; };
|
|
SmallInteger.prototype.toString = function (radix, alphabet) { if (radix === undefined)
|
|
radix = 10; if (radix != 10)
|
|
return toBaseString(this, radix, alphabet); return String(this.value); };
|
|
NativeBigInt.prototype.toString = SmallInteger.prototype.toString;
|
|
NativeBigInt.prototype.toJSON = BigInteger.prototype.toJSON = SmallInteger.prototype.toJSON = function () { return this.toString(); };
|
|
BigInteger.prototype.valueOf = function () { return parseInt(this.toString(), 10); };
|
|
BigInteger.prototype.toJSNumber = BigInteger.prototype.valueOf;
|
|
SmallInteger.prototype.valueOf = function () { return this.value; };
|
|
SmallInteger.prototype.toJSNumber = SmallInteger.prototype.valueOf;
|
|
NativeBigInt.prototype.valueOf = NativeBigInt.prototype.toJSNumber = function () { return parseInt(this.toString(), 10); };
|
|
function parseStringValue(v) { if (isPrecise(+v)) {
|
|
var x = +v;
|
|
if (x === truncate(x))
|
|
return supportsNativeBigInt ? new NativeBigInt(BigInt(x)) : new SmallInteger(x);
|
|
throw new Error("Invalid integer: " + v);
|
|
} var sign = v[0] === "-"; if (sign)
|
|
v = v.slice(1); var split = v.split(/e/i); if (split.length > 2)
|
|
throw new Error("Invalid integer: " + split.join("e")); if (split.length === 2) {
|
|
var exp = split[1];
|
|
if (exp[0] === "+")
|
|
exp = exp.slice(1);
|
|
exp = +exp;
|
|
if (exp !== truncate(exp) || !isPrecise(exp))
|
|
throw new Error("Invalid integer: " + exp + " is not a valid exponent.");
|
|
var text = split[0];
|
|
var decimalPlace = text.indexOf(".");
|
|
if (decimalPlace >= 0) {
|
|
exp -= text.length - decimalPlace - 1;
|
|
text = text.slice(0, decimalPlace) + text.slice(decimalPlace + 1);
|
|
}
|
|
if (exp < 0)
|
|
throw new Error("Cannot include negative exponent part for integers");
|
|
text += new Array(exp + 1).join("0");
|
|
v = text;
|
|
} var isValid = /^([0-9][0-9]*)$/.test(v); if (!isValid)
|
|
throw new Error("Invalid integer: " + v); if (supportsNativeBigInt) {
|
|
return new NativeBigInt(BigInt(sign ? "-" + v : v));
|
|
} var r = [], max = v.length, l = LOG_BASE, min = max - l; while (max > 0) {
|
|
r.push(+v.slice(min, max));
|
|
min -= l;
|
|
if (min < 0)
|
|
min = 0;
|
|
max -= l;
|
|
} trim(r); return new BigInteger(r, sign); }
|
|
function parseNumberValue(v) { if (supportsNativeBigInt) {
|
|
return new NativeBigInt(BigInt(v));
|
|
} if (isPrecise(v)) {
|
|
if (v !== truncate(v))
|
|
throw new Error(v + " is not an integer.");
|
|
return new SmallInteger(v);
|
|
} return parseStringValue(v.toString()); }
|
|
function parseValue(v) { if (typeof v === "number") {
|
|
return parseNumberValue(v);
|
|
} if (typeof v === "string") {
|
|
return parseStringValue(v);
|
|
} if (typeof v === "bigint") {
|
|
return new NativeBigInt(v);
|
|
} return v; }
|
|
for (var i = 0; i < 1e3; i++) {
|
|
Integer[i] = parseValue(i);
|
|
if (i > 0)
|
|
Integer[-i] = parseValue(-i);
|
|
}
|
|
Integer.one = Integer[1];
|
|
Integer.zero = Integer[0];
|
|
Integer.minusOne = Integer[-1];
|
|
Integer.max = max;
|
|
Integer.min = min;
|
|
Integer.gcd = gcd;
|
|
Integer.lcm = lcm;
|
|
Integer.isInstance = function (x) { return x instanceof BigInteger || x instanceof SmallInteger || x instanceof NativeBigInt; };
|
|
Integer.randBetween = randBetween;
|
|
Integer.fromArray = function (digits, base, isNegative) { return parseBaseFromArray(digits.map(parseValue), parseValue(base || 10), isNegative); };
|
|
return Integer;
|
|
}();
|
|
if (typeof module !== "undefined" && module.hasOwnProperty("exports")) {
|
|
module.exports = bigInt;
|
|
}
|
|
if (typeof define === "function" && define.amd) {
|
|
define("big-integer", [], function () { return bigInt; });
|
|
}
|