bigint-decimal 1.0.19 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,244 +1,793 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = exports.BigintDecimal = void 0;
4
- class BigintDecimal {
5
- value = 0n;
6
- decimals = 0;
7
- static precision = 20;
8
- precision = BigintDecimal.precision;
9
- constructor(val = "0") {
10
- if (val instanceof BigintDecimal) {
11
- this.value = val.value;
12
- this.decimals = val.decimals;
13
- return;
14
- }
15
- if (!this.isBigintDecimal(val)) {
16
- throw new Error(`"${val}" is not safe parameter .`);
17
- }
18
- const numberInfo = this.getNumberIFoForBigintDecimal(val);
19
- this.value = numberInfo.value;
20
- this.decimals = numberInfo.decimals;
21
- this.trim();
22
- }
23
- static setPrecisionGlobal(newPrecision) {
24
- this.precision = newPrecision;
25
- }
26
- setPrecision(newPrecision) {
27
- this.precision = newPrecision;
28
- }
29
- trim() {
30
- if (this.value === 0n) {
31
- this.value = 0n;
32
- this.decimals = 0;
33
- }
34
- // While we have decimals AND the last digit is 0
35
- while (this.decimals > 0 && this.value !== 0n && this.value % 10n === 0n) {
36
- this.value /= 10n; // Shrink the number
37
- this.decimals--; // Shrink the scale
38
- }
39
- return this;
40
- }
41
- toSafeValue(val) {
42
- if (typeof val === "string") {
43
- return val.trim();
44
- }
45
- return `${val}`;
46
- }
47
- getNumberIFoForBigintDecimal(val) {
48
- const safeVal = this.toSafeValue(val);
49
- let isDot = false, value = 0n, decimals = 0, sign = 1n;
50
- for (let i = 0; i < safeVal.length; i++) {
51
- const code = safeVal.charCodeAt(i);
52
- if (code >= 48 && code <= 57) {
53
- value = (value * 10n) + BigInt(code - 48);
54
- if (isDot)
55
- decimals++;
56
- continue;
57
- }
58
- if (code === 46 && !isDot) {
59
- isDot = true;
60
- continue;
4
+ // ".js" is required for the ESM build: Node's ESM loader needs the file extension
5
+ const bigintDecimalBase_js_1 = require("./bigintDecimalBase.js");
6
+ /**
7
+ * BigintDecimal with the JS `Math` object's members as statics
8
+ * (except fround, f16round, clz32 and imul, which only make sense for JS floats and 32-bit integers).
9
+ * Functions take the same values as the constructor and return BigintDecimal,
10
+ * computed to `BigintDecimal.precision` decimal places.
11
+ * Where JS Math would return NaN or ±Infinity, they throw a RangeError.
12
+ */
13
+ class BigintDecimal extends bigintDecimalBase_js_1.BigintDecimalBase {
14
+ constructor(...args) {
15
+ super(...args);
16
+ }
17
+ // ---------------------------------------------------------------- constants
18
+ /** Euler's number, e ≈ 2.718 */
19
+ static get E() { return BigintDecimal.exp(1); }
20
+ /** Natural logarithm of 10 ≈ 2.303 */
21
+ static get LN10() { return BigintDecimal.compute((w) => BigintDecimal.ln10Fixed(w)); }
22
+ /** Natural logarithm of 2 ≈ 0.693 */
23
+ static get LN2() { return BigintDecimal.compute((w) => BigintDecimal.ln2Fixed(w)); }
24
+ /** Base-10 logarithm of e ≈ 0.434 */
25
+ static get LOG10E() { return BigintDecimal.compute((w) => BigintDecimal.one(2 * w) / BigintDecimal.ln10Fixed(w)); }
26
+ /** Base-2 logarithm of e ≈ 1.443 */
27
+ static get LOG2E() { return BigintDecimal.compute((w) => BigintDecimal.one(2 * w) / BigintDecimal.ln2Fixed(w)); }
28
+ /** Ratio of a circle's circumference to its diameter ≈ 3.14159 */
29
+ static get PI() { return BigintDecimal.compute((w) => BigintDecimal.piFixed(w)); }
30
+ /** Square root of 1/2 ≈ 0.707 */
31
+ static get SQRT1_2() { return BigintDecimal.sqrt("0.5"); }
32
+ /** Square root of 2 ≈ 1.414 */
33
+ static get SQRT2() { return BigintDecimal.sqrt(2); }
34
+ // ---------------------------------------------------------------- rounding & sign
35
+ /** Absolute value */
36
+ static abs(x) {
37
+ const p = BigintDecimal.parts(x);
38
+ return BigintDecimal.fromParts(BigintDecimal.absBig(p.v), p.d);
39
+ }
40
+ /** -1, 0 or 1, depending on the sign of x */
41
+ static sign(x) {
42
+ const v = BigintDecimal.parts(x).v;
43
+ return new BigintDecimal(v > 0n ? 1 : v < 0n ? -1 : 0);
44
+ }
45
+ /** Integer part of x (removes the fractional digits) */
46
+ static trunc(x) {
47
+ return new BigintDecimal(BigintDecimal.integerPart(BigintDecimal.parts(x)));
48
+ }
49
+ /** Largest integer less than or equal to x */
50
+ static floor(x) {
51
+ const p = BigintDecimal.parts(x);
52
+ return new BigintDecimal(BigintDecimal.floorDiv(p.v, BigintDecimal.pow10(p.d)));
53
+ }
54
+ /** Smallest integer greater than or equal to x */
55
+ static ceil(x) {
56
+ const p = BigintDecimal.parts(x);
57
+ return new BigintDecimal(-BigintDecimal.floorDiv(-p.v, BigintDecimal.pow10(p.d)));
58
+ }
59
+ /** Rounds to the nearest integer; halves go up (toward +Infinity), like Math.round */
60
+ static round(x) {
61
+ const p = BigintDecimal.parts(x);
62
+ const scale = BigintDecimal.pow10(p.d);
63
+ return new BigintDecimal(BigintDecimal.floorDiv(2n * p.v + scale, 2n * scale));
64
+ }
65
+ // ---------------------------------------------------------------- aggregates
66
+ /** Largest of the arguments (at least one is required) */
67
+ static max(...values) {
68
+ return BigintDecimal.pick(values, "max", (best, next) => next.gt(best));
69
+ }
70
+ /** Smallest of the arguments (at least one is required) */
71
+ static min(...values) {
72
+ return BigintDecimal.pick(values, "min", (best, next) => next.lt(best));
73
+ }
74
+ /** Exact sum of all values in an iterable */
75
+ static sumPrecise(values) {
76
+ let sum = new BigintDecimal(0);
77
+ for (const value of values)
78
+ sum = sum.plus(value);
79
+ return sum;
80
+ }
81
+ /** Square root of the sum of squares of the arguments */
82
+ static hypot(...values) {
83
+ let sum = new BigintDecimal(0);
84
+ for (const value of values)
85
+ sum = sum.plus(new BigintDecimal(value).times(value));
86
+ return BigintDecimal.sqrt(sum);
87
+ }
88
+ // ---------------------------------------------------------------- powers & roots
89
+ /** Square root. Argument must be >= 0. Always correctly rounded. */
90
+ static sqrt(x) {
91
+ const p = BigintDecimal.parts(x);
92
+ if (p.v < 0n)
93
+ throw new RangeError("sqrt: argument must be >= 0 (NaN)");
94
+ // Computed in decimal: r = floor(sqrt(x) * 10^P), then
95
+ // sqrt(x) >= r + 1/2 (in units of 10^-P) <=> floor(4x * 10^2P) >= (2r + 1)^2, exactly.
96
+ const P = BigintDecimal.precision;
97
+ const r = BigintDecimal.isqrt(BigintDecimal.floorScale(p.v, p.d, 2 * P));
98
+ const roundUp = BigintDecimal.floorScale(4n * p.v, p.d, 2 * P) >= (2n * r + 1n) ** 2n;
99
+ return BigintDecimal.fromParts(roundUp ? r + 1n : r, P);
100
+ }
101
+ /** Cube root. Always correctly rounded. */
102
+ static cbrt(x) {
103
+ const p = BigintDecimal.parts(x);
104
+ const v = BigintDecimal.absBig(p.v);
105
+ // Same as sqrt: r = floor(cbrt(|x|) * 10^P), rounded up when floor(8|x| * 10^3P) >= (2r + 1)^3
106
+ const P = BigintDecimal.precision;
107
+ const r = BigintDecimal.icbrt(BigintDecimal.floorScale(v, p.d, 3 * P));
108
+ const rounded = BigintDecimal.floorScale(8n * v, p.d, 3 * P) >= (2n * r + 1n) ** 3n ? r + 1n : r;
109
+ return BigintDecimal.fromParts(p.v < 0n ? -rounded : rounded, P);
110
+ }
111
+ /** base raised to the power of exponent. Integer powers are exact where the result stays reasonably sized. */
112
+ static pow(base, exponent) {
113
+ const x = BigintDecimal.parts(base), y = BigintDecimal.parts(exponent);
114
+ if (y.v === 0n)
115
+ return new BigintDecimal(1);
116
+ if (x.v === 0n) {
117
+ if (y.v > 0n)
118
+ return new BigintDecimal(0);
119
+ throw new RangeError("pow: 0 to a negative power is Infinity");
120
+ }
121
+ if (y.d === 0) {
122
+ // Integer exponent: exact power, unless the base's decimals would multiply into far more
123
+ // digits than the rounded result keeps (e.g. 1.0001^1e9); then e^(y * ln x) is much cheaper.
124
+ const n = BigintDecimal.absBig(y.v);
125
+ if (x.d === 0 || BigInt(x.d) * n <= BigInt(4 * BigintDecimal.precision + 100)) {
126
+ const v = x.v ** n;
127
+ const d = x.d * Number(n);
128
+ return y.v > 0n
129
+ ? BigintDecimal.roundDecimal(v, d)
130
+ : BigintDecimal.compute((w) => (BigintDecimal.pow10(d) << BigInt(w)) / v);
61
131
  }
62
- if (i === 0 && (code === 45 || code === 43)) {
63
- if (code === 45)
64
- sign = -1n;
65
- continue;
132
+ }
133
+ else if (x.v < 0n) {
134
+ throw new RangeError("pow: negative base with a non-integer exponent is NaN");
135
+ }
136
+ // x^y = e^(y * ln|x|). The result's integer bits need extra working precision,
137
+ // estimated from a cheap low-precision ln|x|.
138
+ const absX = { v: BigintDecimal.absBig(x.v), d: x.d };
139
+ const roughLnX = Number(BigintDecimal.lnFixed(absX.v, 0, absX.d, 64)) / 2 ** 64;
140
+ const magnitude = Math.max(0, Math.ceil(Number(new BigintDecimal(exponent).toString()) * roughLnX * Math.LOG2E)) + 1;
141
+ if (!Number.isFinite(magnitude))
142
+ throw new RangeError("pow: result is too large to represent");
143
+ const negative = x.v < 0n && (y.v & 1n) === 1n;
144
+ return BigintDecimal.compute((w) => {
145
+ // ln|x| is multiplied by y, so it needs y's integer bits as extra precision too
146
+ const ww = w + BigintDecimal.GUARD_BITS + magnitude + BigintDecimal.bitLength(BigintDecimal.integerPart(y));
147
+ const t = (BigintDecimal.toFixed(y, ww) * BigintDecimal.lnFixed(absX.v, 0, absX.d, ww)) >> BigInt(ww);
148
+ const r = BigintDecimal.expFixed(t, ww, w);
149
+ return negative ? -r : r;
150
+ });
151
+ }
152
+ // ---------------------------------------------------------------- exponentials & logarithms
153
+ /** e raised to the power of x */
154
+ static exp(x) {
155
+ const p = BigintDecimal.parts(x);
156
+ return BigintDecimal.compute((w) => BigintDecimal.expParts(p, w));
157
+ }
158
+ /** e^x - 1 */
159
+ static expm1(x) {
160
+ const p = BigintDecimal.parts(x);
161
+ return BigintDecimal.compute((w) => BigintDecimal.expParts(p, w) - BigintDecimal.one(w));
162
+ }
163
+ /** Natural logarithm (base e). Argument must be > 0. */
164
+ static log(x) {
165
+ return BigintDecimal.logBase(x, "log");
166
+ }
167
+ /** Base-10 logarithm. Argument must be > 0. */
168
+ static log10(x) {
169
+ return BigintDecimal.logBase(x, "log10", (w) => BigintDecimal.ln10Fixed(w));
170
+ }
171
+ /** Base-2 logarithm. Argument must be > 0. */
172
+ static log2(x) {
173
+ return BigintDecimal.logBase(x, "log2", (w) => BigintDecimal.ln2Fixed(w));
174
+ }
175
+ /** Natural logarithm of 1 + x. Argument must be > -1. */
176
+ static log1p(x) {
177
+ return BigintDecimal.logBase(new BigintDecimal(x).plus(1), "log1p");
178
+ }
179
+ // ---------------------------------------------------------------- trigonometry (radians)
180
+ /** Sine */
181
+ static sin(x) {
182
+ const p = BigintDecimal.parts(x);
183
+ return BigintDecimal.compute((w) => BigintDecimal.sinCosParts(p, w)[0]);
184
+ }
185
+ /** Cosine */
186
+ static cos(x) {
187
+ const p = BigintDecimal.parts(x);
188
+ return BigintDecimal.compute((w) => BigintDecimal.sinCosParts(p, w)[1]);
189
+ }
190
+ /** Tangent */
191
+ static tan(x) {
192
+ const p = BigintDecimal.parts(x);
193
+ return BigintDecimal.compute((w) => {
194
+ // Near the poles cos(x) is tiny and sin / cos multiplies its error by 1 / cos^2,
195
+ // so the working precision grows until cos has enough correct bits.
196
+ // cos is never exactly 0 for a decimal x (pi is irrational), so this ends.
197
+ let ww = w + BigintDecimal.GUARD_BITS;
198
+ while (true) {
199
+ const [sin, cos] = BigintDecimal.sinCosParts(p, ww);
200
+ const needed = w + 2 * (ww - BigintDecimal.bitLength(cos)) + BigintDecimal.GUARD_BITS;
201
+ if (cos !== 0n && ww >= needed)
202
+ return ((sin << BigInt(ww)) / cos) >> BigInt(ww - w);
203
+ ww = cos === 0n ? 2 * ww : needed;
66
204
  }
67
- // Scientific Notation Handle
68
- if (code === 101 || code === 69) {
69
- const exp = parseInt(safeVal.slice(i + 1), 10);
70
- if (isNaN(exp))
71
- throw new Error("Invalid exponent");
72
- decimals -= exp;
73
- break;
205
+ });
206
+ }
207
+ /** Arcsine. Argument must be in [-1, 1]. */
208
+ static asin(x) {
209
+ const p = BigintDecimal.parts(x);
210
+ return BigintDecimal.compute((w) => BigintDecimal.asinFixed(p, w));
211
+ }
212
+ /** Arccosine. Argument must be in [-1, 1]. */
213
+ static acos(x) {
214
+ const p = BigintDecimal.parts(x);
215
+ return BigintDecimal.compute((w) => (BigintDecimal.piFixed(w) >> 1n) - BigintDecimal.asinFixed(p, w));
216
+ }
217
+ /** Arctangent */
218
+ static atan(x) {
219
+ const p = BigintDecimal.parts(x);
220
+ return BigintDecimal.compute((w) => BigintDecimal.atanFixed(BigintDecimal.toFixed(p, w), w));
221
+ }
222
+ /** Angle between the positive x-axis and the point (x, y). Note the order: (y, x). */
223
+ static atan2(y, x) {
224
+ const yp = BigintDecimal.parts(y), xp = BigintDecimal.parts(x);
225
+ return BigintDecimal.compute((w) => {
226
+ const pi = BigintDecimal.piFixed(w);
227
+ if (xp.v === 0n)
228
+ return yp.v > 0n ? pi >> 1n : yp.v < 0n ? -(pi >> 1n) : 0n;
229
+ // y / x computed exactly from the parts
230
+ const ratio = ((yp.v * BigintDecimal.pow10(xp.d)) << BigInt(w)) / (xp.v * BigintDecimal.pow10(yp.d));
231
+ const a = BigintDecimal.atanFixed(ratio, w);
232
+ if (xp.v > 0n)
233
+ return a;
234
+ return yp.v >= 0n ? a + pi : a - pi;
235
+ });
236
+ }
237
+ // ---------------------------------------------------------------- hyperbolic
238
+ /** Hyperbolic sine */
239
+ static sinh(x) {
240
+ return BigintDecimal.expPair(x, (ePos, eNeg) => (ePos - eNeg) >> 1n);
241
+ }
242
+ /** Hyperbolic cosine */
243
+ static cosh(x) {
244
+ return BigintDecimal.expPair(x, (ePos, eNeg) => (ePos + eNeg) >> 1n);
245
+ }
246
+ /** Hyperbolic tangent */
247
+ static tanh(x) {
248
+ const p = BigintDecimal.parts(x);
249
+ return BigintDecimal.compute((w) => {
250
+ // tanh|x| = (1 - e^(-2|x|)) / (1 + e^(-2|x|)), which never builds huge numbers
251
+ const one = BigintDecimal.one(w);
252
+ const t = BigintDecimal.expParts({ v: -2n * BigintDecimal.absBig(p.v), d: p.d }, w);
253
+ const r = ((one - t) << BigInt(w)) / (one + t);
254
+ return p.v < 0n ? -r : r;
255
+ });
256
+ }
257
+ /** Hyperbolic arcsine */
258
+ static asinh(x) {
259
+ const value = new BigintDecimal(x);
260
+ // asinh(-x) = -asinh(x)
261
+ return BigintDecimal.lnPlusRoot(BigintDecimal.abs(value), 1, value.lt(0));
262
+ }
263
+ /** Hyperbolic arccosine. Argument must be >= 1. */
264
+ static acosh(x) {
265
+ const value = new BigintDecimal(x);
266
+ if (value.lt(1))
267
+ throw new RangeError("acosh: argument must be >= 1 (NaN)");
268
+ return BigintDecimal.lnPlusRoot(value, -1);
269
+ }
270
+ /** Hyperbolic arctangent. Argument must be in (-1, 1). */
271
+ static atanh(x) {
272
+ const value = new BigintDecimal(x);
273
+ if (value.gte(1) || value.lte(-1))
274
+ throw new RangeError("atanh: argument must be between -1 and 1 (exclusive)");
275
+ // (ln(1 + x) - ln(1 - x)) / 2, both arguments exact
276
+ const plus = BigintDecimal.parts(value.plus(1));
277
+ const minus = BigintDecimal.parts(new BigintDecimal(1).minus(value));
278
+ return BigintDecimal.compute((w) => (BigintDecimal.lnFixed(plus.v, 0, plus.d, w) - BigintDecimal.lnFixed(minus.v, 0, minus.d, w)) >> 1n);
279
+ }
280
+ // ---------------------------------------------------------------- random
281
+ /** Random number in [0, 1) with `BigintDecimal.precision` decimal digits */
282
+ static random() {
283
+ const p = BigintDecimal.precision;
284
+ const limit = BigintDecimal.pow10(p);
285
+ // 8 extra bytes make the modulo bias negligible
286
+ const bytes = new Uint8Array(Math.ceil(BigintDecimal.bitLength(limit) / 8) + 8);
287
+ if (typeof globalThis.crypto?.getRandomValues === "function") {
288
+ globalThis.crypto.getRandomValues(bytes);
289
+ }
290
+ else {
291
+ for (let i = 0; i < bytes.length; i++)
292
+ bytes[i] = Math.floor(Math.random() * 256);
293
+ }
294
+ let r = 0n;
295
+ for (const byte of bytes)
296
+ r = (r << 8n) | BigInt(byte);
297
+ return BigintDecimal.fromParts(r % limit, p);
298
+ }
299
+ // ---------------------------------------------------------------- cache
300
+ /**
301
+ * Frees the cached constants (pi, ln2, ln10, the log table) and powers of ten.
302
+ * They are kept at the highest precision used so far and rebuilt on demand, so this is only
303
+ * useful to give memory back after very high precision work. Results do not change.
304
+ */
305
+ static clearCache() {
306
+ BigintDecimal.constants.clear();
307
+ BigintDecimal.pow10Cache.length = 0;
308
+ }
309
+ // =========================================================================
310
+ // Private helpers.
311
+ // The algorithms work on binary fixed-point bigints: an integer meaning `value / 2^w`.
312
+ // A binary scale turns every rescaling into a cheap bit shift instead of a big division.
313
+ // `compute` runs them with GUARD_BITS extra bits, then rounds to `BigintDecimal.precision` decimals.
314
+ // Helpers are called through the class name, not `this`, so detached calls
315
+ // like `values.map(BigintDecimal.sqrt)` keep working, as they do with Math.
316
+ // =========================================================================
317
+ // Extra working bits (~12 decimal digits) that absorb rounding errors
318
+ static GUARD_BITS = 40;
319
+ // Measured crossovers (working scale in bits) where the asymptotically faster algorithm starts to win:
320
+ // atan by Newton's method instead of its series (~1500 digits)
321
+ static ATAN_NEWTON_BITS = 5000;
322
+ // series by rectangular splitting instead of term by term (~410 digits)
323
+ static RECTANGULAR_BITS = 1400;
324
+ // constants by binary splitting instead of small-integer series (~1200 digits)
325
+ static BINARY_SPLIT_BITS = 4000;
326
+ // Cached constants (pi, ln2, ln10 and the ln(1 + j/256) table) at the highest scale computed so far
327
+ static constants = new Map();
328
+ static POW10_CACHE_SIZE = 1024;
329
+ static pow10Cache = [];
330
+ // ---------------------------------------------------------------- conversion
331
+ static compute(fn) {
332
+ const w = Math.ceil(BigintDecimal.precision * Math.log2(10)) + BigintDecimal.GUARD_BITS;
333
+ const p = BigintDecimal.precision;
334
+ // fixed value / 2^w -> decimal digits, rounded half away from zero
335
+ const v = fn(w);
336
+ const rounded = ((BigintDecimal.absBig(v) * BigintDecimal.pow10(p)) + BigintDecimal.one(w - 1)) >> BigInt(w);
337
+ return BigintDecimal.fromParts(v < 0n ? -rounded : rounded, p);
338
+ }
339
+ // v * 10^-d -> BigintDecimal rounded half away from zero to the current precision
340
+ static roundDecimal(v, d) {
341
+ const p = BigintDecimal.precision;
342
+ if (d <= p)
343
+ return BigintDecimal.fromParts(v, d);
344
+ const unit = BigintDecimal.pow10(d - p);
345
+ const half = unit / 2n;
346
+ return BigintDecimal.fromParts(v >= 0n ? (v + half) / unit : (v - half) / unit, p);
347
+ }
348
+ static parts(x) {
349
+ const n = x instanceof BigintDecimal ? x : new BigintDecimal(x);
350
+ return { v: n.value, d: n.decimals };
351
+ }
352
+ // v * 10^-d -> BigintDecimal, without going through a string
353
+ static fromParts(v, d) {
354
+ const result = new BigintDecimal(v);
355
+ result.decimals = d;
356
+ return result.trim();
357
+ }
358
+ // v * 10^-d -> floor(v * 10^(to - d)) for v >= 0, i.e. the value as an integer count of 10^-to
359
+ static floorScale(v, d, to) {
360
+ return to >= d ? v * BigintDecimal.pow10(to - d) : v / BigintDecimal.pow10(d - to);
361
+ }
362
+ // Decimal parts -> binary fixed point at scale w (truncated toward zero)
363
+ static toFixed(x, w) {
364
+ const shifted = x.v << BigInt(w);
365
+ return x.d === 0 ? shifted : shifted / BigintDecimal.pow10(x.d);
366
+ }
367
+ // Integer part, truncated toward zero
368
+ static integerPart(x) {
369
+ return x.v / BigintDecimal.pow10(x.d);
370
+ }
371
+ // ---------------------------------------------------------------- bigint basics
372
+ // 1 at binary scale w, i.e. 2^w
373
+ static one(w) {
374
+ return 1n << BigInt(w);
375
+ }
376
+ // Moves a fixed value from binary scale `from` to scale `to`
377
+ static shift(v, from, to) {
378
+ return to >= from ? v << BigInt(to - from) : v >> BigInt(from - to);
379
+ }
380
+ // 10^n, cached for the small exponents every call uses (precision, decimals)
381
+ static pow10(n) {
382
+ if (n >= BigintDecimal.POW10_CACHE_SIZE)
383
+ return 10n ** BigInt(n);
384
+ let cached = BigintDecimal.pow10Cache[n];
385
+ if (cached === undefined) {
386
+ cached = 10n ** BigInt(n);
387
+ BigintDecimal.pow10Cache[n] = cached;
388
+ }
389
+ return cached;
390
+ }
391
+ static absBig(n) {
392
+ return n < 0n ? -n : n;
393
+ }
394
+ static bitLength(n) {
395
+ if (n === 0n)
396
+ return 0;
397
+ const hex = BigintDecimal.absBig(n).toString(16);
398
+ // 4 bits per hex digit, minus the unused high bits of the first digit
399
+ return hex.length * 4 - (Math.clz32(parseInt(hex.charAt(0), 16)) - 28);
400
+ }
401
+ static floorDiv(a, b) {
402
+ const q = a / b;
403
+ return a % b !== 0n && (a < 0n) !== (b < 0n) ? q - 1n : q;
404
+ }
405
+ // floor(sqrt(n)), Newton's method.
406
+ // Starts from a float estimate of the top bits (already ~50 bits correct, and never below the root),
407
+ // so only one or two Newton steps are needed.
408
+ static isqrt(n) {
409
+ if (n < 2n)
410
+ return n;
411
+ const s = Math.max(0, BigintDecimal.bitLength(n) - 100) & ~1; // even, so the root shifts by s / 2
412
+ let x = (BigInt(Math.ceil(Math.sqrt(Number(n >> BigInt(s))))) + 1n) << BigInt(s >> 1);
413
+ while (true) {
414
+ const y = (x + n / x) >> 1n;
415
+ if (y >= x)
416
+ return x;
417
+ x = y;
418
+ }
419
+ }
420
+ // floor(cbrt(n)), Newton's method, seeded like isqrt
421
+ static icbrt(n) {
422
+ if (n < 2n)
423
+ return n;
424
+ const s = Math.floor(Math.max(0, BigintDecimal.bitLength(n) - 150) / 3) * 3; // multiple of 3
425
+ let x = (BigInt(Math.ceil(Math.cbrt(Number(n >> BigInt(s))))) + 1n) << BigInt(s / 3);
426
+ while (true) {
427
+ const y = (2n * x + n / (x * x)) / 3n;
428
+ if (y >= x)
429
+ return x;
430
+ x = y;
431
+ }
432
+ }
433
+ // ---------------------------------------------------------------- shared by public functions
434
+ static pick(values, name, isBetter) {
435
+ const [first, ...rest] = values;
436
+ if (first === undefined)
437
+ throw new RangeError(`${name}: needs at least one argument`);
438
+ let best = new BigintDecimal(first);
439
+ for (const value of rest) {
440
+ const next = new BigintDecimal(value);
441
+ if (isBetter(best, next))
442
+ best = next;
443
+ }
444
+ return best;
445
+ }
446
+ // ln(x), or ln(x) / ln(base) when `lnBase` is given
447
+ static logBase(x, name, lnBase) {
448
+ const p = BigintDecimal.parts(x);
449
+ if (p.v <= 0n)
450
+ throw new RangeError(`${name}: argument is out of range`);
451
+ return BigintDecimal.compute((w) => {
452
+ const ln = BigintDecimal.lnFixed(p.v, 0, p.d, w);
453
+ return lnBase ? (ln << BigInt(w)) / lnBase(w) : ln;
454
+ });
455
+ }
456
+ // ±ln(x + sqrt(x^2 + c)), x >= 0: asinh (c = 1) and acosh (c = -1)
457
+ static lnPlusRoot(x, c, negate = false) {
458
+ const xp = BigintDecimal.parts(x);
459
+ const square = BigintDecimal.parts(x.times(x).plus(c));
460
+ return BigintDecimal.compute((w) => {
461
+ const sum = BigintDecimal.toFixed(xp, w) + BigintDecimal.isqrt(BigintDecimal.toFixed(square, 2 * w));
462
+ const r = BigintDecimal.lnFixed(sum, w, 0, w);
463
+ return negate ? -r : r;
464
+ });
465
+ }
466
+ // Combines e^x and e^-x: sinh and cosh
467
+ static expPair(x, combine) {
468
+ const p = BigintDecimal.parts(x);
469
+ return BigintDecimal.compute((w) => combine(BigintDecimal.expParts(p, w), BigintDecimal.expParts({ v: -p.v, d: p.d }, w)));
470
+ }
471
+ // ---------------------------------------------------------------- fixed-point algorithms
472
+ static constant(name, w, compute) {
473
+ let cached = BigintDecimal.constants.get(name);
474
+ if (!cached || w > cached.scale) {
475
+ const scale = w + BigintDecimal.GUARD_BITS;
476
+ cached = { scale, value: compute(scale) };
477
+ BigintDecimal.constants.set(name, cached);
478
+ }
479
+ return cached.value >> BigInt(cached.scale - w);
480
+ }
481
+ // pi at scale w. Low precision: Machin's formula, pi = 16 atan(1/5) - 4 atan(1/239).
482
+ // High precision: the Chudnovsky series (~47 bits per term) by binary splitting:
483
+ // pi = 426880 sqrt(10005) / Σ (-1)^k (6k)! (13591409 + 545140134 k) / ((3k)! (k!)^3 640320^(3k))
484
+ static piFixed(w) {
485
+ return BigintDecimal.constant("pi", w, (s) => {
486
+ if (s < BigintDecimal.BINARY_SPLIT_BITS) {
487
+ return 4n * (4n * BigintDecimal.atanRatio(1n, 5n, s) - BigintDecimal.atanRatio(1n, 239n, s));
74
488
  }
75
- throw new Error(`Unexpected character: ${String.fromCharCode(code)}`);
76
- }
77
- // Handle negative decimals (large integers)
78
- if (decimals < 0) {
79
- value = value * (10n ** BigInt(-decimals));
80
- decimals = 0;
81
- }
82
- ;
83
- return { value: value * sign, decimals };
84
- }
85
- toString() {
86
- // 1. Handle Integer case (Fastest exit, Zero Allocation overhead)
87
- if (this.decimals === 0)
88
- return this.value.toString();
89
- // 2. Separate Sign and Magnitude
90
- // Check sign using BigInt math (fastest)
91
- const isNegative = this.value < 0n;
92
- // Get the string of digits ONLY.
93
- // isNegative ? -this.value : this.value -> creates a temporary BigInt
94
- // .toString() -> creates the string of digits "123"
95
- // This is cheaper than creating "-123" and slicing it.
96
- const s = (isNegative ? -this.value : this.value).toString();
97
- const len = s.length;
98
- // 3. Logic for insertion vs padding
99
- if (len > this.decimals) {
100
- // Case A: 12345 (2 dec) -> 123.45
101
- // splitIndex is purely digits before the dot
102
- const splitIndex = len - this.decimals;
103
- // Build the absolute decimal string
104
- const result = s.substring(0, splitIndex) + "." + s.substring(splitIndex);
105
- // Add sign if needed
106
- return isNegative ? "-" + result : result;
107
- }
108
- // Case B: 5 (2 dec) -> 0.05
109
- // Calculate zeros needed: 2 decimals - length 1 = 1 zero
110
- const zerosNeeded = this.decimals - len;
111
- // Build the result directly
112
- // "0." + "0" + "5"
113
- return (isNegative ? "-0." : "0.") + "0".repeat(zerosNeeded) + s;
114
- }
115
- toJSON() {
116
- return this.toString();
117
- }
118
- [Symbol.for('nodejs.util.inspect.custom')]() {
119
- return this.toString();
120
- }
121
- isBigintDecimal(val) {
122
- const s = this.toSafeValue(val);
123
- if (s.length === 0)
124
- return false;
125
- let dot = false, e = false;
126
- for (let i = 0; i < s.length; i++) {
127
- const c = s.charCodeAt(i);
128
- if (c >= 48 && c <= 57)
129
- continue; // 0-9
130
- if (c === 46 && !dot && !e) {
131
- dot = true;
132
- continue;
133
- } // .
134
- if (i === 0 && (c === 45 || c === 43))
135
- continue; // +/- at start
136
- if ((c === 101 || c === 69) && !e) { // e/E
137
- e = true;
138
- const next = s.charCodeAt(i + 1);
139
- if (next === 45 || next === 43)
140
- i++; // Skip sign after 'e'
141
- continue;
489
+ const C3 = 10939058860032000n; // 640320^3 / 24
490
+ const [, Q, T] = BigintDecimal.binarySplit(0, Math.ceil(s / 47.11) + 2, (k) => 13591409n + 545140134n * k, (k) => -(6n * k - 5n) * (2n * k - 1n) * (6n * k - 1n), (k) => k * k * k * C3);
491
+ return (426880n * BigintDecimal.isqrt(10005n << BigInt(2 * s)) * Q) / T;
492
+ });
493
+ }
494
+ // ln(2) = 2 atanh(1/3)
495
+ static ln2Fixed(w) {
496
+ return BigintDecimal.constant("ln2", w, (s) => 2n * BigintDecimal.atanhRatio(1n, 3n, s));
497
+ }
498
+ // ln(10) = 3 ln(2) + ln(1.25), ln(1.25) = 2 atanh(1/9)
499
+ static ln10Fixed(w) {
500
+ return BigintDecimal.constant("ln10", w, (s) => 3n * BigintDecimal.ln2Fixed(s) + 2n * BigintDecimal.atanhRatio(1n, 9n, s));
501
+ }
502
+ // atanh(j/c) at scale w, for small integers 0 < j < c.
503
+ // High precision: Euler's form atanh(y) = y / (1 - y^2) Σ (2k)!! / (2k + 1)!! (-y^2 / (1 - y^2))^k
504
+ // has small-integer term ratios, so it can be summed by binary splitting.
505
+ static atanhRatio(j, c, w) {
506
+ if (w < BigintDecimal.BINARY_SPLIT_BITS)
507
+ return BigintDecimal.atanRatio(j, c, w, false);
508
+ const j2 = j * j, d = c * c - j2;
509
+ const terms = Math.ceil(w / Math.log2(Number(d) / Number(j2))) + 2;
510
+ const [, Q, T] = BigintDecimal.binarySplit(0, terms, () => 1n, (k) => -2n * k * j2, (k) => (2n * k + 1n) * d);
511
+ return (((j * c) << BigInt(w)) * T) / (d * Q);
512
+ }
513
+ // Σ_{k=lo}^{hi-1} a(k) Π_{t=lo+1..k} p(t)/q(t) as [P, Q, T] with the sum = T / Q (binary splitting).
514
+ // Halving the range recursively turns the work into a few large, balanced multiplications,
515
+ // where V8's fast multiplication algorithms do best.
516
+ static binarySplit(lo, hi, a, p, q) {
517
+ if (hi - lo === 1) {
518
+ const k = BigInt(lo);
519
+ const P = lo === 0 ? 1n : p(k), Q = lo === 0 ? 1n : q(k);
520
+ return [P, Q, a(k) * P];
521
+ }
522
+ const mid = (lo + hi) >> 1;
523
+ const [P1, Q1, T1] = BigintDecimal.binarySplit(lo, mid, a, p, q);
524
+ const [P2, Q2, T2] = BigintDecimal.binarySplit(mid, hi, a, p, q);
525
+ return [P1 * P2, Q1 * Q2, T1 * Q2 + P1 * T2];
526
+ }
527
+ // Σ_{k>=0} x^k Π_{t=1..k} p(t)/q(t) at scale w, for x fixed at scale w (|x| < 1, |p(t)| <= q(t)),
528
+ // by rectangular splitting (Paterson–Stockmeyer): with m ≈ sqrt(N) powers x^1..x^m, each block of
529
+ // m terms costs one full multiplication, and everything else multiplies or divides by small integers.
530
+ // Used from RECTANGULAR_BITS up; below that the callers' direct term-by-term loops are faster.
531
+ static series(x, w, p, q) {
532
+ const W = BigInt(w), one = 1n << W;
533
+ if (x === 0n)
534
+ return one;
535
+ // Terms needed: until |x|^N Π p/q < 2^-(w + 8)
536
+ const log2x = BigintDecimal.bitLength(x) - w;
537
+ let terms = 0;
538
+ for (let size = 0; size > -(w + 8);) {
539
+ terms++;
540
+ const t = BigInt(terms);
541
+ size += log2x + Math.log2(Math.abs(Number(p(t))) / Number(q(t)));
542
+ }
543
+ const m = Math.ceil(Math.sqrt(terms));
544
+ // x^(m-1) .. x^0, highest first, and x^m
545
+ const descendingPowers = [one];
546
+ let xm = one;
547
+ for (let i = 1; i <= m; i++) {
548
+ xm = (xm * x) >> W;
549
+ if (i < m)
550
+ descendingPowers.unshift(xm);
551
+ }
552
+ // Blocks from the last one down, Horner-style in x^m. For a block starting at term b:
553
+ // sum_b = (Σ_i x^i num_i den_i + x^m sum_{b+m} num_m / q(b+m)) / den_0
554
+ // with num_i = Π_{t=b+1..b+i} p(t) and den_i = Π_{t=b+i+1..b+m-1} q(t), both built while i goes down.
555
+ let sum = 0n;
556
+ for (let b = (Math.ceil(terms / m) - 1) * m; b >= 0; b -= m) {
557
+ const base = BigInt(b);
558
+ let num = 1n;
559
+ for (let t = 1; t <= m; t++)
560
+ num *= p(base + BigInt(t));
561
+ let block = sum === 0n ? 0n : (((xm * sum) >> W) * num) / q(base + BigInt(m));
562
+ let den = 1n, i = m;
563
+ for (const power of descendingPowers) {
564
+ i--;
565
+ num /= p(base + BigInt(i + 1)); // exact: num was a product including this factor
566
+ if (i < m - 1)
567
+ den *= q(base + BigInt(i + 1));
568
+ block += power * num * den;
142
569
  }
143
- return false;
144
- }
145
- return true;
146
- }
147
- plus(val) {
148
- const plusValue = new BigintDecimal(val);
149
- // 1. Determine which number has more decimals
150
- const d1 = this.decimals;
151
- const d2 = plusValue.decimals;
152
- const newDecimal = d1 > d2 ? d1 : d2;
153
- // 2. Align values (Common Denominator)
154
- // If 'this' has fewer decimals, scale it up.
155
- const v1 = d1 < newDecimal ? this.value * (10n ** BigInt(newDecimal - d1)) : this.value;
156
- // If 'plusValue' has fewer decimals, scale it up.
157
- const v2 = d2 < newDecimal ? plusValue.value * (10n ** BigInt(newDecimal - d2)) : plusValue.value;
158
- // 3. Now add and return
159
- const result = new BigintDecimal("0");
160
- result.value = v1 + v2;
161
- result.decimals = newDecimal;
162
- return result.trim();
570
+ sum = block / den;
571
+ }
572
+ return sum;
163
573
  }
164
- minus(val) {
165
- const other = new BigintDecimal(val);
166
- const d1 = this.decimals;
167
- const d2 = other.decimals;
168
- const newDecimal = d1 > d2 ? d1 : d2;
169
- // Scale values to the same precision
170
- const v1 = d1 < newDecimal ? this.value * (10n ** BigInt(newDecimal - d1)) : this.value;
171
- const v2 = d2 < newDecimal ? other.value * (10n ** BigInt(newDecimal - d2)) : other.value;
172
- const result = new BigintDecimal("0"); // Fastest instantiation
173
- result.value = v1 - v2;
174
- result.decimals = newDecimal;
175
- return result.trim();
574
+ // Halvings of the argument before a Taylor series (each costs one squaring or double-angle step afterwards).
575
+ // Term-by-term summation favours more halvings (~sqrt(w)/2); rectangular splitting fewer (~1.5 cbrt(w)).
576
+ static halvings(w) {
577
+ return w < BigintDecimal.RECTANGULAR_BITS ? Math.ceil(Math.sqrt(w) / 2) : Math.round(1.5 * Math.cbrt(w));
176
578
  }
177
- times(val) {
178
- const other = new BigintDecimal(val);
179
- const result = new BigintDecimal("0");
180
- // Multiplication: (A * 10^d1) * (B * 10^d2) = (A * B) * 10^(d1 + d2)
181
- result.value = this.value * other.value;
182
- result.decimals = this.decimals + other.decimals;
183
- return result.trim();
579
+ // atan(p/q), or atanh(p/q) when `alternating` is false, at scale w, for small integers p < q.
580
+ // Every step multiplies and divides by small integers, which is much cheaper than a full multiplication.
581
+ static atanRatio(p, q, w, alternating = true) {
582
+ const p2 = p * p, q2 = q * q;
583
+ let term = (p << BigInt(w)) / q, sum = term, negative = alternating;
584
+ for (let k = 3n; term !== 0n; k += 2n) {
585
+ term = (term * p2) / q2;
586
+ sum = negative ? sum - term / k : sum + term / k;
587
+ negative = alternating && !negative;
588
+ }
589
+ return sum;
184
590
  }
185
- round(toDecimals) {
186
- const result = new BigintDecimal("0");
187
- const diff = this.decimals - toDecimals;
188
- if (diff <= 0)
189
- return this; // Already more precise than requested
190
- const power = 10n ** BigInt(diff);
191
- const half = power / 2n;
192
- // Standard rounding: add half of the divisor before dividing
193
- // This turns 0.999... into 1.0
194
- const roundedValue = (this.value >= 0n) ? (this.value + half) / power : (this.value - half) / power;
195
- result.value = roundedValue;
196
- result.decimals = toDecimals;
197
- return result.trim();
591
+ // ln(m) for m (fixed at scale w) in [1, 2], using ln(m) = 2 atanh(y), y = (m - 1) / (m + 1)
592
+ static lnNear1(m, w) {
593
+ const W = BigInt(w), one = BigintDecimal.one(w);
594
+ const y = ((m - one) << W) / (m + one);
595
+ const y2 = (y * y) >> W;
596
+ if (w >= BigintDecimal.RECTANGULAR_BITS) {
597
+ // Euler's form: atanh(y) = y / (1 - y^2) Σ (2k)!! / (2k + 1)!! (-y^2 / (1 - y^2))^k
598
+ const oneMinusY2 = one - y2;
599
+ const sum = BigintDecimal.series(-(y2 << W) / oneMinusY2, w, (t) => 2n * t, (t) => 2n * t + 1n);
600
+ return 2n * ((((y << W) / oneMinusY2) * sum) >> W);
601
+ }
602
+ let term = y, sum = y;
603
+ for (let k = 3n; term !== 0n; k += 2n) {
604
+ term = (term * y2) >> W;
605
+ sum += term / k;
606
+ }
607
+ return 2n * sum;
198
608
  }
199
- div(val) {
200
- const other = val instanceof BigintDecimal ? val : new BigintDecimal(val);
201
- if (other.value === 0n)
202
- throw new Error("Division by zero");
203
- let v1 = this.value;
204
- const v2 = other.value;
205
- // 1. Scale up once to your "Max Allowed" precision
206
- const shift = this.precision + other.decimals - this.decimals;
207
- if (shift > 0)
208
- v1 *= 10n ** BigInt(shift);
209
- else if (shift < 0)
210
- v1 /= 10n ** BigInt(-shift);
211
- const result = new BigintDecimal("0");
212
- result.value = v1 / v2;
213
- result.decimals = this.precision;
214
- // 2. Immediately trim it!
215
- // This is where 0.500000... becomes 0.5 automatically.
216
- return result.trim();
609
+ // ln(v * 2^-binaryExp * 10^-decimalExp) at scale w, for v > 0.
610
+ // Uses v = m * 2^k with m in [1, 2), so ln = ln(m) + (k - binaryExp) ln2 - decimalExp ln10.
611
+ // m is then split as (1 + j/256) * m' using its top 8 bits j. ln(1 + j/256) = 2 atanh(j / (512 + j)) comes
612
+ // from a table, computed once per j and precision, and m' < 1 + 2^-8 makes the remaining series short.
613
+ static lnFixed(v, binaryExp, decimalExp, w) {
614
+ const k = BigintDecimal.bitLength(v) - 1;
615
+ const powerOf2 = k - binaryExp;
616
+ // the constants are multiplied by these exponents, so they need their bits as extra precision
617
+ const ww = w + BigintDecimal.bitLength(BigInt(Math.abs(powerOf2) + decimalExp)) + 8;
618
+ const m = BigintDecimal.shift(v, k, ww);
619
+ const j = (m >> BigInt(ww - 8)) - 256n;
620
+ let r = BigInt(powerOf2) * BigintDecimal.ln2Fixed(ww) - BigInt(decimalExp) * BigintDecimal.ln10Fixed(ww);
621
+ if (j === 0n) {
622
+ r += BigintDecimal.lnNear1(m, ww);
623
+ }
624
+ else {
625
+ r += BigintDecimal.lnNear1((m << 8n) / (256n + j), ww)
626
+ + BigintDecimal.constant(`ln(1+${j}/256)`, ww, (s) => 2n * BigintDecimal.atanhRatio(j, 512n + j, s));
627
+ }
628
+ return r >> BigInt(ww - w);
217
629
  }
218
- compare(val) {
219
- const other = val instanceof BigintDecimal ? val : new BigintDecimal(val);
220
- const maxD = Math.max(this.decimals, other.decimals);
221
- const v1 = this.decimals < maxD ? this.value * (10n ** BigInt(maxD - this.decimals)) : this.value;
222
- const v2 = other.decimals < maxD ? other.value * (10n ** BigInt(maxD - other.decimals)) : other.value;
223
- return v1 > v2 ? 1 : v1 < v2 ? -1 : 0;
630
+ // e^x for exact decimal parts, at scale w
631
+ static expParts(x, w) {
632
+ // The result has about integerPart * log2(e) integer bits; x needs that much extra precision.
633
+ const integerPart = BigintDecimal.integerPart(x);
634
+ const magnitude = Math.max(0, Math.ceil(Number(integerPart) * Math.LOG2E));
635
+ if (!Number.isFinite(magnitude))
636
+ throw new RangeError("exp: result is too large to represent");
637
+ const xw = w + magnitude + BigintDecimal.GUARD_BITS + BigintDecimal.bitLength(integerPart);
638
+ return BigintDecimal.expFixed(BigintDecimal.toFixed(x, xw), xw, w);
224
639
  }
225
- gt(val) {
226
- return this.compare(val) === 1;
640
+ // e^(x / 2^xw) at scale w.
641
+ // e^x = 2^n * e^r with r = x - n * ln2, |r| <= 0.35. Multiplying by 2^n is a shift.
642
+ // e^r: the argument is halved k times, summed as a Taylor series, then squared k times.
643
+ static expFixed(x, xw, w) {
644
+ // n only has to be close to x / ln2, so a low-precision estimate is enough
645
+ const roughScale = BigintDecimal.bitLength(x >> BigInt(xw)) + 64;
646
+ const roughX = BigintDecimal.shift(x, xw, roughScale);
647
+ const roughLn2 = BigintDecimal.ln2Fixed(roughScale);
648
+ const n = BigintDecimal.floorDiv(2n * roughX + roughLn2, 2n * roughLn2);
649
+ // e^x < 2^-(w + 1): rounds to zero
650
+ if (n < -BigInt(w + 2))
651
+ return 0n;
652
+ const integerBits = Math.max(0, Number(n));
653
+ const k = BigintDecimal.halvings(w + integerBits);
654
+ // squaring k times doubles the error k times; the result's integer bits need precision too
655
+ const ww = w + integerBits + k + BigintDecimal.GUARD_BITS;
656
+ const nBits = BigintDecimal.bitLength(n);
657
+ const r = (BigintDecimal.shift(x, xw, ww + nBits) - n * BigintDecimal.ln2Fixed(ww + nBits)) >> BigInt(nBits + k);
658
+ // e^r = Σ r^t / t!
659
+ const WW = BigInt(ww);
660
+ let sum;
661
+ if (ww >= BigintDecimal.RECTANGULAR_BITS) {
662
+ sum = BigintDecimal.series(r, ww, () => 1n, (t) => t);
663
+ }
664
+ else {
665
+ let term = BigintDecimal.one(ww);
666
+ sum = term;
667
+ for (let t = 1n; term !== 0n; t++) {
668
+ term = ((term * r) >> WW) / t;
669
+ sum += term;
670
+ }
671
+ }
672
+ for (let i = 0; i < k; i++)
673
+ sum = (sum * sum) >> WW;
674
+ return sum >> BigInt(ww - w - Number(n));
675
+ }
676
+ // [sin(x), cos(x)] for exact decimal parts, at scale w
677
+ static sinCosParts(x, w) {
678
+ // Large arguments need pi with as many extra bits as the integer part has.
679
+ const base = w + BigintDecimal.GUARD_BITS + BigintDecimal.bitLength(BigintDecimal.integerPart(x));
680
+ const ww = base + BigintDecimal.sinCosLoss(base);
681
+ const [s, c] = BigintDecimal.sinCosFixed(BigintDecimal.toFixed(x, ww), ww);
682
+ return [s >> BigInt(ww - w), c >> BigInt(ww - w)];
683
+ }
684
+ // Bits of precision sinCosFixed loses at scale w (the argument halvings), which callers add as guard bits
685
+ static sinCosLoss(w) {
686
+ return BigintDecimal.halvings(w) + 4;
227
687
  }
228
- lt(val) {
229
- return this.compare(val) === -1;
688
+ // [sin(x), cos(x)] for x fixed at scale w.
689
+ // x = q * (pi / 2) + r with |r| <= pi / 4; r is halved k times, both Taylor series are summed,
690
+ // then the double-angle formulas are applied k times.
691
+ static sinCosFixed(x, w) {
692
+ const halfPi = BigintDecimal.piFixed(w) >> 1n;
693
+ const q = BigintDecimal.floorDiv(2n * x + halfPi, 2n * halfPi);
694
+ const k = BigintDecimal.halvings(w);
695
+ const r = (x - q * halfPi) >> BigInt(k);
696
+ const W = BigInt(w);
697
+ const minusR2 = -((r * r) >> W);
698
+ // sin r = r Σ (-r^2)^t / (2t + 1)!, cos r = Σ (-r^2)^t / (2t)!
699
+ let sin, cos;
700
+ if (w >= BigintDecimal.RECTANGULAR_BITS) {
701
+ sin = (r * BigintDecimal.series(minusR2, w, () => 1n, (t) => 2n * t * (2n * t + 1n))) >> W;
702
+ cos = BigintDecimal.series(minusR2, w, () => 1n, (t) => (2n * t - 1n) * 2n * t);
703
+ }
704
+ else {
705
+ let term = r;
706
+ sin = r;
707
+ for (let n = 2n; term !== 0n; n += 2n) {
708
+ term = ((term * minusR2) >> W) / (n * (n + 1n));
709
+ sin += term;
710
+ }
711
+ term = BigintDecimal.one(w);
712
+ cos = term;
713
+ for (let n = 1n; term !== 0n; n += 2n) {
714
+ term = ((term * minusR2) >> W) / (n * (n + 1n));
715
+ cos += term;
716
+ }
717
+ }
718
+ // sin(2a) = 2 sin(a) cos(a), cos(2a) = cos(a)^2 - sin(a)^2
719
+ for (let i = 0; i < k; i++) {
720
+ [sin, cos] = [(2n * sin * cos) >> W, (cos * cos - sin * sin) >> W];
721
+ }
722
+ const quadrant = Number(((q % 4n) + 4n) % 4n);
723
+ return quadrant === 0 ? [sin, cos] :
724
+ quadrant === 1 ? [cos, -sin] :
725
+ quadrant === 2 ? [-sin, -cos] :
726
+ [-cos, sin];
230
727
  }
231
- gte(val) {
232
- return this.compare(val) >= 0;
728
+ // atan(x) for x fixed at scale w, result at scale w
729
+ static atanFixed(x, w) {
730
+ if (x < 0n)
731
+ return -BigintDecimal.atanFixed(-x, w);
732
+ const one = BigintDecimal.one(w);
733
+ if (x > one)
734
+ return (BigintDecimal.piFixed(w) >> 1n) - BigintDecimal.atanFixed(BigintDecimal.one(2 * w) / x, w);
735
+ if (w > BigintDecimal.ATAN_NEWTON_BITS)
736
+ return BigintDecimal.atanNewton(x, w);
737
+ // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2))), until x < 1/8
738
+ let halvings = 0n;
739
+ while (x << 3n > one) {
740
+ x = (x << BigInt(w)) / (one + BigintDecimal.isqrt(BigintDecimal.one(2 * w) + x * x));
741
+ halvings++;
742
+ }
743
+ const W = BigInt(w);
744
+ const x2 = (x * x) >> W;
745
+ if (w >= BigintDecimal.RECTANGULAR_BITS) {
746
+ // Euler's form: atan(x) = x / (1 + x^2) Σ (2k)!! / (2k + 1)!! (x^2 / (1 + x^2))^k
747
+ const sum = BigintDecimal.series((x2 << W) / (one + x2), w, (t) => 2n * t, (t) => 2n * t + 1n);
748
+ return ((((x << W) / (one + x2)) * sum) >> W) << halvings;
749
+ }
750
+ let sum = x, term = x;
751
+ for (let k = 3n; term !== 0n; k += 2n) {
752
+ term = -((term * x2) >> W);
753
+ sum += term / k;
754
+ }
755
+ return sum << halvings;
233
756
  }
234
- lte(val) {
235
- return this.compare(val) <= 0;
757
+ // atan(x) for x in [0, 1] fixed at scale w, by Newton's method on tan(y) = x:
758
+ // y += (x cos y - sin y) / (cos y + x sin y). Each step doubles the correct bits,
759
+ // so it starts from Math.atan and works at twice the precision every step.
760
+ static atanNewton(x, w) {
761
+ let scale = 53;
762
+ let y = BigInt(Math.round(Math.atan(Number(BigintDecimal.shift(x, w, 53)) / 2 ** 53) * 2 ** 53));
763
+ let correctBits = 50;
764
+ const target = w + 8;
765
+ while (correctBits < target) {
766
+ correctBits = Math.min(2 * correctBits, target);
767
+ const s = correctBits + BigintDecimal.sinCosLoss(correctBits) + 16;
768
+ y = BigintDecimal.shift(y, scale, s);
769
+ scale = s;
770
+ const xs = BigintDecimal.shift(x, w, s);
771
+ const [sin, cos] = BigintDecimal.sinCosFixed(y, s);
772
+ const numerator = ((xs * cos) >> BigInt(s)) - sin;
773
+ const denominator = cos + ((xs * sin) >> BigInt(s));
774
+ y += (numerator << BigInt(s)) / denominator;
775
+ }
776
+ return BigintDecimal.shift(y, scale, w);
236
777
  }
237
- eq(val) {
238
- return this.compare(val) === 0;
778
+ // asin(x) at scale w, |x| <= 1
779
+ static asinFixed(x, w) {
780
+ // 1 - x^2 computed exactly from the decimal parts: near x = ±1 it is tiny, and rounding x first
781
+ // would lose it. asin(x) = atan(x / sqrt(1 - x^2)).
782
+ const oneMinusSquare = BigintDecimal.pow10(2 * x.d) - x.v * x.v;
783
+ if (oneMinusSquare < 0n)
784
+ throw new RangeError("asin/acos: argument must be between -1 and 1 (NaN)");
785
+ const c = BigintDecimal.isqrt(BigintDecimal.toFixed({ v: oneMinusSquare, d: 2 * x.d }, 2 * w));
786
+ if (c === 0n)
787
+ return x.v > 0n ? BigintDecimal.piFixed(w) >> 1n : -(BigintDecimal.piFixed(w) >> 1n);
788
+ return BigintDecimal.atanFixed((BigintDecimal.toFixed(x, w) << BigInt(w)) / c, w);
239
789
  }
240
790
  }
241
791
  exports.BigintDecimal = BigintDecimal;
242
792
  exports.default = BigintDecimal;
243
- ;
244
793
  //# sourceMappingURL=index.js.map