MCPcopy Create free account
hub / github.com/cortex-js/compute-engine / fpexp

Function fpexp

src/big-decimal/utils.ts:276–326  ·  view source on GitHub ↗
(x: bigint, bits: number)

Source from the content-addressed store, hash-verified

274 * @returns exp(x/2^bits) * 2^bits as a bigint
275 */
276export function fpexp(x: bigint, bits: number): bigint {
277 // exp(0) = 1
278 if (x === 0n) return 1n << BigInt(bits);
279
280 // Elevated internal scale. `targetHalvings` extra halvings shorten the Taylor
281 // series to O(√bits) terms; `guard` guard bits absorb the ~2^targetHalvings
282 // error amplification of the squaring-back phase (and the final downshift's
283 // rounding).
284 const targetHalvings = Math.round(EXP_REDUCE_COEF * Math.sqrt(bits));
285 const guard = targetHalvings + 8;
286 const bits2 = bits + guard;
287 const B = BigInt(bits2);
288 const scale = 1n << B;
289
290 // Lift the input to the elevated scale.
291 const g = BigInt(guard);
292 let r = x << g;
293
294 // Argument reduction: halve until |r/scale| < 2^−targetHalvings. The shift
295 // count is derived from the ACTUAL magnitude of r, so a small argument (e.g.
296 // fpln's Newton seed near ln 1 = 0) is never over-reduced to 0 — the shift
297 // always leaves ~bits2 − targetHalvings significant bits. Sign is carried
298 // separately (a right-shift of a negative bigint would round toward −∞).
299 const neg = r < 0n;
300 let ra = neg ? -r : r;
301 const kExtra = Math.max(0, bitLength(ra) - bits2 + targetHalvings);
302 ra >>= BigInt(kExtra);
303 r = neg ? -ra : ra;
304
305 // Taylor series: exp(r/scale) = 1 + r/scale + r²/(2!·scale²) + ...
306 // In fixed-point: sum = scale + r + r²/(2·scale) + r³/(6·scale²) + ...
307 // Incremental: term_n = term_{n-1} * r / (n * scale)
308 // base-2: ((term * r) >> bits2) / n — shift + small-divisor division
309 let sum = scale; // 1.0
310 let term = r; // r/scale in fixed-point
311 sum += term;
312
313 for (let n = 2; ; n++) {
314 term = ((term * r) >> B) / BigInt(n);
315 if (term === 0n) break;
316 sum += term;
317 }
318
319 // Squaring phase: exp(x/scale) = exp((x/scale)/2^kExtra)^(2^kExtra).
320 for (let i = 0; i < kExtra; i++) {
321 sum = (sum * sum) >> B;
322 }
323
324 // Downshift from the elevated scale back to `bits`, rounding to nearest.
325 return (sum + (1n << (g - 1n))) >> g;
326}
327
328// AGM-vs-direct-log crossover, in bits. Below LN_AGM_MIN_BITS the direct-log
329// kernel (`fplnDirect`: one √-reduced fpexp + a short log1p series) wins; above

Callers 3

transcendentals.tsFile · 0.90
utils.test.tsFile · 0.85
fplnDirectFunction · 0.85

Calls 3

bitLengthFunction · 0.85
sqrtMethod · 0.65
roundMethod · 0.45

Tested by

no test coverage detected