Source code
Revision control
Copy as Markdown
Other Tools
// Test that Math.pow uses fdlibm and produces the same bit-exact result on
// every platform.
//
// <= 28 ARM devices with unpatched OEM bionic returns 1.9275814160560204e-50
// for Math.pow(Math.PI, -100) — a 1-ULP-different result from the fdlibm
// value 1.9275814160560206e-50. Math.pow now unconditionally calls fdlibm_pow.
const FDLIBM_POW_PI_NEG_100 = 1.9275814160560206e-50;
assertEq(Math.pow(Math.PI, -100), FDLIBM_POW_PI_NEG_100);
// A few other inputs that hit the libm path (non-integer exponent, or an
// integer that overflows the integer-fast-path early). All must be bit-exact.
assertEq(Math.pow(2, 0.5), Math.SQRT2);
assertEq(Math.pow(10, 0.3010299956639812), 2);
assertEq(Math.pow(Math.E, 2), 7.3890560989306495);
assertEq(Math.pow(0.5, 100), 7.888609052210118e-31);
// Special-case paths must continue to work and return finite IEEE values.
assertEq(Math.pow(NaN, 0), 1);
assertEq(Math.pow(2, 0), 1);
assertEq(Math.pow(-0, 1), -0);
assertEq(Math.pow(4, 0.5), 2); // sqrt fast-path
assertEq(Math.pow(4, -0.5), 0.5);
assertEq(Math.pow(2, Infinity), Infinity);
assertEq(Math.pow(1, Infinity), NaN);
assertEq(Math.pow(-1, -Infinity), NaN);
// Exercise hot paths so baseline + ion both compile pow, and accumulate the
// result over 1000 iterations so any per-call bit difference (across tiers or
// platforms) compounds into the sum and is caught. The expected value is the
// bit-exact accumulated sum; it is deliberately not 1000 * FDLIBM_POW_PI_NEG_100
// because floating-point summation rounds at each step.
function loop() {
let acc = 0;
for (let i = 0; i < 1000; i++) {
acc += Math.pow(Math.PI, -100);
}
return acc;
}
assertEq(loop(), 1.9275814160560497e-47);
// Integer-exponent fast path (powi) is bit-deterministic — the integer fast
// path itself doesn't call libm at all for small n.
assertEq(Math.pow(3, 4), 81);
assertEq(Math.pow(2, 10), 1024);
assertEq(Math.pow(-2, 3), -8);