eligendiexercitationem
Version:
Yet another class for arbitrary-precision integers in pure JavaScript. Small. Well tested.
991 lines (969 loc) • 47.5 kB
JavaScript
var wrapper = function () {
"use strict";
var supportsBase = function (I, base) {
var result = false;
try {
var x = I.parseInt("10", base);
result = I.toString(x, 10) === base.toString(10);
} catch (e) {
console.log(e);
}
return result;
};
var supportsBaseToString = function (I, base) {
var result = false;
try {
var s = base.toString(10);
var x = I.parseInt(s, 10);
result = I.toString(x, base) === "10";
} catch (e) {
console.log(e);
}
return result;
};
(function () {
var input10 = undefined;
var input16 = undefined;
var a = undefined;
var b = undefined;
var as = undefined;
var supportsHex = undefined;
var ok = undefined;
var create10IsOk = undefined;
var create16IsOk = undefined;
var addIsOk = undefined;
var multiplyIsOk = undefined;
var divideIsOk = undefined;
var remainderIsOk = undefined;
var initialize = function () {
var input10 = "012345678901234567890123456789012345678901234567890";
var input16 = "01234567890abcdef01234567890abcdef01234567890abcdef";
var a = I.parseInt(input10, 10);
var b = I.parseInt("213509123601923760129376102397651203958123402314875", 10);
var aa = I.multiply(a, a);
var t = I.parseInt("3735928559", 10);
var as = I.add(aa, t);
var supportsHex = false;
try {
var x = I.parseInt("10", 16);
supportsHex = I.toString(x, 10) === (16).toString(10);
} catch (e) {
console.log(e);
}
var x0 = I.parseInt(input10, 10);
var ok = "0" + I.toString(x0, 10) === input10;
var create10IsOk = ok;
var tmp0 = I.parseInt(input16, 16);
var create16IsOk = supportsHex && "0" + I.toString(tmp0, 16).toLowerCase() === input16;
var tmp1 = I.add(a, b);
var addIsOk = ok && I.toString(tmp1, 10) === "225854802503158328019499559186663549637024636882765";
var tmp2 = I.multiply(a, b);
var multiplyIsOk = ok && I.toString(tmp2, 10) === "2635915082473353673085235184843445396749745111229911595609669061939318527195756503500792996344363750";
var tmp3 = I.divide(as, b);
var divideIsOk = ok && I.toString(tmp3, 10) === "713860770730150993024342853794918979066195767402";
var tmp4 = I.remainder(as, b);
var remainderIsOk = ok && I.toString(tmp4, 10) === "149922972578668446272207027928631904526544890275909";
};
benchmarkSuite.add("create-10", function () {
if (!create10IsOk) {
throw new Error();
}
return I.parseInt(input10, 10);
}, { setup: initialize });
benchmarkSuite.add("create-hex", function () {
if (!create16IsOk) {
throw new Error();
}
return I.parseInt(input16, 16);
}, { setup: initialize });
benchmarkSuite.add("toString-10", function () {
if (!create10IsOk) {
throw new Error();
}
return I.toString(a, 10);
}, { setup: initialize });
benchmarkSuite.add("toString-hex", function () {
if (!create16IsOk) {
throw new Error();
}
return I.toString(a, 16);
}, { setup: initialize });
benchmarkSuite.add("add", function () {
if (!addIsOk) {
throw new Error();
}
return I.add(a, b);
}, { setup: initialize });
benchmarkSuite.add("mul", function () {
if (!multiplyIsOk) {
throw new Error();
}
return I.multiply(a, b);
}, { setup: initialize });
benchmarkSuite.add("div", function () {
if (!divideIsOk) {
throw new Error();
}
return I.divide(as, b);
}, { setup: initialize });
benchmarkSuite.add("mod", function () {
if (!remainderIsOk) {
throw new Error();
}
return I.remainder(as, b);
}, { setup: initialize });
benchmarkSuite.add("bitwise-shift-operators", function () {
var x = I.shiftLeft(a, 1);
var y = I.shiftRight(b, 1);
return I.compareTo(x, y) < 0;
}, { setup: initialize });
benchmarkSuite.add("bitwise-logical-operators", function () {
var x = I.and(a, b);
var y = I.or(a, b);
var z = I.xor(a, b);
return I.compareTo(x, y) < 0 && I.compareTo(x, z) < 0;
}, { setup: initialize });
}());
(function () {
var a = undefined;
var b = undefined;
var initialize = function () {
var a = I.parseInt("134217727", 10);
var b = I.parseInt("134217729", 10);
var c = I.multiply(a, b);
if (I.toString(c, 10) !== "18014398509481983") {
a = undefined;
b = undefined;
}
};
benchmarkSuite.add("27*27==54", function () {
return I.multiply(a, b);
}, { setup: initialize });
}());
(function () {
var a = undefined;
var b = undefined;
var initialize = function () {
var a = I.parseInt("1023", 10);
var b = I.parseInt("1025", 10);
var c = I.multiply(a, b);
if (I.toString(c, 10) !== "1048575") {
a = undefined;
b = undefined;
}
};
benchmarkSuite.add("10*10==20", function () {
return I.multiply(a, b);
}, { setup: initialize });
}());
benchmarkSuite.add("joseprio", function () {
//var params = ["1", "100000000", "7070"];
var params = [
"1",
"100000000000000",
"7071067"
];
var start = Date.now();
var iterations = 0;
var ZERO = I.parseInt("0", 10);
var ONE = I.parseInt("1", 10);
var TWO = I.parseInt("2", 10);
var currentPaint = I.parseInt(params[1], 10);
var currentRadius = I.parseInt(params[0], 10);
currentRadius = I.add(currentRadius, ONE);
var numberCircles = 0;
while (I.compareTo(currentPaint, ZERO) >= 0) {
numberCircles += 1;
var t = I.multiply(currentRadius, TWO);
currentPaint = I.subtract(currentPaint, t);
currentPaint = I.add(currentPaint, ONE);
currentRadius = I.add(currentRadius, TWO);
iterations += 1;
if (iterations === 1000) {
if (Date.now() - start > 4000) {
throw new Error("timeout");
}
iterations = 0;
}
}
numberCircles -= 1;
if (numberCircles !== Number.parseInt(params[2])) {
throw new Error(numberCircles);
}
}, { minSamples: 1 });
function assertEquals(x, y, t) {
if (x !== y) {
throw new RangeError(t + " : " + x + " !== " + y);
}
}
testSuite.add("parseInt", function (I) {
var s = "";
var a = undefined;
var b = undefined;
for (var i = 2; i < 37 + 1; i += 1) {
var z = i === 37 ? false : supportsBase(I, i);
if (!z) {
if (b != undefined) {
s += (s === "" ? "" : ",") + (a === b ? a.toString() : a.toString() + "-" + b.toString());
a = undefined;
b = undefined;
}
} else {
if (a == undefined) {
a = i;
}
b = i;
}
}
throw new RangeError(s);
});
testSuite.add("toString", function (I) {
var s = "";
var a = undefined;
var b = undefined;
for (var i = 2; i < 37 + 1; i += 1) {
var z = i === 37 ? false : supportsBaseToString(I, i);
if (!z) {
if (b != undefined) {
s += (s === "" ? "" : ",") + (a === b ? a.toString() : a.toString() + "-" + b.toString());
a = undefined;
b = undefined;
}
} else {
if (a == undefined) {
a = i;
}
b = i;
}
}
throw new RangeError(s);
});
var testDivide = function () {
var THREE = I.parseInt("3", 10);
var MINUS_THREE = I.parseInt("-3", 10);
var FOUR = I.parseInt("4", 10);
var MINUS_FOUR = I.parseInt("-4", 10);
var a = I.divide(FOUR, THREE);
var b = I.divide(FOUR, MINUS_THREE);
var c = I.divide(MINUS_FOUR, THREE);
var d = I.divide(MINUS_FOUR, MINUS_THREE);
var s = a + ", " + b + ", " + c + ", " + d;
if (s === "1, -1, -1, 1") {
return "truncated division";
}
if (s === "1, -2, -2, 1") {
return "floored division";
}
if (s === "1, -1, -2, 2") {
return "Euclidean division";
}
return "?";
};
var testRemainder = function () {
var THREE = I.parseInt("3", 10);
var MINUS_THREE = I.parseInt("-3", 10);
var FOUR = I.parseInt("4", 10);
var MINUS_FOUR = I.parseInt("-4", 10);
var a = I.remainder(FOUR, THREE);
var b = I.remainder(FOUR, MINUS_THREE);
var c = I.remainder(MINUS_FOUR, THREE);
var d = I.remainder(MINUS_FOUR, MINUS_THREE);
var s = a + ", " + b + ", " + c + ", " + d;
if (s === "1, 1, -1, -1") {
return "truncated division";
}
if (s === "1, -2, 2, -1") {
return "floored division";
}
if (s === "1, 1, 2, 2") {
return "Euclidean division";
}
return "?";
};
var test0 = function (operator) {
var property = "";
var f = function (x, y) {
return 0;
};
var f0 = function (x, y) {
return undefined;
};
if (operator === "%") {
f = function (x, y) {
return 0 + x % y;
};
f0 = function (x, y) {
return I.remainder(x, y);
};
}
if (operator === "/") {
f = function (x, y) {
return 0 + Math.sign(x) * Math.sign(y) * Math.floor(Math.abs(x) / Math.abs(y));
};
f0 = function (x, y) {
return I.divide(x, y);
};
}
if (operator === "&") {
f = function (x, y) {
return x & y;
};
f0 = function (x, y) {
return I.and(x, y);
};
}
if (operator === "|") {
f = function (x, y) {
return x | y;
};
f0 = function (x, y) {
return I.or(x, y);
};
}
if (operator === "^") {
f = function (x, y) {
return x ^ y;
};
f0 = function (x, y) {
return I.xor(x, y);
};
}
var THREE = I.parseInt("3", 10);
var MINUS_THREE = I.parseInt("-3", 10);
var FOUR = I.parseInt("4", 10);
var MINUS_FOUR = I.parseInt("-4", 10);
var f1 = function (a, b) {
var c = f0(a, b);
return I.toString(c, 10);
};
var a = f1(FOUR, THREE);
var b = f1(FOUR, MINUS_THREE);
var c = f1(MINUS_FOUR, THREE);
var d = f1(MINUS_FOUR, MINUS_THREE);
var s = a + ", " + b + ", " + c + ", " + d;
if (operator === "/") {
if (s === "1, -1, -1, 1") {
throw new RangeError("truncated division");
}
if (s === "1, -2, -2, 1") {
throw new RangeError("floored division");
}
if (s === "1, -1, -2, 2") {
throw new RangeError("Euclidean division");
}
}
if (operator === "%") {
if (s === "1, 1, -1, -1") {
throw new RangeError("truncated division");
}
if (s === "1, -2, 2, -1") {
throw new RangeError("floored division");
}
if (s === "1, 1, 2, 2") {
throw new RangeError("Euclidean division");
}
}
assertEquals(a, f(4, 3).toString(), "4 " + operator + " 3");
assertEquals(b, f(4, -3).toString(), "4 " + operator + " -3");
assertEquals(c, f(-4, 3).toString(), "-4 " + operator + " 3");
assertEquals(d, f(-4, -3).toString(), "-4 " + operator + " -3");
if (operator === "&" || operator === "|" || operator === "^") {
var fx = function (s1, s2) {
var a = I.parseInt(s1, 10);
var b = I.parseInt(s2, 10);
return f1(a, b);
};
var ff = function (a, b) {
var s1 = a.toString();
var s2 = b.toString();
assertEquals(fx(s1, s2).toString(), f(a, b).toString(), "-3 " + operator + " -2");
};
ff(4, 1);
ff(4, -1);
ff(-4, 1);
ff(-4, -1);
ff(3, 1);
ff(3, -1);
ff(-3, 1);
ff(-3, -1);
ff(4, 2);
ff(4, -2);
ff(-4, 2);
ff(-4, -2);
ff(3, 2);
ff(3, -2);
ff(-3, 2);
ff(-3, -2);
}
};
testSuite.add("%", function (I) {
test0("%");
});
testSuite.add("/", function (I) {
test0("/");
});
testSuite.add("&", function (I) {
test0("&");
});
testSuite.add("|", function (I) {
test0("|");
});
testSuite.add("^", function (I) {
test0("^");
});
testSuite.add("~", function (I) {
var x = I.parseInt("3", 10);
var tmp1 = I.not(x);
var s = I.toString(tmp1, 10);
assertEquals(s, (~3).toString(), "~3");
var x = I.parseInt("-3", 10);
var tmp1 = I.not(x);
var s = I.toString(tmp1, 10);
assertEquals(s, (~-3).toString(), "~-3");
});
testSuite.add("<<", function (I) {
var a = I.parseInt("3", 10);
var b = I.shiftLeft(a, 8);
var s = I.toString(b, 10);
assertEquals(s, (3 << 8).toString(), "3 << 8");
var a = I.parseInt("-3", 10);
var b = I.shiftLeft(a, 8);
var s = I.toString(b, 10);
assertEquals(s, (-3 << 8).toString(), "-3 << 8");
});
testSuite.add(">>", function (I) {
var a = I.parseInt("3", 10);
var b = I.shiftRight(a, 8);
var s = I.toString(b, 10);
assertEquals(s, (3 >> 8).toString(), "-3 >> 8");
var a = I.parseInt("-3", 10);
var b = I.shiftRight(a, 8);
var s = I.toString(b, 10);
assertEquals(s, (-3 >> 8).toString(), "-3 >> 8");
});
testSuite.add("<< -n", function (I) {
var a = I.parseInt("3", 10);
var b = I.shiftLeft(a, -1);
var s = I.toString(b, 10);
assertEquals(s, "1", "3 << -1"); // OR Throw an error (?)
});
testSuite.add(">> -n", function (I) {
var a = I.parseInt("3", 10);
var b = I.shiftRight(a, -1);
var s = I.toString(b, 10);
assertEquals(s, "6", "3 >> -1"); // OR Throw an error (?)
});
testSuite.add("<< 32", function (I) {
var a = I.parseInt("3", 10);
var b = I.shiftLeft(a, 32);
var s = I.toString(b, 10);
assertEquals(s, "12884901888", "3 << 32"); // OR Throw an error (?)
});
testSuite.add(">> 32", function (I) {
var a = I.parseInt("12884901888", 10);
var b = I.shiftRight(a, 32);
var s = I.toString(b, 10);
assertEquals(s, "3", "12884901888 >> 32"); // OR Throw an error (?)
});
testSuite.add("-1024 >> 9007199254740991", function (I) {
var a = I.parseInt("-1024", 10);
var b = I.shiftRight(a, 9007199254740991);
var s = I.toString(b, 10);
assertEquals(s, "-1");
});
//testSuite.add("1024 >> 9007199254740991", function (I) {
// var a = I.parseInt("1024", 10);
// var b = I.shiftRight(a, 9007199254740991);
// var s = I.toString(b, 10);
// assertEquals(s, "0");
//});
//testSuite.add("0 << 9007199254740991", function (I) {
// var a = I.parseInt("0", 10);
// var b = I.shiftLeft(a, 9007199254740991);
// var s = I.toString(b, 10);
// assertEquals(s, "0");
//});
testSuite.add("bitLength", function (I) {
// ceil(log2(this < 0 ? 0 - this : this + 1))
var a = I.parseInt("4294967295", 10);
var b = I.bitLength(a);
console.log(b, typeof b);
var s = typeof b === "number" ? b.toString(10) : "-"; // I.toString(b, 10);
assertEquals(s, "32", "bitLength(4294967295)");
for (var i = 0; i < 4; i += 1) {
var tmp0 = i.toString();
var tmp1 = I.parseInt(tmp0, 10);
var tmp2 = I.bitLength(tmp1);
var s = typeof tmp2 === "number" ? tmp2.toString(10) : "-";//I.toString(tmp2, 10);
assertEquals(s, (i === 0 ? 0 : 1 + Math.floor(Math.log(i + 0.5) * Math.LOG2E)).toString(), "bitLength(" + i.toString() + ")");
}
});
var testPow = function (sa, sb) {
var ssa = sa.toString();
var a = I.parseInt(ssa, 10);
var b = null;
try {
b = I.pow(a, sb);
} catch (error) {
if (sb < 0) {
console.log(error);
} else {
throw error;
}
}
var c = b == null ? null : I.toString(b, 10);
assertEquals(c, sb < 0 ? null : Math.pow(sa, sb).toString(), sa + " ** " + sb);
};
testSuite.add("x ** y", function (I) {
for (var a = +2; a >= -2; a -= 1) {
for (var b = +2; b >= -2; b -= 1) {
testPow(a, b);
}
}
});
// jsbn's bug
testSuite.add("0 ** (0xffffffff + 1)", function (I) {
testPow(0, 0xffffffff + 1);
});
testSuite.add("fromNumber", function (I) {
var i = I.fromNumber(42);
var s = I.toString(i, 10);
assertEquals(s, "42");
var i = I.fromNumber(9007199254740991);
var s = I.toString(i, 10);
assertEquals(s, "9007199254740991");
});
testSuite.add("fromNumber-big", function (I) {
var i = I.fromNumber(Number.MAX_VALUE);
var s = I.toString(i, 10);
assertEquals(s, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368");
});
testSuite.add("toNumber", function (I) {
var i = I.parseInt("42", 10);
var s = I.toNumber(i);
assertEquals(s, 42);
var i = I.parseInt("9007199254740991", 10);
var s = I.toNumber(i);
assertEquals(s, 9007199254740991);
});
testSuite.add("toNumber-big", function (I) {
var i = I.parseInt("100000000000000008192", 10);
var s = I.toNumber(i);
assertEquals(s, 100000000000000000000);
var i = I.parseInt("100000000000000008193", 10);
var s = I.toNumber(i);
assertEquals(s, 100000000000000016384);
// 2**106+(2**53+4)
var i = I.parseInt("81129638414606690702988259885060", 10);
var s = I.toNumber(i);
assertEquals(s, 9007199254740994 * 9007199254740992);
});
testSuite.add("mod", function (I) {
var testMod = function (I) {
var THREE = I.parseInt("3", 10);
var MINUS_THREE = I.parseInt("-3", 10);
var FOUR = I.parseInt("4", 10);
var MINUS_FOUR = I.parseInt("-4", 10);
var a = I.mod(FOUR, THREE);
var c = I.mod(MINUS_FOUR, THREE);
var as = I.toString(a, 10)
var cs = I.toString(c, 10);
assertEquals(as, "1");
assertEquals(cs, "2");
//try {
// var t = I.mod(FOUR, MINUS_THREE);
// assertEquals(false, true);
//} catch (error) {
//}
//try {
// var t = I.mod(MINUS_FOUR, MINUS_THREE);
// assertEquals(false, true);
//} catch (error) {
//}
};
testMod(I);
});
testSuite.add("modInverse", function (I) {
var a = I.parseInt("7", 10);
var b = I.parseInt("20", 10);
var x = I.modInverse(a, b);
var s = I.toString(x, 10);
assertEquals(s, "3");
});
testSuite.add("modPow", function (I) {
var a = I.parseInt("10", 10);
var b = I.parseInt("3", 10);
var c = I.parseInt("30", 10);
var x = I.modPow(a, b, c);
var s = I.toString(x, 10);
assertEquals(s, "10");
});
/*
testSuite.add("modPow", function (I) {
var t = Date.now();
var a = "-29694681763448712115267303514023904033265211886910761264672576231554464098637402550663040547342726600568933793424522580102024307390684120501123145913181335140054630257537266316462992944143291789428368597319366497044735307450905133722212599357295495795914532499656994934020209866067682479620381834108247731805362251476372300643310863145482504070318221407436590709353870667746678473405580031604287313646969125892734476605404502107124001169091069970155161376239893444309019800637825991490992886756114995636568690097893351815480034167383046629554600914654853770556603406920385489591581795592966209762321826324786588707444458373503608685515834491712886834370824573830770838543360344886700981870";
// var b = "119334647663227291363113405741243413916434827363146166012200067038894142816254113710841716638008805209543910927476491099816542561560345503311330152550056221240122563520612198703057065667637570340647063422988042473190059156975005813463818646696643573820202000369152615667401021816298491297653620614440782978764393137821956464627163145421579373439868081673415678986432326806001408975760610901250649711198896213496068605039486228645916762983047459546900860937537474723612261449751343757826252579432285178556676653805951590208797794400875516522254480074885052650095801006651270614765243081674516367874973021395155320563";
var b = "11933464766322729136311340574124341391643482736314616601220006703889414281625411371084171663";
var c = "21766174458617435773191008891802753781907668374255538511144643224689886235383840957210909013086056401571399717235807266581649606472148410291413364152197364477180887395655483738115072677402235101762521901569820740293149529620419333266262073471054548368736039519702486226506248861060256971802984953561121442680157668000761429988222457090413873973970171927093992114751765168063614761119615476233422096442783117971236371647333871414335895773474667308967050807005509320424799678417036867928316761272274230314067548291133582479583061439577559347101961771406173684378522703483495337037655006751328447510550299250924469288819";
//var e = "72324557783415787424155521118202596834933898242395886137674358852236580794269836377307287786755289962440782013831739423702014967616850758313183751932896777891669089456853771795527757996329325050996269324970201536028633484579111946278204478269805106124073503820660024439715627250378312057531479971103107712537148991421528677788413535635435770715226291273808528964474082509191820953587881465428407150420995055514194080761192776104785866884604229750694117199160680355057545631740521663782384430018469927006099212868328005800482010975321397684122860835203872900466151550540270815104453823592754896203799696226528729895";
var e = "13540802089857741167023542037988805222546440577229559332533075840910935632532209556364267054685794323888640528195606483456493117658256579047999363349321383330093264011066537310121911518868496867167891598543722545495853065340968093012365382813267366017727691685093503665250431900627681102142398694435798038224365707752325308958087778218641883318154142118828465677276422817258682513984877559101140482783383241463776862894614490093886509444848747212475405025421083989216107083936711753381670137437841278736875577642823331640840588001717269730039276342775573437428364758255438364398063059345080931231137408921321659897500";
var tmp0 = I.parseInt(a, 10);
var tmp1 = I.parseInt(b, 10);
var tmp2 = I.parseInt(c, 10);
var x = I.modPow(tmp0, tmp1, tmp2);
var s = I.toString(x, 10);
t = Date.now() - t;
console.log(t, url);
assertEquals(s, e, "modPow");
});
*/
//!!!
(function () {
var basicTests = [
"-1000000000000000000000000000000000001+1000000000000000000000000000000000000=-1",
"100000000000000000002222222222222222222-100000000000000000001111111111111111111=1111111111111111111",
"16**13==4503599627370496",
"123456789123456789**10==822526267372365207989468699031914332476569003445489153619518989325083908083922133639704420166045905346960117046949453426283086050487204639652635846010822673782217799736601",
"2**63=9223372036854775808",
"306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000=306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000",
"306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000=0x9822997e35bb99bcf103a64299aa92b8446ab93879fba53349f1626f3c8f78a4ee1d8d9e7562538f8e374fdf64c8eff7481c63cde5ca9821abfb3df6fb3e2489d2f85d34cf347f3e89191a19cc6b6b8072a976a8f1bcf68d20f18a1c0efb023252ba2d0961428a5c282d2645f3f7fa160f7f84aca88e40a74066c4a787bed7d0082f7e45b1ffee532715f56bd5f8168eaf7eaae112ed1316371f047692631e70e6b85b290ef063845b364dad7e10b9deb9fcfb708f83b7c3c6b82ce16eb0034c030b332a58d637a7b547fd0527051d7de9e5004db2ea2bd75f5c5a280a1a9b93c3c83373b6dcf1b65c01197096e97d13076b6613bc2ebf47c91fbe1aefeea966134bfbbf5f850320f0f0c2d88888bd82d118a6aaf8df2b092cf5456eff7e209feb476bf3c01d6d2e7ca0b9f40d83b107b4def92f2927cf0a1bb6190c67a4da91478709262ed1f1ecb77fbaf1197ac238c246a63a697f51e8d539f850e790137e7fce5f764896fdfb4fc3787520608f0400e72aeea5737c36304c6887ec1a174564ecec63a57b1e0946dc311dd3aea7bfae197ff9c7fcbf17c97d9db303d231702ef502dde1b53896196dc2e5d30b2b6ec58fc3744f4de08109eb99aa9f22ffe2f12f3953f516f91d35a8852aff4a19e250410fbd8dbcdae99f92f88e2f94341fc1ecdff32733d194c0541f708a72c5b4c03e5515e1086d0903addca0e172968ff1dee87bbd4fee679e2ee5a52975807ae7212cc2a33e0821e2d9b44eaa7dc29536a94c6597eda41bdd1e5e618e7b388b53d38ef9542523bce888738db46c6706c3ee82cbc3655408071e9e422a44d309e3cfd31ec2135ee0cba32b0c6721c8bee4d076543b71c35a06087a007c14e51d1f0c4d0aa9aa0751dfd3776d2357a010e6b147aca40c7b669291e6defbf5ca77505c960f14b330e6c90dc2539431329ef78a1e9f26b2ead7d28a622e6b586bcee22bd0a495442c6a1235588988252cbd4d36975560fb8e7e5c8cf06f29aeb68659c5cb4cf8d011375b00000000000000000000000000000000000000000000000000000000000000000000000000",
"9223372036854775808=0b1000000000000000000000000000000000000000000000000000000000000000",
"-1=-1",
"-10000000000000000=-10000000000000000",
"0x324AFCCC342342333CCD239998881232324AFCCC342342333CCD239998881232=22748133857356174891035811692236022265357659892433333914058690475216129757746",
"234345345345=234345345345",
"234345345345=0x3690123141",
"1230000000=1230000000",
"-0x10=-16",
"-0=0",
"-0000000000000000000000123=-123",
"1+0=1",
"10+10000000000000000=10000000000000010",
"10000000000000000+10=10000000000000010",
"10000000000000000+10000000000000000=20000000000000000",
"0b1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111+0b1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111=0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110",
"10+10=20",
"-10000000000000000+0=-10000000000000000",
"0+10000000000000000=10000000000000000",
"1+0b11111111111111111111111111=67108864",
"10-10000000000000000=-9999999999999990",
"10000000000000000-10=9999999999999990",
"10000000000000000-10000000000000000=0",
"10-10=0",
"-10000000000000000-0=-10000000000000000",
"0-10000000000000000=-10000000000000000",
"-1-0b11111111111111111111111111=-67108864",
"10*10000000000000000=100000000000000000",
"10000000000000000*10=100000000000000000",
"10000000000000000*10000000000000000=100000000000000000000000000000000",
"10*10=100",
"100000000000000000*-1=-100000000000000000",
"-1*100000000000000000=-100000000000000000",
"0*-100000000000000000=0",
"-100000000000000000*0=0",
"0*-1=0",
"10/10000000000000000=0",
"10000000000000000/10=1000000000000000",
"10000000000000000/10000000000000000=1",
"10/10=1",
"-10/10=-1",
"10/-10=-1",
"-10/-10=1",
"-3221225473/3=-1073741824",
"-3221225472/2=-1610612736",
"00000000000000000000000000000000000000/2=0",
"0/-10000000000000000=0",
"10000000000000000/-1000000000000000000000000000000000000000000000000=0",
"727587048255308587128283949527991017146474/3262705074329558374374751=223001169790014763",
"194994622673976706651658530346880329671441/985341126327582219965=197895548520066180152",
"10/10=1",
"6582018229284824168619876730229320890292528855852623664389292032/730750818665451459101842416358132502628711530497=9007199254740991",
"10%10000000000000000=10",
"10000000000000000%10=0",
"10000000000000000%10000000000000000=0",
"10%10=0",
"0%-10000000000000000=0",
"-3%3=0",
"10<=>10000000000000000=-1",
"10000000000000000<=>10=1",
"10000000000000000<=>10000000000000000=0",
"10<=>10=0",
"1<=>2=-1",
"2<=>1=1",
"0<=>10000000000000000=-1",
"10000000000000000<=>0=1",
"9007199254740991+1=9007199254740992",
"-9007199254740991-1=-9007199254740992",
"-5325786+0=-5325786",
"5325786+0=5325786",
"-10/-1=10",
"-10/1=-10",
"-10*-1=10",
"-10*1=-10",
"-1*-10=10",
"1*-10=-10",
"9-10=-1",
"-9+10=1",
"9720461847429978160121544487215098400/252477884013826224964152=38500250766113",
"-9574957903731725597006190931748628130509/38500250766113=-248698585416990960511658890",
"0<=>-1=1",
"-1<=>-1=0",
"0<=>0=0",
"1<=>1=0",
"1<=>-1=1",
"7%4=3",
"-1*-1=1",
"-1*0=0",
"6*5=30",
"3532344566*49823554654=175993962540860910164",
"306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000*306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000=93671200784116709168212603693264364491482625140650867012458907580850290479914858264565537535310631693272766559003934292711906009200684627249517173304448324734928094279109540960988005032678411543160632864773462725296609470788914777324208956654901916718052447794025580721872592906456183913463092191741342070445684239516003619737023925365750418514776445402451077204908500545814231399834008986998489607202994429669705269992974675929240962547032808582647838847126057197173872616052439789970160446312025948012277132907416345489644872455137593054745212854458919536502094918842320643368201359463330136605206022340820844860783320865546136566072749156961102456117415146305779819245975135392214778387549605996353627520849328240846135361548408069158100232642516618512258711646524053695093681984213935153010000089399908749062684640944173803129898417404797961177294631508660424692823609149766102132719268107342261493147254317799773900921401553815299967676469915320518174445065337121677714632518336731258782009414814334567511810621472393747064687526968680665458697226848388002476327915592106057333872616052439789970160446312025948012277132907416345489644872455137593054745212854458919536502094918842320643368201359463330136605206022340820844860689649664762019856904536553267838091625932521165128952233516227811364487907634747731788089985538696547573368802544473776446194223441831991262741538342075728960165587705104394192021995056721497205902051776170711077833288946615883183853085674853758507974771161355740521410846675200886077579684162126058431830475717314299296347939445989954767755930288891719226637427609836185444550609580805347569022203418477964077359417533994004736217734679815579419828489068466048860160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"11000000000/-11=-1000000000",
"0/-1=0",
"-2/-1=2",
"-2%-1=0",
"175993962540860910164/49823554654=3532344566",
"49823554654/34566=1441403",
"1234+1235=2469",
"-5%-3=-2",
"100000000000000000000*2=200000000000000000000",
"100000000000000000000*0=0",
"100000000000000000000/1000000000000000000000=0",
"0b11111111111111111111111111=0b11111111111111111111111111",
"1000%10=0",
"-0=0",
"30!=265252859812191058636308480000000",
"-2147483649=-0x80000001",
"10000000010000000-10000000=10000000000000000",
"12345678901234567890123456789012345678901234567890123456789012345678901234567890/1234567890=10000000001000000000100000000010000000001000000000100000000010000000001",
// an error if not zero-fill a result array in the division
"(0x1000000000000000000000000*0x1000000000000000000000000)/0x1000000000000000000000000=0x1000000000000000000000000",
// https://github.com/GoogleChromeLabs/jsbi/issues/13
"2788589391528142331873770897124985830679715361908029740727468171087321981075%170141183460469231731687303715884105727=170141183460469231731687303715884105726"
];
var run = function (input) {
//if (testDivide() !== "truncated division" && input.indexOf("/") !== -1) {
// console.log("TODO:testDivide");
// return;
//}
//if (testRemainder() !== "truncated division" && input.indexOf("%") !== -1) {
// console.log("TODO:testRemainder");
// return;
//}
if (input.indexOf("0x") !== -1 && !supportsBase(I, 16)) {
return;
}
if (input.indexOf("0b") !== -1 && !supportsBase(I, 2)) {
return;
}
var ZERO = I.parseInt("0", 10);
var ONE = I.parseInt("1", 10);
var divideType = testDivide();
var divideInternal = function (a, b) {
var q = I.divide(a, b);
if (divideType === "truncated division") {
return q;
}
if (divideType === "floored division") {
var p = I.multiply(q, b);
if (I.compareTo(a, ZERO) * I.compareTo(b, ZERO) < 0 && I.compareTo(p, a) !== 0) {
q = I.add(q, ONE);
}
return q;
}
if (divideType === "Euclidean division") {
var p = I.multiply(q, b);
if (I.compareTo(a, ZERO) < 0 && I.compareTo(p, a) !== 0) {
q = I.compareTo(b, ZERO) < 0 ? I.subtract(q, ONE) : I.add(q, ONE);
}
return q;
}
throw new RangeError(divideType);
};
var remainderType = testRemainder();
var remainderInternal = function (a, b) {
var r = I.remainder(a, b);
if (remainderType === "truncated division") {
return r;
}
if (remainderType === "floored division") {
if (I.compareTo(a, ZERO) * I.compareTo(b, ZERO) < 0 && I.compareTo(r, ZERO) !== 0) {
r = I.subtract(r, b);
}
return r;
}
if (remainderType === "Euclidean division") {
if (I.compareTo(a, ZERO) < 0 && I.compareTo(r, ZERO) !== 0) {
r = I.compareTo(b, ZERO) < 0 ? I.add(r, b) : I.subtract(r, b);
}
return r;
}
throw new RangeError(remainderType);
};
var integerRegExp = /^(0b|0x)?([0-9a-fA-F]+)/;
var operatorRegExp = /^(?:\*\*|[\+\-\*\/%]|<\=>|\!)/;
var pow = function (x, count, accumulator) {
if (count < 0) {
throw new RangeError();
}
return count < 1 ? accumulator : Math.floor(count / 2) * 2 !== count ? pow(x, count - 1, I.multiply(accumulator, x)) : pow(I.multiply(x, x), Math.floor(count / 2), accumulator);
};
var factorial = function (n) {
var result = I.parseInt("1", 10);
var i = 0;
while (++i <= n) {
var tmp0 = i.toString(10);
var tmp1 = I.parseInt(tmp0, 10);
result = I.multiply(result, tmp1);
}
return result;
};
var evaluate = function (input, position, p) {
var result = undefined;
var ok = true;
while (position < input.length && ok) {
if (result != undefined && input.slice(position, position + 1) === ")") {
return [
position,
result
];
}
if (result == undefined && input.slice(position, position + 1) === "(") {
var tmp = evaluate(input, position + 1, 0);
position = tmp[0];
result = tmp[1];
if (input.slice(position, position + 1) === ")") {
position += 1;
}
} else {
var match = integerRegExp.exec(input.slice(position));
if (match != undefined) {
position += match[0].length;
var i = I.parseInt(match[2], match[1] === "0b" ? 2 : match[1] === "0x" ? 16 : 10);
if (result == undefined) {
result = i;
} else {
result = I.multiply(result, i);
}
} else if (result != undefined) {
match = operatorRegExp.exec(input.slice(position));
if (match != undefined) {
var tmp = undefined;
if (match[0] === "+" && p < 2) {
position += match[0].length;
tmp = evaluate(input, position, 2);
position = tmp[0];
result = I.add(result, tmp[1]);
} else if (match[0] === "-" && p < 2) {
position += match[0].length;
tmp = evaluate(input, position, 2);
position = tmp[0];
result = I.subtract(result, tmp[1]);
} else if (match[0] === "*" && p < 3) {
position += match[0].length;
tmp = evaluate(input, position, 3);
position = tmp[0];
result = I.multiply(result, tmp[1]);
} else if (match[0] === "/" && p < 3) {
position += match[0].length;
tmp = evaluate(input, position, 3);
position = tmp[0];
result = divideInternal(result, tmp[1]);
} else if (match[0] === "%" && p < 3) {
position += match[0].length;
tmp = evaluate(input, position, 3);
position = tmp[0];
result = remainderInternal(result, tmp[1]);
} else if (match[0] === "<=>" && p < 1) {
position += match[0].length;
tmp = evaluate(input, position, 1);
position = tmp[0];
result = I.compareTo(result, tmp[1]);
} else if (match[0] === "**" && p < 3) {
position += match[0].length;
tmp = evaluate(input, position, 3);
position = tmp[0];
result = pow(result, Number.parseInt(I.toString(tmp[1], 10)), I.parseInt("1", 10));
} else if (match[0] === "!") {
position += match[0].length;
result = factorial(Number.parseInt(I.toString(result, 10), 10));
} else {
ok = false;
}
} else {
ok = false;
}
} else if (result == undefined) {
match = /^\-/.exec(input.slice(position));
if (match != undefined) {
position += match[0].length;
var tmp = evaluate(input, position, 3);
position = tmp[0];
var MINUS_ONE = I.parseInt("-1", 10);
result = I.multiply(MINUS_ONE, tmp[1]);
} else {
ok = false;
}
} else {
ok = false;
}
}
}
return [
position,
result
];
};
var t = input.split("=");
var right = t.slice(-1).join("=");
var radix = 10;
var prefix = "";
if (right.slice(0, 2) === "0b" || right.slice(0, 3) === "-0b") {
radix = 2;
prefix = "0b";
}
if (right.slice(0, 2) === "0x" || right.slice(0, 3) === "-0x") {
radix = 16;
prefix = "0x";
}
var result = evaluate(t.slice(0, -1).join("="), 0, 0)[1];
if (input.indexOf("<=>") === -1) {
var left = I.toString(result, radix).replace(/^(\-)?/, "$1" + prefix);
assertEquals(left.toLowerCase(), right.toLowerCase(), input); //!toLowerCase
} else {
assertEquals(Math.sign(result).toString(), Math.sign(Number(right)).toString(), input); //assertEquals((1 / result).toString(), (1 / Number(right)).toString(), input);
}
};
var i = -1;
var allTests = generatedTests.concat(basicTests);
while (++i < allTests.length) {
var input = allTests[i];
if (input !== "?") {
testSuite.add(input, run.bind(undefined, input));
}
}
}());
testSuite.add("negate", function () {
var a = I.parseInt("0", 10);
var b = I.negate(a);
var c = I.compareTo(a, b);
assertEquals(c, 0, "0<=>-0");
});
testSuite.add("2", function () {
for (var d = 2; d < 10 + 8; d += 8) {
for (var c = 1; c < Math.pow(2, 53); c *= d) {
var tmp0 = c.toString();
var base = I.parseInt(tmp0, 10);
var one = I.parseInt("1", 10);
var tmp1 = I.subtract(base, one);
var tmp2 = I.multiply(tmp1, base);
var tmp3 = I.add(tmp2, tmp1);
var tmp4 = I.multiply(tmp3, base);
var a = I.multiply(tmp4, base);
var b = I.add(tmp4, one);
var tmp6 = I.divide(a, b);
assertEquals(I.toString(tmp6, 10), (c - 1).toString(), "?");
}
}
});
};
// TODO: https://github.com/peterolson/BigInteger.js/issues/88