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

Function bigintDigits

src/big-decimal/utils.ts:198–237  ·  view source on GitHub ↗
(n: bigint)

Source from the content-addressed store, hash-verified

196
197/** Count the number of decimal digits in a bigint (absolute value). */
198export function bigintDigits(n: bigint): number {
199 if (n === 0n) return 1;
200 if (n < 0n) n = -n;
201 // Fast path: fits in a Number (< 2^53), so `Number(n)` is exact. Resolve the
202 // digit count with an exact float comparison ladder (a 4-deep binary search
203 // over the 16 possible lengths) rather than `Math.floor(Math.log10(x)) + 1`.
204 // The `log10` form is not only a libm call but *wrong* at a power-of-ten
205 // boundary: `Math.log10(999999999999999) === 15` rounds up, so it returned 16
206 // for the fifteen-nines value (and 999999999999998), over-counting by one and
207 // corrupting every consumer that derives an order of magnitude from the count
208 // (`cmp`'s magnitude early-out could invert an ordering; `toPrecision(15)` of
209 // a genuine 15-digit value rounded it to 1e15). Every power 10^0…10^15 is an
210 // exact double (10^15 < 2^53) and `x` is exact, so each comparison is exact —
211 // the ladder is correct by construction and needs no boundary fix-up. It is
212 // also faster than the old path (no `log10`): ~17–34% in an A/B micro-bench.
213 if (n < 0x20000000000000n) {
214 const x = Number(n);
215 if (x < 1e8) {
216 if (x < 1e4) return x < 1e2 ? (x < 1e1 ? 1 : 2) : x < 1e3 ? 3 : 4;
217 return x < 1e6 ? (x < 1e5 ? 5 : 6) : x < 1e7 ? 7 : 8;
218 }
219 if (x < 1e12) return x < 1e10 ? (x < 1e9 ? 9 : 10) : x < 1e11 ? 11 : 12;
220 return x < 1e14 ? (x < 1e13 ? 13 : 14) : x < 1e15 ? 15 : 16;
221 }
222 // Large bigints: seed the decimal digit count from the hex-string length.
223 // `n.toString(16).length` is a single near-linear native base-16 conversion
224 // (hex being a power of 2, it is far cheaper than a base-10 stringification)
225 // and gives `bits/4` rounded up — i.e. an upper bound on the bit length, high
226 // by at most the 3 bits the top nibble may leave unused. That is ≤ ~1 decimal
227 // digit of slack, which the cached-pow10 boundary walk (0–2 steps) settles
228 // exactly. Replaces the doubling + binary-search bit-length scan, whose
229 // ~2·log2(bits) per-step `tmp >> BigInt(shift)` calls each allocated a fresh
230 // full-width bigint. Byte-identical result; ~2–4× faster in the 30–500-digit
231 // working-precision range that dominates div/cmp operand sizing.
232 const bits = n.toString(16).length * 4;
233 let approx = Math.ceil(bits * 0.30102999566398);
234 while (n < pow10(approx - 1)) approx--;
235 while (n >= pow10(approx)) approx++;
236 return approx;
237}
238
239/**
240 * Extra argument-reduction depth for `fpexp`, as a multiple of √bits.

Callers 6

utils.test.tsFile · 0.90
fromFixedPointFunction · 0.90
cancellationLossFunction · 0.90
digitCountMethod · 0.90
roundMagnitudeTowardFunction · 0.90

Calls 3

pow10Function · 0.85
toStringMethod · 0.65
ceilMethod · 0.45

Tested by

no test coverage detected