mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
Require integer views to stay below 2^53 exactly, and fix corpus 1420
This commit is contained in:
@@ -65,6 +65,22 @@ function magnitude(range: IntegerRange): number {
|
||||
return Math.max(Math.abs(range.min), Math.abs(range.max));
|
||||
}
|
||||
|
||||
/** The bounds of a sum and a product of two magnitude bounds, as doubles.
|
||||
* Below 2^53 the double result is the integer; above it the result is past
|
||||
* every exactness limit either way, and rounding moves it far less than the
|
||||
* margin from WIDE_BOUND to the i64 range. A result of exactly 2^53 may
|
||||
* stand for 2^53 + 1 (2^53 - 1 + 2 rounds to 2^53), so it moves to the next
|
||||
* double up unless the sum is exactly 2^53. */
|
||||
function sumBound(a: number, b: number): number {
|
||||
const sum = a + b;
|
||||
return sum === EXACT_DOUBLES && EXACT_DOUBLES - a !== b ? sum + 2 : sum;
|
||||
}
|
||||
|
||||
function productBound(a: number, b: number): number {
|
||||
const product = a * b;
|
||||
return product === EXACT_DOUBLES ? product + 2 : product;
|
||||
}
|
||||
|
||||
/** The wide view of `l op r` for `+`, `-` and `*` when the exact operands
|
||||
* have no proven result range (their product or sum may pass 2^53).
|
||||
*
|
||||
@@ -98,14 +114,14 @@ export function wideArithmetic(
|
||||
if (op === "*") {
|
||||
if (lv.below !== Infinity || rv.below !== Infinity) return null;
|
||||
below = EXACT_DOUBLES;
|
||||
bound = lv.bound * rv.bound;
|
||||
bound = productBound(lv.bound, rv.bound);
|
||||
} else if (lv.below === Infinity && rv.below === Infinity) {
|
||||
below = EXACT_DOUBLES;
|
||||
bound = lv.bound + rv.bound;
|
||||
bound = sumBound(lv.bound, rv.bound);
|
||||
} else if (lv.below === Infinity || rv.below === Infinity) {
|
||||
const [exact, wide] = lv.below === Infinity ? [lv, rv] : [rv, lv];
|
||||
below = Math.min(wide.below - exact.bound, EXACT_DOUBLES);
|
||||
bound = exact.bound + wide.bound;
|
||||
bound = sumBound(exact.bound, wide.bound);
|
||||
} else return null;
|
||||
if (!(bound <= WIDE_BOUND) || below < INDEX_LIMIT) return null;
|
||||
const operand = (value: LlValue, integer: LlInteger | null): string =>
|
||||
|
||||
@@ -60,6 +60,20 @@ function nearLimit(start: number): string {
|
||||
return seen.join(" ");
|
||||
}
|
||||
|
||||
function atLimit(start: number, end: number): string {
|
||||
// A counter of integer locals only, up to 2^53 - 1: `i + 2` may be
|
||||
// 2^53 + 1, whose double is 2^53, so `i + 1 === i + 2` holds at the end.
|
||||
let same = 0;
|
||||
let above = 0;
|
||||
let mixed = 0;
|
||||
for (let i = start; i <= end; i++) {
|
||||
if (i + 1 === i + 2) same++;
|
||||
if (i + 2 > 9007199254740992) above++;
|
||||
mixed += (i * 2) % 3;
|
||||
}
|
||||
return `${same} ${above} ${mixed}`;
|
||||
}
|
||||
|
||||
console.log(heapSort(new Int32Array([5, -3, 9, 0, 9, 2147483647, -2147483648, 7, 1])));
|
||||
console.log(heapSort(new Int32Array([])), heapSort(new Int32Array([4])));
|
||||
console.log(neighbors(new Float64Array([1, 2, 3, 4])));
|
||||
@@ -67,3 +81,5 @@ const sorted = new Int32Array([-5, -1, 0, 0, 3, 8, 8, 13]);
|
||||
console.log([-6, -1, 0, 1, 8, 13, 14].map((v) => lowerBound(sorted, v)).join());
|
||||
console.log(nearLimit(9007199254740988));
|
||||
console.log(nearLimit(-9007199254740991));
|
||||
console.log(atLimit(9007199254740988, 9007199254740991));
|
||||
console.log(atLimit(-9007199254740991, -9007199254740988));
|
||||
|
||||
Reference in New Issue
Block a user