Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 11x 11x 11x 1x 10x 2x 8x 3x 5x 5x 5x 5x 5x 17x 17x 9x 9x 8x 8x 5x | /**
* Reads a lookup table with linear interpolation between its points, such as a calibration curve or a tank
* gauging table. Outside the table, the first or last output is held. Binary search: O(log n).
*
* @param x - The input to look up.
* @param table - The points `[x, y]`, sorted by increasing `x`.
* @returns The interpolated output; `NaN` for an empty table.
* @example
* const tank = [[0, 0], [10, 150], [20, 380]] as const;
* interpolateTable(15, tank); // 265
* interpolateTable(40, tank); // 380
*/
export function interpolateTable(x: number, table: readonly (readonly [x: number, y: number])[]): number {
const [first] = table;
const last = table.at(-1);
if (first === undefined || last === undefined) {
return NaN;
}
if (x <= first[0]) {
return first[1];
}
if (x >= last[0]) {
return last[1];
}
let low = first;
let high = last;
let lowIndex = 0;
let highIndex = table.length - 1;
while (highIndex - lowIndex > 1) {
const middleIndex = (lowIndex + highIndex) >>> 1;
/* v8 ignore next -- `?? high` only satisfies noUncheckedIndexedAccess. */
const middle = table[middleIndex] ?? high;
if (middle[0] <= x) {
low = middle;
lowIndex = middleIndex;
} else {
high = middle;
highIndex = middleIndex;
}
}
return low[1] + ((high[1] - low[1]) * (x - low[0])) / (high[0] - low[0]);
}
|