mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-06 08:23:19 +08:00
Prove 32-bit products exact only below 2^53
The exactness test for a product's 32-bit form multiplied the operands' magnitude bounds in a double and accepted a result of at most 2^53. A bound of 2^53 + 1 (3 * 3002399751580331) rounds to 2^53 there, so a product the double rounds took the integer multiply's low bits: `(3 * 3002399751580331) | 0` printed 1 where Node prints 0. The test is now strict: a bound below 2^53 is exact, and no bound of 2^53 or more rounds below it.
This commit is contained in:
@@ -176,12 +176,14 @@ export function emitWrappingSum(
|
||||
}
|
||||
|
||||
/** Whether every product of a value in `left` and one in `right` is an
|
||||
* integer of magnitude at most 2^53, which the double product holds
|
||||
* exactly. */
|
||||
* integer of magnitude below 2^53, which the double product holds exactly.
|
||||
* The bound's own product is computed in a double: a bound of at least
|
||||
* 2^53 never rounds below 2^53, while 2^53 + 1 (3 * 3002399751580331)
|
||||
* rounds to 2^53, so the test is strict. */
|
||||
function exactProduct(left: IntegerRange, right: IntegerRange): boolean {
|
||||
const magnitude = (range: IntegerRange): number =>
|
||||
Math.max(Math.abs(range.min), Math.abs(range.max));
|
||||
return magnitude(left) * magnitude(right) <= 2 ** 53;
|
||||
return magnitude(left) * magnitude(right) < 2 ** 53;
|
||||
}
|
||||
|
||||
/** The number locals of `fn` that only hold exact integers (never -0) or NaN, with the range of
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/8195-wrapping-products-near-2-53.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Products that reach bitwise operators with operands whose ranges are
|
||||
// known, around 2^53: below it the double product is exact, and from it on
|
||||
// the double product rounds, so the 32-bit result comes from the rounded
|
||||
// value (3 * 3002399751580331 is 2^53 + 1, which rounds to 2^53).
|
||||
const pairs: [number, number][] = [
|
||||
[3, 3002399751580331],
|
||||
[-3, 3002399751580331],
|
||||
[2 ** 26, 2 ** 27],
|
||||
[94906265, 94906267],
|
||||
[94906267, 94906267],
|
||||
[7, 1286742750677284],
|
||||
[65535, 137443147777],
|
||||
];
|
||||
for (const [a, b] of pairs) console.log(a, b, (a * b) | 0, (a * b) >>> 0, (a * b) ^ 1, (a * b) << 3);
|
||||
|
||||
// The same products with literal operands, which the compiler sees whole.
|
||||
console.log((3 * 3002399751580331) | 0, (3 * 3002399751580331) >>> 0);
|
||||
console.log((-3 * 3002399751580331) | 0, (2 ** 26 * 2 ** 27) | 0);
|
||||
console.log((94906267 * 94906267) | 0, (94906265 * 94906267) >>> 0);
|
||||
|
||||
// A counted loop whose counter multiplies a constant past 2^53.
|
||||
const step = 1286742750677284;
|
||||
let h = 0;
|
||||
for (let k = 5; k < 9; k++) h = (h + ((k * step) | 0)) | 0;
|
||||
console.log(h);
|
||||
Reference in New Issue
Block a user