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