functionalscript
Advanced tools
Comparing version 0.4.1 to 0.4.2
{ | ||
"name": "functionalscript", | ||
"version": "0.4.1", | ||
"version": "0.4.2", | ||
"type": "module", | ||
@@ -5,0 +5,0 @@ "files": [ |
@@ -26,2 +26,4 @@ /** | ||
export const serialize = (a) => `${a}n`; | ||
const { isFinite } = Number; | ||
const { log2: mathLog2 } = Math; | ||
/** | ||
@@ -56,3 +58,3 @@ * Calculates the base-2 logarithm (floor). | ||
// For example: `Number((1n << 1024n) - (1n << 970n)) === Inf`. | ||
let i = 1023n; | ||
let i = 0x400n; | ||
while (true) { | ||
@@ -73,3 +75,3 @@ const n = v >> i; | ||
// Because of this, We check if `i` is greater than 1023 before we divide it by 2. | ||
while (i !== 1023n) { | ||
while (i !== 0x400n) { | ||
i >>= 1n; | ||
@@ -85,8 +87,16 @@ const n = v >> i; | ||
// | ||
// We know that `v` is less than `1n << 1023` so we can calculate a remainder using | ||
// We know that `v` is less than `1n << 1024` so we can calculate a remainder using | ||
// `Math.log2`. | ||
const rem = BigInt(Math.log2(Number(v)) | 0); | ||
// (v >> rem) is either `0` or `1`, and it's used as a correction for | ||
// Math.log2 rounding. | ||
return result + rem + (v >> rem); | ||
const nl = mathLog2(Number(v)); | ||
if (isFinite(nl)) { | ||
const rem = BigInt(nl | 0); | ||
// (v >> rem) is either `0` or `1`, and it's used as a correction for | ||
// Math.log2 rounding. | ||
return result + rem + (v >> rem); | ||
} | ||
else { | ||
// nl is Inf, it means log2(v) === 0x3FF and we add +1 to compensate for initial | ||
// `result = -1n`. | ||
return result + 0x400n; | ||
} | ||
}; | ||
@@ -93,0 +103,0 @@ /** |
@@ -67,2 +67,46 @@ import { sum, abs, serialize, log2, bitLength, mask, min } from "./module.f.js"; | ||
}; | ||
const m1023log2 = (v) => { | ||
if (v <= 0n) { | ||
return -1n; | ||
} | ||
// | ||
// 1. Fast Doubling. | ||
// | ||
let result = -1n; | ||
// `bigints` higher than 2**1023 may lead to `Inf` during conversion to `number`. | ||
// For example: `Number((1n << 1024n) - (1n << 970n)) === Inf`. | ||
let i = 1023n; | ||
while (true) { | ||
const n = v >> i; | ||
if (n === 0n) { | ||
// overshot | ||
break; | ||
} | ||
v = n; | ||
result += i; | ||
i <<= 1n; | ||
} | ||
// | ||
// 2. Binary Search. | ||
// | ||
// We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0. | ||
// Because of this, We check if `i` is greater than 1023 before we divide it by 2. | ||
while (i !== 1023n) { | ||
i >>= 1n; | ||
const n = v >> i; | ||
if (n !== 0n) { | ||
result += i; | ||
v = n; | ||
} | ||
} | ||
// | ||
// 3. Remainder Phase. | ||
// | ||
// We know that `v` is less than `1n << 1023` so we can calculate a remainder using | ||
// `Math.log2`. | ||
const rem = BigInt(Math.log2(Number(v)) | 0); | ||
// (v >> rem) is either `0` or `1`, and it's used as a correction for | ||
// Math.log2 rounding. | ||
return result + rem + (v >> rem); | ||
}; | ||
const benchmark = f => () => { | ||
@@ -142,2 +186,3 @@ let e = 1048575n; | ||
clz32Log2, | ||
m1023log2, | ||
log2, | ||
@@ -144,0 +189,0 @@ }; |
553729
15787