@danielsimonjr/mathts-core 0.3.1 → 0.4.0
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/dist/chunk-JB4VPWK4.js +6349 -0
- package/dist/index-qMNYDTSO.d.ts +440 -0
- package/dist/index.d.ts +212 -186
- package/dist/index.js +138 -2741
- package/dist/internal.d.ts +510 -0
- package/dist/internal.js +188 -0
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -1,557 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Conversion Methods
|
|
70
|
-
// ============================================================
|
|
71
|
-
valueOf() {
|
|
72
|
-
return this.abs();
|
|
73
|
-
}
|
|
74
|
-
toString() {
|
|
75
|
-
if (this.im === 0) return `${this.re}`;
|
|
76
|
-
if (this.re === 0) {
|
|
77
|
-
if (this.im === 1) return "i";
|
|
78
|
-
if (this.im === -1) return "-i";
|
|
79
|
-
return `${this.im}i`;
|
|
80
|
-
}
|
|
81
|
-
const sign = this.im >= 0 ? " + " : " - ";
|
|
82
|
-
const absIm = Math.abs(this.im);
|
|
83
|
-
const imStr = absIm === 1 ? "i" : `${absIm}i`;
|
|
84
|
-
return `${this.re}${sign}${imStr}`;
|
|
85
|
-
}
|
|
86
|
-
toJSON() {
|
|
87
|
-
return { mathjs: "Complex", re: this.re, im: this.im };
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Return polar representation
|
|
91
|
-
*/
|
|
92
|
-
toPolar() {
|
|
93
|
-
return { r: this.abs(), phi: this.arg() };
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Format with options (precision, notation, etc.)
|
|
97
|
-
*/
|
|
98
|
-
format(options) {
|
|
99
|
-
const formatNum = (n) => {
|
|
100
|
-
if (!options) return String(n);
|
|
101
|
-
if (options.precision !== void 0) {
|
|
102
|
-
if (options.notation === "exponential") {
|
|
103
|
-
return n.toExponential(options.precision);
|
|
104
|
-
}
|
|
105
|
-
if (options.notation === "fixed") {
|
|
106
|
-
return n.toFixed(options.precision);
|
|
107
|
-
}
|
|
108
|
-
return Number(n.toPrecision(options.precision)).toString();
|
|
109
|
-
}
|
|
110
|
-
return String(n);
|
|
111
|
-
};
|
|
112
|
-
let re = this.re;
|
|
113
|
-
let im = this.im;
|
|
114
|
-
if (options?.precision !== void 0) {
|
|
115
|
-
const epsilon = Math.pow(10, -options.precision);
|
|
116
|
-
if (Math.abs(re) < epsilon * Math.abs(im)) re = 0;
|
|
117
|
-
if (Math.abs(im) < epsilon * Math.abs(re)) im = 0;
|
|
118
|
-
}
|
|
119
|
-
if (im === 0) return formatNum(re);
|
|
120
|
-
if (re === 0) {
|
|
121
|
-
if (im === 1) return "i";
|
|
122
|
-
if (im === -1) return "-i";
|
|
123
|
-
return `${formatNum(im)}i`;
|
|
124
|
-
}
|
|
125
|
-
const sign = im < 0 ? " - " : " + ";
|
|
126
|
-
const absIm = Math.abs(im);
|
|
127
|
-
if (absIm === 1) {
|
|
128
|
-
return `${formatNum(re)}${sign}i`;
|
|
129
|
-
}
|
|
130
|
-
return `${formatNum(re)}${sign}${formatNum(absIm)}i`;
|
|
131
|
-
}
|
|
132
|
-
// ============================================================
|
|
133
|
-
// Basic Properties
|
|
134
|
-
// ============================================================
|
|
135
|
-
/**
|
|
136
|
-
* Complex conjugate (a + bi → a - bi)
|
|
137
|
-
*/
|
|
138
|
-
conjugate() {
|
|
139
|
-
return new _Complex(this.re, -this.im);
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Magnitude (absolute value) |z| = √(re² + im²)
|
|
143
|
-
*/
|
|
144
|
-
abs() {
|
|
145
|
-
return Math.hypot(this.re, this.im);
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Phase angle (argument) in radians, range (-π, π]
|
|
149
|
-
*/
|
|
150
|
-
arg() {
|
|
151
|
-
return Math.atan2(this.im, this.re);
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Squared magnitude |z|² = re² + im²
|
|
155
|
-
* More efficient than abs() when you don't need the square root
|
|
156
|
-
*/
|
|
157
|
-
abs2() {
|
|
158
|
-
return this.re * this.re + this.im * this.im;
|
|
159
|
-
}
|
|
160
|
-
// ============================================================
|
|
161
|
-
// Arithmetic Operations (Scalar interface)
|
|
162
|
-
// ============================================================
|
|
163
|
-
/**
|
|
164
|
-
* Addition: (a + bi) + (c + di) = (a + c) + (b + d)i
|
|
165
|
-
*/
|
|
166
|
-
add(other) {
|
|
167
|
-
if (other instanceof _Complex) {
|
|
168
|
-
return new _Complex(this.re + other.re, this.im + other.im);
|
|
169
|
-
}
|
|
170
|
-
return new _Complex(this.re + Number(other.valueOf()), this.im);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i
|
|
174
|
-
*/
|
|
175
|
-
subtract(other) {
|
|
176
|
-
if (other instanceof _Complex) {
|
|
177
|
-
return new _Complex(this.re - other.re, this.im - other.im);
|
|
178
|
-
}
|
|
179
|
-
return new _Complex(this.re - Number(other.valueOf()), this.im);
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Multiplication: (a + bi)(c + di) = (ac - bd) + (ad + bc)i
|
|
183
|
-
*/
|
|
184
|
-
multiply(other) {
|
|
185
|
-
if (other instanceof _Complex) {
|
|
186
|
-
return new _Complex(
|
|
187
|
-
this.re * other.re - this.im * other.im,
|
|
188
|
-
this.re * other.im + this.im * other.re
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
const n = Number(other.valueOf());
|
|
192
|
-
return new _Complex(this.re * n, this.im * n);
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Division: (a + bi)/(c + di) = ((ac + bd) + (bc - ad)i) / (c² + d²)
|
|
196
|
-
*/
|
|
197
|
-
divide(other) {
|
|
198
|
-
if (other instanceof _Complex) {
|
|
199
|
-
const denom = other.re * other.re + other.im * other.im;
|
|
200
|
-
if (denom === 0) {
|
|
201
|
-
return new _Complex(
|
|
202
|
-
this.re !== 0 ? this.re > 0 ? Infinity : -Infinity : NaN,
|
|
203
|
-
this.im !== 0 ? this.im > 0 ? Infinity : -Infinity : NaN
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
return new _Complex(
|
|
207
|
-
(this.re * other.re + this.im * other.im) / denom,
|
|
208
|
-
(this.im * other.re - this.re * other.im) / denom
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
const n = Number(other.valueOf());
|
|
212
|
-
if (n === 0) {
|
|
213
|
-
return new _Complex(
|
|
214
|
-
this.re !== 0 ? this.re > 0 ? Infinity : -Infinity : NaN,
|
|
215
|
-
this.im !== 0 ? this.im > 0 ? Infinity : -Infinity : NaN
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
return new _Complex(this.re / n, this.im / n);
|
|
219
|
-
}
|
|
220
|
-
// ------------------------------------------------------------
|
|
221
|
-
// Short-name aliases (mathjs-functions calling convention)
|
|
222
|
-
//
|
|
223
|
-
// The functions-package typed-function arithmetic (subtractScalar,
|
|
224
|
-
// multiplyScalar, divideScalar, …) invokes `.add/.sub/.mul/.div/.neg`
|
|
225
|
-
// on scalars. A core Complex (e.g. produced by `sqrt(-4)`) can flow into
|
|
226
|
-
// those code paths, so it must answer to the short names too — otherwise
|
|
227
|
-
// `x.sub is not a function`. Mirrors the Fraction short-alias fix.
|
|
228
|
-
// ------------------------------------------------------------
|
|
229
|
-
sub(other) {
|
|
230
|
-
return this.subtract(other);
|
|
231
|
-
}
|
|
232
|
-
mul(other) {
|
|
233
|
-
return this.multiply(other);
|
|
234
|
-
}
|
|
235
|
-
div(other) {
|
|
236
|
-
return this.divide(other);
|
|
237
|
-
}
|
|
238
|
-
neg() {
|
|
239
|
-
return this.negate();
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Negation: -(a + bi) = -a - bi
|
|
243
|
-
*/
|
|
244
|
-
negate() {
|
|
245
|
-
return new _Complex(-this.re, -this.im);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Multiplicative inverse: 1/z = z̄/|z|²
|
|
249
|
-
*/
|
|
250
|
-
inverse() {
|
|
251
|
-
const denom = this.abs2();
|
|
252
|
-
if (denom === 0) {
|
|
253
|
-
return new _Complex(Infinity, Infinity);
|
|
254
|
-
}
|
|
255
|
-
return new _Complex(this.re / denom, -this.im / denom);
|
|
256
|
-
}
|
|
257
|
-
// ============================================================
|
|
258
|
-
// Transcendental Functions
|
|
259
|
-
// ============================================================
|
|
260
|
-
/**
|
|
261
|
-
* Square root using principal branch
|
|
262
|
-
* √z = √r · e^(iθ/2) where r = |z|, θ = arg(z)
|
|
263
|
-
*/
|
|
264
|
-
sqrt() {
|
|
265
|
-
const r = this.abs();
|
|
266
|
-
const theta = this.arg();
|
|
267
|
-
return _Complex.fromPolar(Math.sqrt(r), theta / 2);
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* n-th root (returns principal root)
|
|
271
|
-
*/
|
|
272
|
-
nthRoot(n) {
|
|
273
|
-
const r = this.abs();
|
|
274
|
-
const theta = this.arg();
|
|
275
|
-
return _Complex.fromPolar(Math.pow(r, 1 / n), theta / n);
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* All n-th roots
|
|
279
|
-
*/
|
|
280
|
-
nthRoots(n) {
|
|
281
|
-
const r = this.abs();
|
|
282
|
-
const theta = this.arg();
|
|
283
|
-
const rootR = Math.pow(r, 1 / n);
|
|
284
|
-
const roots = [];
|
|
285
|
-
for (let k = 0; k < n; k++) {
|
|
286
|
-
roots.push(_Complex.fromPolar(rootR, (theta + 2 * Math.PI * k) / n));
|
|
287
|
-
}
|
|
288
|
-
return roots;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Exponential: e^(a+bi) = e^a · (cos(b) + i·sin(b))
|
|
292
|
-
*/
|
|
293
|
-
exp() {
|
|
294
|
-
const ea = Math.exp(this.re);
|
|
295
|
-
return new _Complex(ea * Math.cos(this.im), ea * Math.sin(this.im));
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Natural logarithm: ln(z) = ln|z| + i·arg(z)
|
|
299
|
-
*/
|
|
300
|
-
log() {
|
|
301
|
-
return new _Complex(Math.log(this.abs()), this.arg());
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Logarithm base 10
|
|
305
|
-
*/
|
|
306
|
-
log10() {
|
|
307
|
-
return this.log().divide(new _Complex(Math.LN10, 0));
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Logarithm base 2
|
|
311
|
-
*/
|
|
312
|
-
log2() {
|
|
313
|
-
return this.log().divide(new _Complex(Math.LN2, 0));
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Power: z^w = e^(w·ln(z))
|
|
317
|
-
*/
|
|
318
|
-
pow(n) {
|
|
319
|
-
if (typeof n === "number") {
|
|
320
|
-
if (this.re === 0 && this.im === 0) {
|
|
321
|
-
return n === 0 ? new _Complex(1, 0) : new _Complex(0, 0);
|
|
322
|
-
}
|
|
323
|
-
const r = this.abs();
|
|
324
|
-
const theta = this.arg();
|
|
325
|
-
return _Complex.fromPolar(Math.pow(r, n), theta * n);
|
|
326
|
-
}
|
|
327
|
-
if (this.re === 0 && this.im === 0) {
|
|
328
|
-
return new _Complex(0, 0);
|
|
329
|
-
}
|
|
330
|
-
return this.log().multiply(n).exp();
|
|
331
|
-
}
|
|
332
|
-
// ============================================================
|
|
333
|
-
// Trigonometric Functions
|
|
334
|
-
// ============================================================
|
|
335
|
-
/**
|
|
336
|
-
* Sine: sin(a + bi) = sin(a)cosh(b) + i·cos(a)sinh(b)
|
|
337
|
-
*/
|
|
338
|
-
sin() {
|
|
339
|
-
return new _Complex(
|
|
340
|
-
Math.sin(this.re) * Math.cosh(this.im),
|
|
341
|
-
Math.cos(this.re) * Math.sinh(this.im)
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* Cosine: cos(a + bi) = cos(a)cosh(b) - i·sin(a)sinh(b)
|
|
346
|
-
*/
|
|
347
|
-
cos() {
|
|
348
|
-
return new _Complex(
|
|
349
|
-
Math.cos(this.re) * Math.cosh(this.im),
|
|
350
|
-
-Math.sin(this.re) * Math.sinh(this.im)
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Tangent: tan(z) = sin(z) / cos(z)
|
|
355
|
-
*/
|
|
356
|
-
tan() {
|
|
357
|
-
return this.sin().divide(this.cos());
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Cotangent: cot(z) = cos(z) / sin(z)
|
|
361
|
-
*/
|
|
362
|
-
cot() {
|
|
363
|
-
return this.cos().divide(this.sin());
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Secant: sec(z) = 1 / cos(z)
|
|
367
|
-
*/
|
|
368
|
-
sec() {
|
|
369
|
-
return this.cos().inverse();
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Cosecant: csc(z) = 1 / sin(z)
|
|
373
|
-
*/
|
|
374
|
-
csc() {
|
|
375
|
-
return this.sin().inverse();
|
|
376
|
-
}
|
|
377
|
-
// ============================================================
|
|
378
|
-
// Hyperbolic Functions
|
|
379
|
-
// ============================================================
|
|
380
|
-
/**
|
|
381
|
-
* Hyperbolic sine: sinh(z) = (e^z - e^(-z)) / 2
|
|
382
|
-
*/
|
|
383
|
-
sinh() {
|
|
384
|
-
return new _Complex(
|
|
385
|
-
Math.sinh(this.re) * Math.cos(this.im),
|
|
386
|
-
Math.cosh(this.re) * Math.sin(this.im)
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Hyperbolic cosine: cosh(z) = (e^z + e^(-z)) / 2
|
|
391
|
-
*/
|
|
392
|
-
cosh() {
|
|
393
|
-
return new _Complex(
|
|
394
|
-
Math.cosh(this.re) * Math.cos(this.im),
|
|
395
|
-
Math.sinh(this.re) * Math.sin(this.im)
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Hyperbolic tangent: tanh(z) = sinh(z) / cosh(z)
|
|
400
|
-
*/
|
|
401
|
-
tanh() {
|
|
402
|
-
return this.sinh().divide(this.cosh());
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Hyperbolic cotangent: coth(z) = cosh(z) / sinh(z)
|
|
406
|
-
*/
|
|
407
|
-
coth() {
|
|
408
|
-
return this.cosh().divide(this.sinh());
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Hyperbolic secant: sech(z) = 1 / cosh(z)
|
|
412
|
-
*/
|
|
413
|
-
sech() {
|
|
414
|
-
return this.cosh().inverse();
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Hyperbolic cosecant: csch(z) = 1 / sinh(z)
|
|
418
|
-
*/
|
|
419
|
-
csch() {
|
|
420
|
-
return this.sinh().inverse();
|
|
421
|
-
}
|
|
422
|
-
// ============================================================
|
|
423
|
-
// Inverse Trigonometric Functions
|
|
424
|
-
// ============================================================
|
|
425
|
-
/**
|
|
426
|
-
* Arc sine: asin(z) = -i·ln(iz + √(1 - z²))
|
|
427
|
-
*/
|
|
428
|
-
asin() {
|
|
429
|
-
const iz = new _Complex(-this.im, this.re);
|
|
430
|
-
const one = new _Complex(1, 0);
|
|
431
|
-
const sqrt = one.subtract(this.multiply(this)).sqrt();
|
|
432
|
-
return iz.add(sqrt).log().multiply(new _Complex(0, -1));
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Arc cosine: acos(z) = π/2 - asin(z)
|
|
436
|
-
*/
|
|
437
|
-
acos() {
|
|
438
|
-
return new _Complex(Math.PI / 2, 0).subtract(this.asin());
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Arc tangent: atan(z) = (i/2)·ln((i + z)/(i - z))
|
|
442
|
-
*/
|
|
443
|
-
atan() {
|
|
444
|
-
const i = new _Complex(0, 1);
|
|
445
|
-
const iHalf = new _Complex(0, 0.5);
|
|
446
|
-
const num = i.add(this);
|
|
447
|
-
const denom = i.subtract(this);
|
|
448
|
-
return num.divide(denom).log().multiply(iHalf);
|
|
449
|
-
}
|
|
450
|
-
// ============================================================
|
|
451
|
-
// Inverse Hyperbolic Functions
|
|
452
|
-
// ============================================================
|
|
453
|
-
/**
|
|
454
|
-
* Inverse hyperbolic sine: asinh(z) = ln(z + √(z² + 1))
|
|
455
|
-
*/
|
|
456
|
-
asinh() {
|
|
457
|
-
const one = new _Complex(1, 0);
|
|
458
|
-
return this.add(this.multiply(this).add(one).sqrt()).log();
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* Inverse hyperbolic cosine: acosh(z) = ln(z + √(z² - 1))
|
|
462
|
-
*/
|
|
463
|
-
acosh() {
|
|
464
|
-
const one = new _Complex(1, 0);
|
|
465
|
-
return this.add(this.multiply(this).subtract(one).sqrt()).log();
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Inverse hyperbolic tangent: atanh(z) = (1/2)·ln((1 + z)/(1 - z))
|
|
469
|
-
*/
|
|
470
|
-
atanh() {
|
|
471
|
-
const one = new _Complex(1, 0);
|
|
472
|
-
const half = new _Complex(0.5, 0);
|
|
473
|
-
return one.add(this).divide(one.subtract(this)).log().multiply(half);
|
|
474
|
-
}
|
|
475
|
-
// ============================================================
|
|
476
|
-
// Utility Methods
|
|
477
|
-
// ============================================================
|
|
478
|
-
/**
|
|
479
|
-
* Check equality within tolerance
|
|
480
|
-
*/
|
|
481
|
-
equals(other, epsilon = 1e-12) {
|
|
482
|
-
return Math.abs(this.re - other.re) < epsilon && Math.abs(this.im - other.im) < epsilon;
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Check if this is a real number (im ≈ 0)
|
|
486
|
-
*/
|
|
487
|
-
isReal(epsilon = 0) {
|
|
488
|
-
return Math.abs(this.im) <= epsilon;
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Check if this is purely imaginary (re ≈ 0, im ≠ 0)
|
|
492
|
-
*/
|
|
493
|
-
isImaginary(epsilon = 0) {
|
|
494
|
-
return Math.abs(this.re) <= epsilon && Math.abs(this.im) > epsilon;
|
|
495
|
-
}
|
|
496
|
-
/**
|
|
497
|
-
* Check if this is zero
|
|
498
|
-
*/
|
|
499
|
-
isZero(epsilon = 0) {
|
|
500
|
-
return Math.abs(this.re) <= epsilon && Math.abs(this.im) <= epsilon;
|
|
501
|
-
}
|
|
502
|
-
/**
|
|
503
|
-
* Check if this is NaN
|
|
504
|
-
*/
|
|
505
|
-
isNaN() {
|
|
506
|
-
return Number.isNaN(this.re) || Number.isNaN(this.im);
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* Check if this is infinite
|
|
510
|
-
*/
|
|
511
|
-
isInfinite() {
|
|
512
|
-
return !this.isNaN() && (!Number.isFinite(this.re) || !Number.isFinite(this.im));
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Clone this complex number
|
|
516
|
-
*/
|
|
517
|
-
clone() {
|
|
518
|
-
return new _Complex(this.re, this.im);
|
|
519
|
-
}
|
|
520
|
-
/**
|
|
521
|
-
* Round real and imaginary parts to specified decimals
|
|
522
|
-
*/
|
|
523
|
-
round(decimals = 0) {
|
|
524
|
-
const factor = Math.pow(10, decimals);
|
|
525
|
-
return new _Complex(
|
|
526
|
-
Math.round(this.re * factor) / factor,
|
|
527
|
-
Math.round(this.im * factor) / factor
|
|
528
|
-
);
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Floor real and imaginary parts
|
|
532
|
-
*/
|
|
533
|
-
floor() {
|
|
534
|
-
return new _Complex(Math.floor(this.re), Math.floor(this.im));
|
|
535
|
-
}
|
|
536
|
-
/**
|
|
537
|
-
* Ceil real and imaginary parts
|
|
538
|
-
*/
|
|
539
|
-
ceil() {
|
|
540
|
-
return new _Complex(Math.ceil(this.re), Math.ceil(this.im));
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* Sign function: z / |z| (unit complex number in same direction)
|
|
544
|
-
*/
|
|
545
|
-
sign() {
|
|
546
|
-
const r = this.abs();
|
|
547
|
-
if (r === 0) return new _Complex(0, 0);
|
|
548
|
-
return new _Complex(this.re / r, this.im / r);
|
|
549
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
BIGNUMBER_E,
|
|
3
|
+
BIGNUMBER_LN10,
|
|
4
|
+
BIGNUMBER_LN2,
|
|
5
|
+
BIGNUMBER_NEG_ONE,
|
|
6
|
+
BIGNUMBER_ONE,
|
|
7
|
+
BIGNUMBER_PI,
|
|
8
|
+
BIGNUMBER_TEN,
|
|
9
|
+
BIGNUMBER_ZERO,
|
|
10
|
+
BigNumber,
|
|
11
|
+
COMPLEX_NEG_ONE,
|
|
12
|
+
COMPLEX_ONE,
|
|
13
|
+
COMPLEX_ZERO,
|
|
14
|
+
Complex,
|
|
15
|
+
DimensionMismatchError,
|
|
16
|
+
FRACTION_HALF,
|
|
17
|
+
FRACTION_NEG_ONE,
|
|
18
|
+
FRACTION_ONE,
|
|
19
|
+
FRACTION_QUARTER,
|
|
20
|
+
FRACTION_THIRD,
|
|
21
|
+
FRACTION_ZERO,
|
|
22
|
+
Fraction,
|
|
23
|
+
I,
|
|
24
|
+
Unit,
|
|
25
|
+
UnitParseError,
|
|
26
|
+
abs,
|
|
27
|
+
addScalar,
|
|
28
|
+
divideScalar,
|
|
29
|
+
equal,
|
|
30
|
+
fix,
|
|
31
|
+
isBigNumber,
|
|
32
|
+
isComplex,
|
|
33
|
+
isFraction,
|
|
34
|
+
isNumeric,
|
|
35
|
+
isUnit,
|
|
36
|
+
multiplyScalar,
|
|
37
|
+
number,
|
|
38
|
+
pow,
|
|
39
|
+
round,
|
|
40
|
+
subtractScalar
|
|
41
|
+
} from "./chunk-JB4VPWK4.js";
|
|
42
|
+
|
|
43
|
+
// src/types/dual-rules.ts
|
|
44
|
+
var DUAL_UNARY_RULES = {
|
|
45
|
+
exp: { primal: Math.exp, deriv: (_x, y) => y },
|
|
46
|
+
expm1: { primal: Math.expm1, deriv: (_x, y) => y + 1 },
|
|
47
|
+
log: { primal: Math.log, deriv: (x) => 1 / x },
|
|
48
|
+
log2: { primal: Math.log2, deriv: (x) => 1 / (x * Math.LN2) },
|
|
49
|
+
log10: { primal: Math.log10, deriv: (x) => 1 / (x * Math.LN10) },
|
|
50
|
+
log1p: { primal: Math.log1p, deriv: (x) => 1 / (1 + x) },
|
|
51
|
+
sin: { primal: Math.sin, deriv: (x) => Math.cos(x) },
|
|
52
|
+
cos: { primal: Math.cos, deriv: (x) => -Math.sin(x) },
|
|
53
|
+
tan: { primal: Math.tan, deriv: (x) => 1 / (Math.cos(x) * Math.cos(x)) },
|
|
54
|
+
asin: { primal: Math.asin, deriv: (x) => 1 / Math.sqrt(1 - x * x) },
|
|
55
|
+
acos: { primal: Math.acos, deriv: (x) => -1 / Math.sqrt(1 - x * x) },
|
|
56
|
+
atan: { primal: Math.atan, deriv: (x) => 1 / (1 + x * x) },
|
|
57
|
+
sinh: { primal: Math.sinh, deriv: (x) => Math.cosh(x) },
|
|
58
|
+
cosh: { primal: Math.cosh, deriv: (x) => Math.sinh(x) },
|
|
59
|
+
tanh: { primal: Math.tanh, deriv: (_x, y) => 1 - y * y },
|
|
60
|
+
asinh: { primal: Math.asinh, deriv: (x) => 1 / Math.sqrt(x * x + 1) },
|
|
61
|
+
acosh: { primal: Math.acosh, deriv: (x) => 1 / Math.sqrt(x * x - 1) },
|
|
62
|
+
atanh: { primal: Math.atanh, deriv: (x) => 1 / (1 - x * x) },
|
|
63
|
+
sqrt: { primal: Math.sqrt, deriv: (_x, y) => 1 / (2 * y) },
|
|
64
|
+
cbrt: { primal: Math.cbrt, deriv: (_x, y) => 1 / (3 * y * y) },
|
|
65
|
+
square: { primal: (x) => x * x, deriv: (x) => 2 * x },
|
|
66
|
+
reciprocal: { primal: (x) => 1 / x, deriv: (x) => -1 / (x * x) },
|
|
67
|
+
abs: { primal: Math.abs, deriv: (x) => Math.sign(x) },
|
|
68
|
+
sign: { primal: Math.sign, deriv: () => 0 }
|
|
550
69
|
};
|
|
551
|
-
var I = new Complex(0, 1);
|
|
552
|
-
var COMPLEX_ZERO = new Complex(0, 0);
|
|
553
|
-
var COMPLEX_ONE = new Complex(1, 0);
|
|
554
|
-
var COMPLEX_NEG_ONE = new Complex(-1, 0);
|
|
555
70
|
|
|
556
71
|
// src/types/dual.ts
|
|
557
72
|
var Dual = class _Dual {
|
|
@@ -575,1776 +90,89 @@ var Dual = class _Dual {
|
|
|
575
90
|
add(o) {
|
|
576
91
|
return new _Dual(this.value + o.value, this.deriv + o.deriv);
|
|
577
92
|
}
|
|
578
|
-
sub(o) {
|
|
579
|
-
return new _Dual(this.value - o.value, this.deriv - o.deriv);
|
|
580
|
-
}
|
|
581
|
-
mul(o) {
|
|
582
|
-
return new _Dual(this.value * o.value, this.deriv * o.value + this.value * o.deriv);
|
|
583
|
-
}
|
|
584
|
-
div(o) {
|
|
585
|
-
const d = (this.deriv * o.value - this.value * o.deriv) / (o.value * o.value);
|
|
586
|
-
return new _Dual(this.value / o.value, d);
|
|
587
|
-
}
|
|
588
|
-
neg() {
|
|
589
|
-
return new _Dual(-this.value, -this.deriv);
|
|
590
|
-
}
|
|
591
|
-
/** Power with a constant real exponent: d(xᵏ) = k·xᵏ⁻¹·dx. */
|
|
592
|
-
powConst(k) {
|
|
593
|
-
return new _Dual(Math.pow(this.value, k), this.deriv * k * Math.pow(this.value, k - 1));
|
|
594
|
-
}
|
|
595
|
-
/** General power a^b: d = a^b·(b'·ln a + b·a'/a). */
|
|
596
|
-
pow(o) {
|
|
597
|
-
const v = Math.pow(this.value, o.value);
|
|
598
|
-
const d = v * (o.deriv * Math.log(this.value) + o.value * this.deriv / this.value);
|
|
599
|
-
return new _Dual(v, d);
|
|
600
|
-
}
|
|
601
|
-
// --- elementary functions ------------------------------------------------
|
|
602
|
-
sin() {
|
|
603
|
-
return new _Dual(Math.sin(this.value), this.deriv * Math.cos(this.value));
|
|
604
|
-
}
|
|
605
|
-
cos() {
|
|
606
|
-
return new _Dual(Math.cos(this.value), -this.deriv * Math.sin(this.value));
|
|
607
|
-
}
|
|
608
|
-
tan() {
|
|
609
|
-
const c = Math.cos(this.value);
|
|
610
|
-
return new _Dual(Math.tan(this.value), this.deriv / (c * c));
|
|
611
|
-
}
|
|
612
|
-
exp() {
|
|
613
|
-
const e = Math.exp(this.value);
|
|
614
|
-
return new _Dual(e, this.deriv * e);
|
|
615
|
-
}
|
|
616
|
-
log() {
|
|
617
|
-
return new _Dual(Math.log(this.value), this.deriv / this.value);
|
|
618
|
-
}
|
|
619
|
-
sqrt() {
|
|
620
|
-
const s = Math.sqrt(this.value);
|
|
621
|
-
return new _Dual(s, this.deriv / (2 * s));
|
|
622
|
-
}
|
|
623
|
-
square() {
|
|
624
|
-
return new _Dual(this.value * this.value, 2 * this.value * this.deriv);
|
|
625
|
-
}
|
|
626
|
-
abs() {
|
|
627
|
-
return new _Dual(Math.abs(this.value), this.deriv * Math.sign(this.value));
|
|
628
|
-
}
|
|
629
|
-
sinh() {
|
|
630
|
-
return new _Dual(Math.sinh(this.value), this.deriv * Math.cosh(this.value));
|
|
631
|
-
}
|
|
632
|
-
cosh() {
|
|
633
|
-
return new _Dual(Math.cosh(this.value), this.deriv * Math.sinh(this.value));
|
|
634
|
-
}
|
|
635
|
-
tanh() {
|
|
636
|
-
const t = Math.tanh(this.value);
|
|
637
|
-
return new _Dual(t, this.deriv * (1 - t * t));
|
|
638
|
-
}
|
|
639
|
-
toString() {
|
|
640
|
-
return `Dual(${this.value}, ${this.deriv})`;
|
|
641
|
-
}
|
|
642
|
-
};
|
|
643
|
-
function isDual(x) {
|
|
644
|
-
return x instanceof Dual;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// src/constants.ts
|
|
648
|
-
var PI = Math.PI;
|
|
649
|
-
var E = Math.E;
|
|
650
|
-
var TAU = 2 * Math.PI;
|
|
651
|
-
var PHI = (1 + Math.sqrt(5)) / 2;
|
|
652
|
-
var SQRT2 = Math.SQRT2;
|
|
653
|
-
var SQRT1_2 = Math.SQRT1_2;
|
|
654
|
-
var LN2 = Math.LN2;
|
|
655
|
-
var LN10 = Math.LN10;
|
|
656
|
-
var LOG2E = Math.LOG2E;
|
|
657
|
-
var LOG10E = Math.LOG10E;
|
|
658
|
-
|
|
659
|
-
// src/types/fraction.ts
|
|
660
|
-
function isFraction(value) {
|
|
661
|
-
return value instanceof Fraction;
|
|
662
|
-
}
|
|
663
|
-
function gcd(a, b) {
|
|
664
|
-
a = a < 0n ? -a : a;
|
|
665
|
-
b = b < 0n ? -b : b;
|
|
666
|
-
while (b !== 0n) {
|
|
667
|
-
const t = b;
|
|
668
|
-
b = a % b;
|
|
669
|
-
a = t;
|
|
670
|
-
}
|
|
671
|
-
return a;
|
|
672
|
-
}
|
|
673
|
-
var Fraction = class _Fraction {
|
|
674
|
-
type = "Fraction";
|
|
675
|
-
numerator;
|
|
676
|
-
denominator;
|
|
677
|
-
constructor(numerator, denominator = 1n) {
|
|
678
|
-
const toRatio = (x) => {
|
|
679
|
-
if (typeof x === "number" && !Number.isInteger(x)) {
|
|
680
|
-
const f = _Fraction.fromNumber(x);
|
|
681
|
-
return [f.numerator, f.denominator];
|
|
682
|
-
}
|
|
683
|
-
return [typeof x === "bigint" ? x : BigInt(x), 1n];
|
|
684
|
-
};
|
|
685
|
-
const [pn, qn] = toRatio(numerator);
|
|
686
|
-
const [pd, qd] = toRatio(denominator);
|
|
687
|
-
let num = pn * qd;
|
|
688
|
-
let den = qn * pd;
|
|
689
|
-
if (den === 0n) {
|
|
690
|
-
throw new Error("Fraction denominator cannot be zero");
|
|
691
|
-
}
|
|
692
|
-
if (den < 0n) {
|
|
693
|
-
num = -num;
|
|
694
|
-
den = -den;
|
|
695
|
-
}
|
|
696
|
-
const g = gcd(num, den);
|
|
697
|
-
this.numerator = num / g;
|
|
698
|
-
this.denominator = den / g;
|
|
699
|
-
}
|
|
700
|
-
// ============================================================
|
|
701
|
-
// Static Factory Methods
|
|
702
|
-
// ============================================================
|
|
703
|
-
/**
|
|
704
|
-
* Create a Fraction from a number (with optional precision)
|
|
705
|
-
*/
|
|
706
|
-
static fromNumber(n, maxDenominator = 1000000n) {
|
|
707
|
-
if (!Number.isFinite(n)) {
|
|
708
|
-
throw new Error("Cannot create fraction from non-finite number");
|
|
709
|
-
}
|
|
710
|
-
if (Number.isInteger(n)) {
|
|
711
|
-
return new _Fraction(BigInt(n), 1n);
|
|
712
|
-
}
|
|
713
|
-
const sign = n < 0 ? -1n : 1n;
|
|
714
|
-
n = Math.abs(n);
|
|
715
|
-
let h1 = 1n, h2 = 0n;
|
|
716
|
-
let k1 = 0n, k2 = 1n;
|
|
717
|
-
let b = n;
|
|
718
|
-
do {
|
|
719
|
-
const a = BigInt(Math.floor(b));
|
|
720
|
-
let aux = h1;
|
|
721
|
-
h1 = a * h1 + h2;
|
|
722
|
-
h2 = aux;
|
|
723
|
-
aux = k1;
|
|
724
|
-
k1 = a * k1 + k2;
|
|
725
|
-
k2 = aux;
|
|
726
|
-
b = 1 / (b - Number(a));
|
|
727
|
-
} while (Math.abs(n - Number(h1) / Number(k1)) > Number.EPSILON && k1 < maxDenominator);
|
|
728
|
-
return new _Fraction(sign * h1, k1);
|
|
729
|
-
}
|
|
730
|
-
/**
|
|
731
|
-
* Create a Fraction from a decimal string
|
|
732
|
-
*/
|
|
733
|
-
static fromDecimalString(str) {
|
|
734
|
-
str = str.trim();
|
|
735
|
-
const repeatingMatch = str.match(/^(-?\d*)\.(\d*)\((\d+)\)$/);
|
|
736
|
-
if (repeatingMatch) {
|
|
737
|
-
const sign2 = str.startsWith("-") ? -1n : 1n;
|
|
738
|
-
const intPart2 = repeatingMatch[1] === "-" ? "0" : repeatingMatch[1] || "0";
|
|
739
|
-
const nonRepeating = repeatingMatch[2] || "";
|
|
740
|
-
const repeating = repeatingMatch[3];
|
|
741
|
-
const fullDigits = intPart2 + nonRepeating + repeating;
|
|
742
|
-
const nonRepDigits = intPart2 + nonRepeating;
|
|
743
|
-
const fullNum = BigInt(fullDigits.replace("-", ""));
|
|
744
|
-
const nonRepNum = BigInt(nonRepDigits.replace("-", "") || "0");
|
|
745
|
-
const nines = BigInt("9".repeat(repeating.length));
|
|
746
|
-
const zeros = BigInt("1" + "0".repeat(nonRepeating.length));
|
|
747
|
-
const num2 = fullNum - nonRepNum;
|
|
748
|
-
const den2 = nines * zeros;
|
|
749
|
-
return new _Fraction(sign2 * num2, den2);
|
|
750
|
-
}
|
|
751
|
-
const [intPart, decPart = ""] = str.split(".");
|
|
752
|
-
const sign = str.startsWith("-") ? -1n : 1n;
|
|
753
|
-
const absInt = intPart.replace("-", "") || "0";
|
|
754
|
-
const combined = absInt + decPart;
|
|
755
|
-
const num = BigInt(combined);
|
|
756
|
-
const den = BigInt("1" + "0".repeat(decPart.length));
|
|
757
|
-
return new _Fraction(sign * num, den);
|
|
758
|
-
}
|
|
759
|
-
/**
|
|
760
|
-
* Parse a fraction from a string
|
|
761
|
-
* Supports formats: "3/4", "-3/4", "3", "3.14", "0.(3)"
|
|
762
|
-
*/
|
|
763
|
-
static parse(str) {
|
|
764
|
-
str = str.trim();
|
|
765
|
-
if (str.includes("/")) {
|
|
766
|
-
const [numStr, denStr] = str.split("/");
|
|
767
|
-
return new _Fraction(BigInt(numStr.trim()), BigInt(denStr.trim()));
|
|
768
|
-
}
|
|
769
|
-
if (str.includes(".") || str.includes("(")) {
|
|
770
|
-
return _Fraction.fromDecimalString(str);
|
|
771
|
-
}
|
|
772
|
-
return new _Fraction(BigInt(str), 1n);
|
|
773
|
-
}
|
|
774
|
-
/**
|
|
775
|
-
* Create a Fraction from a JSON object
|
|
776
|
-
*/
|
|
777
|
-
static fromJSON(json) {
|
|
778
|
-
if ("n" in json) {
|
|
779
|
-
return new _Fraction(BigInt(json.n), BigInt(json.d));
|
|
780
|
-
}
|
|
781
|
-
return new _Fraction(BigInt(json.numerator), BigInt(json.denominator));
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Compare two fractions
|
|
785
|
-
* @returns -1, 0, or 1
|
|
786
|
-
*/
|
|
787
|
-
static compare(a, b) {
|
|
788
|
-
const diff = a.numerator * b.denominator - b.numerator * a.denominator;
|
|
789
|
-
if (diff < 0n) return -1;
|
|
790
|
-
if (diff > 0n) return 1;
|
|
791
|
-
return 0;
|
|
792
|
-
}
|
|
793
|
-
// ============================================================
|
|
794
|
-
// Conversion Methods
|
|
795
|
-
// ============================================================
|
|
796
|
-
valueOf() {
|
|
797
|
-
return Number(this.numerator) / Number(this.denominator);
|
|
798
|
-
}
|
|
799
|
-
toString() {
|
|
800
|
-
if (this.denominator === 1n) {
|
|
801
|
-
return this.numerator.toString();
|
|
802
|
-
}
|
|
803
|
-
return `${this.numerator}/${this.denominator}`;
|
|
804
|
-
}
|
|
805
|
-
toJSON() {
|
|
806
|
-
return {
|
|
807
|
-
mathjs: "Fraction",
|
|
808
|
-
n: this.numerator.toString(),
|
|
809
|
-
d: this.denominator.toString()
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
/**
|
|
813
|
-
* Convert to number
|
|
814
|
-
*/
|
|
815
|
-
toNumber() {
|
|
816
|
-
return this.valueOf();
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* Convert to decimal string with specified precision
|
|
820
|
-
*/
|
|
821
|
-
toDecimal(precision = 10) {
|
|
822
|
-
const sign = this.numerator < 0n ? "-" : "";
|
|
823
|
-
let num = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
824
|
-
const den = this.denominator;
|
|
825
|
-
const intPart = num / den;
|
|
826
|
-
num = num % den;
|
|
827
|
-
if (num === 0n || precision === 0) {
|
|
828
|
-
return sign + intPart.toString();
|
|
829
|
-
}
|
|
830
|
-
let decPart = "";
|
|
831
|
-
for (let i = 0; i < precision && num !== 0n; i++) {
|
|
832
|
-
num *= 10n;
|
|
833
|
-
decPart += (num / den).toString();
|
|
834
|
-
num = num % den;
|
|
835
|
-
}
|
|
836
|
-
return sign + intPart.toString() + "." + decPart;
|
|
837
|
-
}
|
|
838
|
-
/**
|
|
839
|
-
* Convert to LaTeX string
|
|
840
|
-
*/
|
|
841
|
-
toLatex() {
|
|
842
|
-
if (this.denominator === 1n) {
|
|
843
|
-
return this.numerator.toString();
|
|
844
|
-
}
|
|
845
|
-
const sign = this.numerator < 0n ? "-" : "";
|
|
846
|
-
const absNum = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
847
|
-
return `${sign}\\frac{${absNum}}{${this.denominator}}`;
|
|
848
|
-
}
|
|
849
|
-
/**
|
|
850
|
-
* Convert to mixed number representation
|
|
851
|
-
*/
|
|
852
|
-
toMixed() {
|
|
853
|
-
const sign = this.numerator < 0n ? -1n : 1n;
|
|
854
|
-
const absNum = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
855
|
-
const whole = sign * (absNum / this.denominator);
|
|
856
|
-
const remainder = absNum % this.denominator;
|
|
857
|
-
return {
|
|
858
|
-
whole,
|
|
859
|
-
numerator: remainder,
|
|
860
|
-
denominator: this.denominator
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
// ============================================================
|
|
864
|
-
// Arithmetic Operations (Scalar interface)
|
|
865
|
-
// ============================================================
|
|
866
|
-
/**
|
|
867
|
-
* Addition: a/b + c/d = (ad + bc) / bd
|
|
868
|
-
*/
|
|
869
|
-
add(other) {
|
|
870
|
-
if (other instanceof _Fraction) {
|
|
871
|
-
const num = this.numerator * other.denominator + other.numerator * this.denominator;
|
|
872
|
-
const den = this.denominator * other.denominator;
|
|
873
|
-
return new _Fraction(num, den);
|
|
874
|
-
}
|
|
875
|
-
return this.add(_Fraction.fromNumber(Number(other.valueOf())));
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* Subtraction: a/b - c/d = (ad - bc) / bd
|
|
879
|
-
*/
|
|
880
|
-
subtract(other) {
|
|
881
|
-
if (other instanceof _Fraction) {
|
|
882
|
-
const num = this.numerator * other.denominator - other.numerator * this.denominator;
|
|
883
|
-
const den = this.denominator * other.denominator;
|
|
884
|
-
return new _Fraction(num, den);
|
|
885
|
-
}
|
|
886
|
-
return this.subtract(_Fraction.fromNumber(Number(other.valueOf())));
|
|
887
|
-
}
|
|
888
|
-
/**
|
|
889
|
-
* Multiplication: a/b * c/d = ac / bd
|
|
890
|
-
*/
|
|
891
|
-
multiply(other) {
|
|
892
|
-
if (other instanceof _Fraction) {
|
|
893
|
-
return new _Fraction(this.numerator * other.numerator, this.denominator * other.denominator);
|
|
894
|
-
}
|
|
895
|
-
return this.multiply(_Fraction.fromNumber(Number(other.valueOf())));
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Division: a/b ÷ c/d = ad / bc
|
|
899
|
-
*/
|
|
900
|
-
divide(other) {
|
|
901
|
-
if (other instanceof _Fraction) {
|
|
902
|
-
if (other.numerator === 0n) {
|
|
903
|
-
throw new Error("Division by zero");
|
|
904
|
-
}
|
|
905
|
-
return new _Fraction(this.numerator * other.denominator, this.denominator * other.numerator);
|
|
906
|
-
}
|
|
907
|
-
return this.divide(_Fraction.fromNumber(Number(other.valueOf())));
|
|
908
|
-
}
|
|
909
|
-
// Short-name aliases (mathjs Fraction API). Ported mathjs functions such as
|
|
910
|
-
// multiplyScalar/subtractScalar/divideScalar call x.mul/x.sub/x.div; without
|
|
911
|
-
// these, mixed number/Fraction dispatch (e.g. affine unit conversion like
|
|
912
|
-
// celsius→fahrenheit) threw "x.mul is not a function".
|
|
913
|
-
mul(other) {
|
|
914
|
-
return this.multiply(other);
|
|
915
|
-
}
|
|
916
|
-
sub(other) {
|
|
917
|
-
return this.subtract(other);
|
|
918
|
-
}
|
|
919
|
-
div(other) {
|
|
920
|
-
return this.divide(other);
|
|
921
|
-
}
|
|
922
|
-
/**
|
|
923
|
-
* Negation: -(a/b) = -a/b
|
|
924
|
-
*/
|
|
925
|
-
negate() {
|
|
926
|
-
return new _Fraction(-this.numerator, this.denominator);
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* Absolute value: |a/b|
|
|
930
|
-
*/
|
|
931
|
-
abs() {
|
|
932
|
-
return new _Fraction(this.numerator < 0n ? -this.numerator : this.numerator, this.denominator);
|
|
933
|
-
}
|
|
934
|
-
/**
|
|
935
|
-
* Reciprocal: b/a
|
|
936
|
-
*/
|
|
937
|
-
inverse() {
|
|
938
|
-
if (this.numerator === 0n) {
|
|
939
|
-
throw new Error("Cannot invert zero");
|
|
940
|
-
}
|
|
941
|
-
return new _Fraction(this.denominator, this.numerator);
|
|
942
|
-
}
|
|
943
|
-
/**
|
|
944
|
-
* Power (integer exponent)
|
|
945
|
-
*/
|
|
946
|
-
pow(n) {
|
|
947
|
-
const exp = typeof n === "bigint" ? n : BigInt(n);
|
|
948
|
-
if (exp === 0n) {
|
|
949
|
-
return new _Fraction(1n, 1n);
|
|
950
|
-
}
|
|
951
|
-
if (exp < 0n) {
|
|
952
|
-
return this.inverse().pow(-exp);
|
|
953
|
-
}
|
|
954
|
-
let result = new _Fraction(1n, 1n);
|
|
955
|
-
let base = this.clone();
|
|
956
|
-
let e = exp;
|
|
957
|
-
while (e > 0n) {
|
|
958
|
-
if (e % 2n === 1n) {
|
|
959
|
-
result = result.multiply(base);
|
|
960
|
-
}
|
|
961
|
-
base = base.multiply(base);
|
|
962
|
-
e = e / 2n;
|
|
963
|
-
}
|
|
964
|
-
return result;
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* Modulo operation
|
|
968
|
-
*/
|
|
969
|
-
mod(other) {
|
|
970
|
-
const quotient = this.divide(other);
|
|
971
|
-
const floorQuot = quotient.floor();
|
|
972
|
-
return this.subtract(other.multiply(floorQuot));
|
|
973
|
-
}
|
|
974
|
-
// ============================================================
|
|
975
|
-
// Comparison Methods
|
|
976
|
-
// ============================================================
|
|
977
|
-
/**
|
|
978
|
-
* Check equality
|
|
979
|
-
*/
|
|
980
|
-
equals(other) {
|
|
981
|
-
return this.numerator === other.numerator && this.denominator === other.denominator;
|
|
982
|
-
}
|
|
983
|
-
/**
|
|
984
|
-
* Check if less than
|
|
985
|
-
*/
|
|
986
|
-
lessThan(other) {
|
|
987
|
-
return _Fraction.compare(this, other) < 0;
|
|
988
|
-
}
|
|
989
|
-
/**
|
|
990
|
-
* Check if less than or equal
|
|
991
|
-
*/
|
|
992
|
-
lessThanOrEqual(other) {
|
|
993
|
-
return _Fraction.compare(this, other) <= 0;
|
|
994
|
-
}
|
|
995
|
-
/**
|
|
996
|
-
* Check if greater than
|
|
997
|
-
*/
|
|
998
|
-
greaterThan(other) {
|
|
999
|
-
return _Fraction.compare(this, other) > 0;
|
|
1000
|
-
}
|
|
1001
|
-
/**
|
|
1002
|
-
* Check if greater than or equal
|
|
1003
|
-
*/
|
|
1004
|
-
greaterThanOrEqual(other) {
|
|
1005
|
-
return _Fraction.compare(this, other) >= 0;
|
|
1006
|
-
}
|
|
1007
|
-
/**
|
|
1008
|
-
* Compare with another fraction
|
|
1009
|
-
* @returns -1, 0, or 1
|
|
1010
|
-
*/
|
|
1011
|
-
compareTo(other) {
|
|
1012
|
-
return _Fraction.compare(this, other);
|
|
1013
|
-
}
|
|
1014
|
-
compare(other) {
|
|
1015
|
-
return this.compareTo(other);
|
|
1016
|
-
}
|
|
1017
|
-
// ============================================================
|
|
1018
|
-
// Utility Methods
|
|
1019
|
-
// ============================================================
|
|
1020
|
-
/**
|
|
1021
|
-
* Return fraction already in lowest terms (no-op since constructor reduces)
|
|
1022
|
-
*/
|
|
1023
|
-
simplify() {
|
|
1024
|
-
return this;
|
|
1025
|
-
}
|
|
1026
|
-
/**
|
|
1027
|
-
* Check if this is zero
|
|
1028
|
-
*/
|
|
1029
|
-
isZero() {
|
|
1030
|
-
return this.numerator === 0n;
|
|
1031
|
-
}
|
|
1032
|
-
/**
|
|
1033
|
-
* Check if this is positive
|
|
1034
|
-
*/
|
|
1035
|
-
isPositive() {
|
|
1036
|
-
return this.numerator > 0n;
|
|
1037
|
-
}
|
|
1038
|
-
/**
|
|
1039
|
-
* Check if this is negative
|
|
1040
|
-
*/
|
|
1041
|
-
isNegative() {
|
|
1042
|
-
return this.numerator < 0n;
|
|
1043
|
-
}
|
|
1044
|
-
/**
|
|
1045
|
-
* Check if this is an integer
|
|
1046
|
-
*/
|
|
1047
|
-
isInteger() {
|
|
1048
|
-
return this.denominator === 1n;
|
|
1049
|
-
}
|
|
1050
|
-
/**
|
|
1051
|
-
* Check if this is a unit fraction (1/n)
|
|
1052
|
-
*/
|
|
1053
|
-
isUnit() {
|
|
1054
|
-
return this.numerator === 1n || this.numerator === -1n;
|
|
1055
|
-
}
|
|
1056
|
-
/**
|
|
1057
|
-
* Floor: largest integer ≤ this
|
|
1058
|
-
*/
|
|
1059
|
-
floor() {
|
|
1060
|
-
if (this.denominator === 1n) {
|
|
1061
|
-
return this;
|
|
1062
|
-
}
|
|
1063
|
-
const quot = this.numerator / this.denominator;
|
|
1064
|
-
if (this.numerator >= 0n || this.numerator % this.denominator === 0n) {
|
|
1065
|
-
return new _Fraction(quot, 1n);
|
|
1066
|
-
}
|
|
1067
|
-
return new _Fraction(quot - 1n, 1n);
|
|
1068
|
-
}
|
|
1069
|
-
/**
|
|
1070
|
-
* Ceiling: smallest integer ≥ this
|
|
1071
|
-
*/
|
|
1072
|
-
ceil() {
|
|
1073
|
-
if (this.denominator === 1n) {
|
|
1074
|
-
return this;
|
|
1075
|
-
}
|
|
1076
|
-
const quot = this.numerator / this.denominator;
|
|
1077
|
-
if (this.numerator <= 0n || this.numerator % this.denominator === 0n) {
|
|
1078
|
-
return new _Fraction(quot, 1n);
|
|
1079
|
-
}
|
|
1080
|
-
return new _Fraction(quot + 1n, 1n);
|
|
1081
|
-
}
|
|
1082
|
-
/**
|
|
1083
|
-
* Round to nearest integer
|
|
1084
|
-
*/
|
|
1085
|
-
round() {
|
|
1086
|
-
const floor = this.floor();
|
|
1087
|
-
const diff = this.subtract(floor);
|
|
1088
|
-
const half = new _Fraction(1n, 2n);
|
|
1089
|
-
if (diff.greaterThanOrEqual(half)) {
|
|
1090
|
-
return floor.add(new _Fraction(1n, 1n));
|
|
1091
|
-
}
|
|
1092
|
-
return floor;
|
|
1093
|
-
}
|
|
1094
|
-
/**
|
|
1095
|
-
* Truncate (round toward zero)
|
|
1096
|
-
*/
|
|
1097
|
-
trunc() {
|
|
1098
|
-
return new _Fraction(this.numerator / this.denominator, 1n);
|
|
1099
|
-
}
|
|
1100
|
-
/**
|
|
1101
|
-
* Get the sign: -1, 0, or 1
|
|
1102
|
-
*/
|
|
1103
|
-
sign() {
|
|
1104
|
-
if (this.numerator < 0n) return -1;
|
|
1105
|
-
if (this.numerator > 0n) return 1;
|
|
1106
|
-
return 0;
|
|
1107
|
-
}
|
|
1108
|
-
/**
|
|
1109
|
-
* Clone this fraction
|
|
1110
|
-
*/
|
|
1111
|
-
clone() {
|
|
1112
|
-
return new _Fraction(this.numerator, this.denominator);
|
|
1113
|
-
}
|
|
1114
|
-
/**
|
|
1115
|
-
* Get the GCD of numerator and denominator (always 1 since we reduce)
|
|
1116
|
-
*/
|
|
1117
|
-
gcd() {
|
|
1118
|
-
return 1n;
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* Get continued fraction representation
|
|
1122
|
-
*/
|
|
1123
|
-
toContinuedFraction() {
|
|
1124
|
-
const result = [];
|
|
1125
|
-
let num = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
1126
|
-
let den = this.denominator;
|
|
1127
|
-
while (den !== 0n) {
|
|
1128
|
-
result.push(num / den);
|
|
1129
|
-
const temp = num % den;
|
|
1130
|
-
num = den;
|
|
1131
|
-
den = temp;
|
|
1132
|
-
}
|
|
1133
|
-
if (this.numerator < 0n && result.length > 0) {
|
|
1134
|
-
result[0] = -result[0];
|
|
1135
|
-
}
|
|
1136
|
-
return result;
|
|
1137
|
-
}
|
|
1138
|
-
/**
|
|
1139
|
-
* Create fraction from continued fraction
|
|
1140
|
-
*/
|
|
1141
|
-
static fromContinuedFraction(cf) {
|
|
1142
|
-
if (cf.length === 0) {
|
|
1143
|
-
return new _Fraction(0n, 1n);
|
|
1144
|
-
}
|
|
1145
|
-
let num = cf[cf.length - 1];
|
|
1146
|
-
let den = 1n;
|
|
1147
|
-
for (let i = cf.length - 2; i >= 0; i--) {
|
|
1148
|
-
const temp = num;
|
|
1149
|
-
num = cf[i] * num + den;
|
|
1150
|
-
den = temp;
|
|
1151
|
-
}
|
|
1152
|
-
return new _Fraction(num, den);
|
|
1153
|
-
}
|
|
1154
|
-
/**
|
|
1155
|
-
* Mediant of two fractions: (a+c)/(b+d)
|
|
1156
|
-
* Used in Stern-Brocot tree and Farey sequences
|
|
1157
|
-
*/
|
|
1158
|
-
mediant(other) {
|
|
1159
|
-
return new _Fraction(this.numerator + other.numerator, this.denominator + other.denominator);
|
|
1160
|
-
}
|
|
1161
|
-
};
|
|
1162
|
-
var FRACTION_ZERO = new Fraction(0n, 1n);
|
|
1163
|
-
var FRACTION_ONE = new Fraction(1n, 1n);
|
|
1164
|
-
var FRACTION_NEG_ONE = new Fraction(-1n, 1n);
|
|
1165
|
-
var FRACTION_HALF = new Fraction(1n, 2n);
|
|
1166
|
-
var FRACTION_THIRD = new Fraction(1n, 3n);
|
|
1167
|
-
var FRACTION_QUARTER = new Fraction(1n, 4n);
|
|
1168
|
-
|
|
1169
|
-
// src/types/bignumber.ts
|
|
1170
|
-
function isBigNumber(value) {
|
|
1171
|
-
return value instanceof BigNumber;
|
|
1172
|
-
}
|
|
1173
|
-
var defaultConfig = {
|
|
1174
|
-
precision: 64,
|
|
1175
|
-
rounding: "halfUp",
|
|
1176
|
-
minExponent: -1e9,
|
|
1177
|
-
maxExponent: 1e9
|
|
1178
|
-
};
|
|
1179
|
-
var globalConfig = { ...defaultConfig };
|
|
1180
|
-
var BigNumber = class _BigNumber {
|
|
1181
|
-
type = "BigNumber";
|
|
1182
|
-
/**
|
|
1183
|
-
* Duck-typing marker for Decimal.js / mathjs formatter compatibility.
|
|
1184
|
-
* Allows external code that checks `obj.isBigNumber === true` to identify
|
|
1185
|
-
* this class without an `instanceof` check.
|
|
1186
|
-
*/
|
|
1187
|
-
isBigNumber = true;
|
|
1188
|
-
// Internal representation: sign * coefficient * 10^exponent
|
|
1189
|
-
_sign;
|
|
1190
|
-
_coefficient;
|
|
1191
|
-
// Absolute value, normalized
|
|
1192
|
-
_exponent;
|
|
1193
|
-
// Power of 10
|
|
1194
|
-
// Special values
|
|
1195
|
-
_isNaN = false;
|
|
1196
|
-
_isInfinite = false;
|
|
1197
|
-
constructor(sign, coefficient, exponent, isNaN2 = false, isInfinite = false) {
|
|
1198
|
-
this._sign = sign;
|
|
1199
|
-
this._coefficient = coefficient;
|
|
1200
|
-
this._exponent = exponent;
|
|
1201
|
-
this._isNaN = isNaN2;
|
|
1202
|
-
this._isInfinite = isInfinite;
|
|
1203
|
-
}
|
|
1204
|
-
// ============================================================
|
|
1205
|
-
// Static Factory Methods
|
|
1206
|
-
// ============================================================
|
|
1207
|
-
/**
|
|
1208
|
-
* Create a BigNumber from a number
|
|
1209
|
-
*/
|
|
1210
|
-
static fromNumber(n) {
|
|
1211
|
-
if (Number.isNaN(n)) {
|
|
1212
|
-
return new _BigNumber(0, 0n, 0, true, false);
|
|
1213
|
-
}
|
|
1214
|
-
if (!Number.isFinite(n)) {
|
|
1215
|
-
return new _BigNumber(n > 0 ? 1 : -1, 0n, 0, false, true);
|
|
1216
|
-
}
|
|
1217
|
-
if (n === 0) {
|
|
1218
|
-
return new _BigNumber(0, 0n, 0);
|
|
1219
|
-
}
|
|
1220
|
-
return _BigNumber.parse(n.toString());
|
|
1221
|
-
}
|
|
1222
|
-
/**
|
|
1223
|
-
* Create a BigNumber from a string
|
|
1224
|
-
*/
|
|
1225
|
-
static parse(str) {
|
|
1226
|
-
str = str.trim().toLowerCase();
|
|
1227
|
-
if (str === "nan") {
|
|
1228
|
-
return new _BigNumber(0, 0n, 0, true, false);
|
|
1229
|
-
}
|
|
1230
|
-
if (str === "infinity" || str === "+infinity") {
|
|
1231
|
-
return new _BigNumber(1, 0n, 0, false, true);
|
|
1232
|
-
}
|
|
1233
|
-
if (str === "-infinity") {
|
|
1234
|
-
return new _BigNumber(-1, 0n, 0, false, true);
|
|
1235
|
-
}
|
|
1236
|
-
let sign = 1;
|
|
1237
|
-
if (str.startsWith("-")) {
|
|
1238
|
-
sign = -1;
|
|
1239
|
-
str = str.slice(1);
|
|
1240
|
-
} else if (str.startsWith("+")) {
|
|
1241
|
-
str = str.slice(1);
|
|
1242
|
-
}
|
|
1243
|
-
let exponentPart = 0;
|
|
1244
|
-
const eIndex = str.indexOf("e");
|
|
1245
|
-
if (eIndex !== -1) {
|
|
1246
|
-
exponentPart = parseInt(str.slice(eIndex + 1), 10);
|
|
1247
|
-
str = str.slice(0, eIndex);
|
|
1248
|
-
}
|
|
1249
|
-
const dotIndex = str.indexOf(".");
|
|
1250
|
-
let coefficient;
|
|
1251
|
-
let decimalPlaces = 0;
|
|
1252
|
-
if (dotIndex !== -1) {
|
|
1253
|
-
coefficient = str.slice(0, dotIndex) + str.slice(dotIndex + 1);
|
|
1254
|
-
decimalPlaces = str.length - dotIndex - 1;
|
|
1255
|
-
} else {
|
|
1256
|
-
coefficient = str;
|
|
1257
|
-
}
|
|
1258
|
-
coefficient = coefficient.replace(/^0+/, "") || "0";
|
|
1259
|
-
if (coefficient === "0") {
|
|
1260
|
-
return new _BigNumber(0, 0n, 0);
|
|
1261
|
-
}
|
|
1262
|
-
let trailingZeros = 0;
|
|
1263
|
-
for (let i = coefficient.length - 1; i >= 0; i--) {
|
|
1264
|
-
if (coefficient[i] === "0") {
|
|
1265
|
-
trailingZeros++;
|
|
1266
|
-
} else {
|
|
1267
|
-
break;
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
if (trailingZeros > 0) {
|
|
1271
|
-
coefficient = coefficient.slice(0, -trailingZeros);
|
|
1272
|
-
}
|
|
1273
|
-
const finalExponent = exponentPart - decimalPlaces + trailingZeros;
|
|
1274
|
-
return new _BigNumber(sign, BigInt(coefficient), finalExponent);
|
|
1275
|
-
}
|
|
1276
|
-
/**
|
|
1277
|
-
* Create from bigint
|
|
1278
|
-
*/
|
|
1279
|
-
static fromBigInt(n) {
|
|
1280
|
-
if (n === 0n) {
|
|
1281
|
-
return new _BigNumber(0, 0n, 0);
|
|
1282
|
-
}
|
|
1283
|
-
const sign = n < 0n ? -1 : 1;
|
|
1284
|
-
let str = (n < 0n ? -n : n).toString();
|
|
1285
|
-
let trailingZeros = 0;
|
|
1286
|
-
for (let i = str.length - 1; i >= 0; i--) {
|
|
1287
|
-
if (str[i] === "0") {
|
|
1288
|
-
trailingZeros++;
|
|
1289
|
-
} else {
|
|
1290
|
-
break;
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
if (trailingZeros > 0) {
|
|
1294
|
-
str = str.slice(0, -trailingZeros);
|
|
1295
|
-
}
|
|
1296
|
-
return new _BigNumber(sign, BigInt(str), trailingZeros);
|
|
1297
|
-
}
|
|
1298
|
-
/**
|
|
1299
|
-
* Create a BigNumber from a JSON object
|
|
1300
|
-
*/
|
|
1301
|
-
static fromJSON(json) {
|
|
1302
|
-
return _BigNumber.parse(json.value);
|
|
1303
|
-
}
|
|
1304
|
-
/**
|
|
1305
|
-
* Get/set global configuration
|
|
1306
|
-
*/
|
|
1307
|
-
static config(newConfig) {
|
|
1308
|
-
if (newConfig) {
|
|
1309
|
-
globalConfig = { ...globalConfig, ...newConfig };
|
|
1310
|
-
}
|
|
1311
|
-
return { ...globalConfig };
|
|
1312
|
-
}
|
|
1313
|
-
/**
|
|
1314
|
-
* Reset configuration to defaults
|
|
1315
|
-
*/
|
|
1316
|
-
static resetConfig() {
|
|
1317
|
-
globalConfig = { ...defaultConfig };
|
|
1318
|
-
}
|
|
1319
|
-
/**
|
|
1320
|
-
* Compare two BigNumbers
|
|
1321
|
-
* @returns -1, 0, or 1
|
|
1322
|
-
*/
|
|
1323
|
-
static compare(a, b) {
|
|
1324
|
-
if (a._isNaN || b._isNaN) return NaN;
|
|
1325
|
-
if (a._isInfinite && b._isInfinite) {
|
|
1326
|
-
if (a._sign === b._sign) return 0;
|
|
1327
|
-
return a._sign > b._sign ? 1 : -1;
|
|
1328
|
-
}
|
|
1329
|
-
if (a._isInfinite) return a._sign;
|
|
1330
|
-
if (b._isInfinite) return -b._sign;
|
|
1331
|
-
if (a._sign === 0 && b._sign === 0) return 0;
|
|
1332
|
-
if (a._sign === 0) return -b._sign;
|
|
1333
|
-
if (b._sign === 0) return a._sign;
|
|
1334
|
-
if (a._sign !== b._sign) return a._sign > b._sign ? 1 : -1;
|
|
1335
|
-
const result = _BigNumber.compareMagnitude(a, b);
|
|
1336
|
-
return a._sign === 1 ? result : -result;
|
|
1337
|
-
}
|
|
1338
|
-
static compareMagnitude(a, b) {
|
|
1339
|
-
const aDigits = a._coefficient.toString();
|
|
1340
|
-
const bDigits = b._coefficient.toString();
|
|
1341
|
-
const aOrder = aDigits.length + a._exponent;
|
|
1342
|
-
const bOrder = bDigits.length + b._exponent;
|
|
1343
|
-
if (aOrder !== bOrder) {
|
|
1344
|
-
return aOrder > bOrder ? 1 : -1;
|
|
1345
|
-
}
|
|
1346
|
-
const aFull = aDigits + "0".repeat(Math.max(0, a._exponent));
|
|
1347
|
-
const bFull = bDigits + "0".repeat(Math.max(0, b._exponent));
|
|
1348
|
-
if (aFull === bFull) return 0;
|
|
1349
|
-
return aFull > bFull ? 1 : -1;
|
|
1350
|
-
}
|
|
1351
|
-
// ============================================================
|
|
1352
|
-
// Conversion Methods
|
|
1353
|
-
// ============================================================
|
|
1354
|
-
valueOf() {
|
|
1355
|
-
if (this._isNaN) return NaN;
|
|
1356
|
-
if (this._isInfinite) return this._sign === 1 ? Infinity : -Infinity;
|
|
1357
|
-
if (this._sign === 0) return 0;
|
|
1358
|
-
const str = this.toString();
|
|
1359
|
-
return parseFloat(str);
|
|
1360
|
-
}
|
|
1361
|
-
/**
|
|
1362
|
-
* Convert to a JS number.
|
|
1363
|
-
* Alias for `valueOf()` — provided for Decimal.js / mathjs formatter
|
|
1364
|
-
* duck-typing compatibility.
|
|
1365
|
-
*/
|
|
1366
|
-
toNumber() {
|
|
1367
|
-
return this.valueOf();
|
|
1368
|
-
}
|
|
1369
|
-
toString() {
|
|
1370
|
-
if (this._isNaN) return "NaN";
|
|
1371
|
-
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1372
|
-
if (this._sign === 0) return "0";
|
|
1373
|
-
const sign = this._sign === -1 ? "-" : "";
|
|
1374
|
-
const digits = this._coefficient.toString();
|
|
1375
|
-
if (this._exponent >= 0) {
|
|
1376
|
-
return sign + digits + "0".repeat(this._exponent);
|
|
1377
|
-
} else if (-this._exponent < digits.length) {
|
|
1378
|
-
const insertPos = digits.length + this._exponent;
|
|
1379
|
-
return sign + digits.slice(0, insertPos) + "." + digits.slice(insertPos);
|
|
1380
|
-
} else {
|
|
1381
|
-
return sign + "0." + "0".repeat(-this._exponent - digits.length) + digits;
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
toJSON() {
|
|
1385
|
-
return {
|
|
1386
|
-
mathjs: "BigNumber",
|
|
1387
|
-
value: this.toString()
|
|
1388
|
-
};
|
|
1389
|
-
}
|
|
1390
|
-
/**
|
|
1391
|
-
* Convert to fixed-point notation.
|
|
1392
|
-
*
|
|
1393
|
-
* When called with no argument (or `undefined`) returns the full fixed-point
|
|
1394
|
-
* string representation without rounding — matching Decimal.js semantics where
|
|
1395
|
-
* `toFixed()` is equivalent to a lossless fixed-point stringify.
|
|
1396
|
-
* When called with a non-negative integer `decimalPlaces`, rounds and formats
|
|
1397
|
-
* to exactly that many digits after the decimal point.
|
|
1398
|
-
*/
|
|
1399
|
-
toFixed(decimalPlaces) {
|
|
1400
|
-
if (decimalPlaces === void 0) {
|
|
1401
|
-
return this.toFixedInternal(void 0);
|
|
1402
|
-
}
|
|
1403
|
-
return this.round(decimalPlaces).toFixedInternal(decimalPlaces);
|
|
1404
|
-
}
|
|
1405
|
-
toFixedInternal(decimalPlaces) {
|
|
1406
|
-
if (this._isNaN) return "NaN";
|
|
1407
|
-
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1408
|
-
const dp = decimalPlaces ?? -1;
|
|
1409
|
-
const allDigits = dp < 0;
|
|
1410
|
-
if (this._sign === 0) return allDigits ? "0" : dp > 0 ? "0." + "0".repeat(dp) : "0";
|
|
1411
|
-
const sign = this._sign === -1 ? "-" : "";
|
|
1412
|
-
const digits = this._coefficient.toString();
|
|
1413
|
-
if (this._exponent >= 0) {
|
|
1414
|
-
const intPart = digits + "0".repeat(this._exponent);
|
|
1415
|
-
if (allDigits) return sign + intPart;
|
|
1416
|
-
return sign + intPart + (dp > 0 ? "." + "0".repeat(dp) : "");
|
|
1417
|
-
} else if (-this._exponent <= digits.length) {
|
|
1418
|
-
const insertPos = digits.length + this._exponent;
|
|
1419
|
-
const intPart = digits.slice(0, insertPos) || "0";
|
|
1420
|
-
const decPart = digits.slice(insertPos);
|
|
1421
|
-
if (allDigits) {
|
|
1422
|
-
return sign + intPart + (decPart.length > 0 ? "." + decPart : "");
|
|
1423
|
-
}
|
|
1424
|
-
let paddedDec = decPart;
|
|
1425
|
-
if (paddedDec.length < dp) {
|
|
1426
|
-
paddedDec += "0".repeat(dp - paddedDec.length);
|
|
1427
|
-
}
|
|
1428
|
-
return sign + intPart + (dp > 0 ? "." + paddedDec.slice(0, dp) : "");
|
|
1429
|
-
} else {
|
|
1430
|
-
const leadingZeros = -this._exponent - digits.length;
|
|
1431
|
-
const decPart = "0".repeat(leadingZeros) + digits;
|
|
1432
|
-
if (allDigits) {
|
|
1433
|
-
return sign + "0." + decPart;
|
|
1434
|
-
}
|
|
1435
|
-
let paddedDec = decPart;
|
|
1436
|
-
if (paddedDec.length < dp) {
|
|
1437
|
-
paddedDec += "0".repeat(dp - paddedDec.length);
|
|
1438
|
-
}
|
|
1439
|
-
return sign + "0" + (dp > 0 ? "." + paddedDec.slice(0, dp) : "");
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
/**
|
|
1443
|
-
* Convert to exponential notation
|
|
1444
|
-
*/
|
|
1445
|
-
toExponential(decimalPlaces) {
|
|
1446
|
-
if (this._isNaN) return "NaN";
|
|
1447
|
-
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1448
|
-
if (this._sign === 0) {
|
|
1449
|
-
const dp = decimalPlaces ?? 0;
|
|
1450
|
-
return dp > 0 ? "0." + "0".repeat(dp) + "e+0" : "0e+0";
|
|
1451
|
-
}
|
|
1452
|
-
const sign = this._sign === -1 ? "-" : "";
|
|
1453
|
-
const digits = this._coefficient.toString();
|
|
1454
|
-
const exp = digits.length - 1 + this._exponent;
|
|
1455
|
-
const expSign = exp >= 0 ? "+" : "";
|
|
1456
|
-
if (decimalPlaces === void 0) {
|
|
1457
|
-
if (digits.length === 1) {
|
|
1458
|
-
return `${sign}${digits}e${expSign}${exp}`;
|
|
1459
|
-
}
|
|
1460
|
-
return `${sign}${digits[0]}.${digits.slice(1)}e${expSign}${exp}`;
|
|
1461
|
-
}
|
|
1462
|
-
if (decimalPlaces === 0) {
|
|
1463
|
-
return `${sign}${digits[0]}e${expSign}${exp}`;
|
|
1464
|
-
}
|
|
1465
|
-
let decPart = digits.slice(1);
|
|
1466
|
-
if (decPart.length < decimalPlaces) {
|
|
1467
|
-
decPart += "0".repeat(decimalPlaces - decPart.length);
|
|
1468
|
-
} else {
|
|
1469
|
-
decPart = decPart.slice(0, decimalPlaces);
|
|
1470
|
-
}
|
|
1471
|
-
return `${sign}${digits[0]}.${decPart}e${expSign}${exp}`;
|
|
1472
|
-
}
|
|
1473
|
-
/**
|
|
1474
|
-
* Convert to precision
|
|
1475
|
-
*/
|
|
1476
|
-
toPrecision(significantDigits) {
|
|
1477
|
-
if (significantDigits === void 0) {
|
|
1478
|
-
return this.toString();
|
|
1479
|
-
}
|
|
1480
|
-
if (this._isNaN) return "NaN";
|
|
1481
|
-
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1482
|
-
if (this._sign === 0) {
|
|
1483
|
-
return significantDigits > 1 ? "0." + "0".repeat(significantDigits - 1) : "0";
|
|
1484
|
-
}
|
|
1485
|
-
const digits = this._coefficient.toString();
|
|
1486
|
-
const order = digits.length + this._exponent;
|
|
1487
|
-
if (order > significantDigits || order < -6) {
|
|
1488
|
-
return this.toExponential(significantDigits - 1);
|
|
1489
|
-
}
|
|
1490
|
-
return this.toFixed(significantDigits - order);
|
|
1491
|
-
}
|
|
1492
|
-
/**
|
|
1493
|
-
* Convert to bigint (truncated)
|
|
1494
|
-
*/
|
|
1495
|
-
toBigInt() {
|
|
1496
|
-
if (this._isNaN || this._isInfinite) {
|
|
1497
|
-
throw new Error("Cannot convert NaN or Infinity to bigint");
|
|
1498
|
-
}
|
|
1499
|
-
if (this._sign === 0) return 0n;
|
|
1500
|
-
const digits = this._coefficient.toString();
|
|
1501
|
-
if (this._exponent >= 0) {
|
|
1502
|
-
return BigInt(this._sign) * BigInt(digits + "0".repeat(this._exponent));
|
|
1503
|
-
} else if (-this._exponent < digits.length) {
|
|
1504
|
-
return BigInt(this._sign) * BigInt(digits.slice(0, digits.length + this._exponent));
|
|
1505
|
-
}
|
|
1506
|
-
return 0n;
|
|
1507
|
-
}
|
|
1508
|
-
/**
|
|
1509
|
-
* Binary string representation, e.g. `255 -> '0b11111111'`, `0.5 -> '0b0.1'`.
|
|
1510
|
-
* Mirrors Decimal.js `toBinary()`. Negatives carry a leading `-`.
|
|
1511
|
-
*/
|
|
1512
|
-
toBinary() {
|
|
1513
|
-
return this.toRadixString(2, "0b");
|
|
1514
|
-
}
|
|
1515
|
-
/**
|
|
1516
|
-
* Octal string representation, e.g. `8 -> '0o10'`.
|
|
1517
|
-
* Mirrors Decimal.js `toOctal()`.
|
|
1518
|
-
*/
|
|
1519
|
-
toOctal() {
|
|
1520
|
-
return this.toRadixString(8, "0o");
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* Hexadecimal string representation, e.g. `255 -> '0xff'`, `10.5 -> '0xa.8'`.
|
|
1524
|
-
* Mirrors Decimal.js `toHexadecimal()`.
|
|
1525
|
-
*/
|
|
1526
|
-
toHexadecimal() {
|
|
1527
|
-
return this.toRadixString(16, "0x");
|
|
1528
|
-
}
|
|
1529
|
-
/**
|
|
1530
|
-
* Shared radix formatter for {@link toBinary}/{@link toOctal}/{@link toHexadecimal}.
|
|
1531
|
-
* Integers and terminating fractions are exact; a non-terminating fraction is
|
|
1532
|
-
* truncated at `maxFractionDigits` radix digits (a safety bound — the common
|
|
1533
|
-
* use is integer formatting).
|
|
1534
|
-
*/
|
|
1535
|
-
toRadixString(radix, prefix, maxFractionDigits = 1100) {
|
|
1536
|
-
if (this._isNaN) return "NaN";
|
|
1537
|
-
if (this._isInfinite) return (this._sign < 0 ? "-" : "") + "Infinity";
|
|
1538
|
-
if (this._sign === 0) return prefix + "0";
|
|
1539
|
-
const negative = this._sign < 0;
|
|
1540
|
-
const absVal = this.abs();
|
|
1541
|
-
const intPart = absVal.toBigInt();
|
|
1542
|
-
let out = prefix + intPart.toString(radix);
|
|
1543
|
-
let frac = absVal.subtract(_BigNumber.fromBigInt(intPart));
|
|
1544
|
-
if (!frac.isZero()) {
|
|
1545
|
-
const radixBN = _BigNumber.fromNumber(radix);
|
|
1546
|
-
let digits = "";
|
|
1547
|
-
for (let i = 0; i < maxFractionDigits && !frac.isZero(); i++) {
|
|
1548
|
-
frac = frac.multiply(radixBN);
|
|
1549
|
-
const digit = frac.toBigInt();
|
|
1550
|
-
digits += Number(digit).toString(radix);
|
|
1551
|
-
frac = frac.subtract(_BigNumber.fromBigInt(digit));
|
|
1552
|
-
}
|
|
1553
|
-
out += "." + digits;
|
|
1554
|
-
}
|
|
1555
|
-
return (negative ? "-" : "") + out;
|
|
1556
|
-
}
|
|
1557
|
-
// ============================================================
|
|
1558
|
-
// Arithmetic Operations
|
|
1559
|
-
// ============================================================
|
|
1560
|
-
/**
|
|
1561
|
-
* Addition
|
|
1562
|
-
*/
|
|
1563
|
-
add(other) {
|
|
1564
|
-
const b = this.ensureBigNumber(other);
|
|
1565
|
-
if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1566
|
-
if (this._isInfinite && b._isInfinite) {
|
|
1567
|
-
if (this._sign === b._sign) return this;
|
|
1568
|
-
return new _BigNumber(0, 0n, 0, true);
|
|
1569
|
-
}
|
|
1570
|
-
if (this._isInfinite) return this;
|
|
1571
|
-
if (b._isInfinite) return b;
|
|
1572
|
-
if (this._sign === 0) return b;
|
|
1573
|
-
if (b._sign === 0) return this;
|
|
1574
|
-
const [aCoef, bCoef, exp] = this.alignExponents(this, b);
|
|
1575
|
-
if (this._sign === b._sign) {
|
|
1576
|
-
return this.normalize(this._sign, aCoef + bCoef, exp);
|
|
1577
|
-
} else {
|
|
1578
|
-
if (aCoef >= bCoef) {
|
|
1579
|
-
const diff = aCoef - bCoef;
|
|
1580
|
-
return this.normalize(diff === 0n ? 0 : this._sign, diff, exp);
|
|
1581
|
-
} else {
|
|
1582
|
-
return this.normalize(b._sign, bCoef - aCoef, exp);
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
/**
|
|
1587
|
-
* Subtraction
|
|
1588
|
-
*/
|
|
1589
|
-
subtract(other) {
|
|
1590
|
-
const b = this.ensureBigNumber(other);
|
|
1591
|
-
return this.add(b.negate());
|
|
1592
|
-
}
|
|
1593
|
-
/**
|
|
1594
|
-
* Alias for subtract — mathjs / Decimal.js compatibility.
|
|
1595
|
-
*/
|
|
1596
|
-
sub(other) {
|
|
1597
|
-
return this.subtract(other);
|
|
1598
|
-
}
|
|
1599
|
-
/**
|
|
1600
|
-
* Multiplication
|
|
1601
|
-
*/
|
|
1602
|
-
multiply(other) {
|
|
1603
|
-
const b = this.ensureBigNumber(other);
|
|
1604
|
-
if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1605
|
-
if (this._isInfinite || b._isInfinite) {
|
|
1606
|
-
if (this._sign === 0 || b._sign === 0) return new _BigNumber(0, 0n, 0, true);
|
|
1607
|
-
const sign2 = this._sign * b._sign;
|
|
1608
|
-
return new _BigNumber(sign2, 0n, 0, false, true);
|
|
1609
|
-
}
|
|
1610
|
-
if (this._sign === 0 || b._sign === 0) return new _BigNumber(0, 0n, 0);
|
|
1611
|
-
const sign = this._sign * b._sign;
|
|
1612
|
-
const coefficient = this._coefficient * b._coefficient;
|
|
1613
|
-
const exponent = this._exponent + b._exponent;
|
|
1614
|
-
return this.normalize(sign, coefficient, exponent);
|
|
1615
|
-
}
|
|
1616
|
-
/**
|
|
1617
|
-
* Alias for multiply — mathjs / Decimal.js compatibility.
|
|
1618
|
-
*/
|
|
1619
|
-
mul(other) {
|
|
1620
|
-
return this.multiply(other);
|
|
1621
|
-
}
|
|
1622
|
-
/**
|
|
1623
|
-
* Division
|
|
1624
|
-
*/
|
|
1625
|
-
divide(other) {
|
|
1626
|
-
const b = this.ensureBigNumber(other);
|
|
1627
|
-
if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1628
|
-
if (this._isInfinite && b._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1629
|
-
if (b._sign === 0) {
|
|
1630
|
-
if (this._sign === 0) return new _BigNumber(0, 0n, 0, true);
|
|
1631
|
-
return new _BigNumber(this._sign, 0n, 0, false, true);
|
|
1632
|
-
}
|
|
1633
|
-
if (this._isInfinite) {
|
|
1634
|
-
const sign2 = this._sign * b._sign;
|
|
1635
|
-
return new _BigNumber(sign2, 0n, 0, false, true);
|
|
1636
|
-
}
|
|
1637
|
-
if (b._isInfinite) return new _BigNumber(0, 0n, 0);
|
|
1638
|
-
if (this._sign === 0) return new _BigNumber(0, 0n, 0);
|
|
1639
|
-
const sign = this._sign * b._sign;
|
|
1640
|
-
const precision = globalConfig.precision;
|
|
1641
|
-
const scale = BigInt(10) ** BigInt(precision + 10);
|
|
1642
|
-
const scaledDividend = this._coefficient * scale;
|
|
1643
|
-
const quotient = scaledDividend / b._coefficient;
|
|
1644
|
-
const exponent = this._exponent - b._exponent - precision - 10;
|
|
1645
|
-
return this.normalize(sign, quotient, exponent).roundToPrecision(precision);
|
|
1646
|
-
}
|
|
1647
|
-
/**
|
|
1648
|
-
* Negation
|
|
1649
|
-
*/
|
|
1650
|
-
negate() {
|
|
1651
|
-
if (this._isNaN) return this;
|
|
1652
|
-
if (this._sign === 0) return this;
|
|
1653
|
-
const newSign = this._sign === 1 ? -1 : 1;
|
|
1654
|
-
return new _BigNumber(newSign, this._coefficient, this._exponent, false, this._isInfinite);
|
|
1655
|
-
}
|
|
1656
|
-
/**
|
|
1657
|
-
* Absolute value
|
|
1658
|
-
*/
|
|
1659
|
-
abs() {
|
|
1660
|
-
if (this._isNaN) return this;
|
|
1661
|
-
if (this._sign === 0) return this;
|
|
1662
|
-
return new _BigNumber(1, this._coefficient, this._exponent, false, this._isInfinite);
|
|
1663
|
-
}
|
|
1664
|
-
/**
|
|
1665
|
-
* Power (integer exponent)
|
|
1666
|
-
*/
|
|
1667
|
-
pow(n) {
|
|
1668
|
-
const exp = typeof n === "bigint" ? Number(n) : n;
|
|
1669
|
-
if (this._isNaN) return this;
|
|
1670
|
-
if (exp === 0) return _BigNumber.fromNumber(1);
|
|
1671
|
-
if (this._sign === 0) {
|
|
1672
|
-
if (exp < 0) return new _BigNumber(1, 0n, 0, false, true);
|
|
1673
|
-
return this;
|
|
1674
|
-
}
|
|
1675
|
-
if (exp < 0) {
|
|
1676
|
-
return _BigNumber.fromNumber(1).divide(this.pow(-exp));
|
|
1677
|
-
}
|
|
1678
|
-
let result = _BigNumber.fromNumber(1);
|
|
1679
|
-
let base = this.clone();
|
|
1680
|
-
let e = exp;
|
|
1681
|
-
while (e > 0) {
|
|
1682
|
-
if (e % 2 === 1) {
|
|
1683
|
-
result = result.multiply(base);
|
|
1684
|
-
}
|
|
1685
|
-
base = base.multiply(base);
|
|
1686
|
-
e = Math.floor(e / 2);
|
|
1687
|
-
}
|
|
1688
|
-
return result.roundToPrecision(globalConfig.precision);
|
|
1689
|
-
}
|
|
1690
|
-
/**
|
|
1691
|
-
* Square root
|
|
1692
|
-
*/
|
|
1693
|
-
sqrt() {
|
|
1694
|
-
if (this._isNaN) return this;
|
|
1695
|
-
if (this._sign === -1) return new _BigNumber(0, 0n, 0, true);
|
|
1696
|
-
if (this._sign === 0) return this;
|
|
1697
|
-
if (this._isInfinite) return this;
|
|
1698
|
-
const precision = globalConfig.precision;
|
|
1699
|
-
let guess = _BigNumber.fromNumber(Math.sqrt(this.valueOf()));
|
|
1700
|
-
for (let i = 0; i < 100; i++) {
|
|
1701
|
-
const newGuess = guess.add(this.divide(guess)).divide(_BigNumber.fromNumber(2));
|
|
1702
|
-
if (guess.subtract(newGuess).abs().compareTo(guess.multiply(_BigNumber.parse("1e-" + (precision + 5)))) <= 0) {
|
|
1703
|
-
return newGuess.roundToPrecision(precision);
|
|
1704
|
-
}
|
|
1705
|
-
guess = newGuess;
|
|
1706
|
-
}
|
|
1707
|
-
return guess.roundToPrecision(precision);
|
|
1708
|
-
}
|
|
1709
|
-
// ============================================================
|
|
1710
|
-
// Comparison Methods
|
|
1711
|
-
// ============================================================
|
|
1712
|
-
equals(other) {
|
|
1713
|
-
return _BigNumber.compare(this, other) === 0;
|
|
1714
|
-
}
|
|
1715
|
-
lessThan(other) {
|
|
1716
|
-
return _BigNumber.compare(this, other) < 0;
|
|
1717
|
-
}
|
|
1718
|
-
lessThanOrEqual(other) {
|
|
1719
|
-
return _BigNumber.compare(this, other) <= 0;
|
|
1720
|
-
}
|
|
1721
|
-
greaterThan(other) {
|
|
1722
|
-
return _BigNumber.compare(this, other) > 0;
|
|
1723
|
-
}
|
|
1724
|
-
greaterThanOrEqual(other) {
|
|
1725
|
-
return _BigNumber.compare(this, other) >= 0;
|
|
1726
|
-
}
|
|
1727
|
-
compareTo(other) {
|
|
1728
|
-
return _BigNumber.compare(this, other);
|
|
1729
|
-
}
|
|
1730
|
-
compare(other) {
|
|
1731
|
-
return this.compareTo(other);
|
|
1732
|
-
}
|
|
1733
|
-
/**
|
|
1734
|
-
* Returns true iff this > other.
|
|
1735
|
-
* Accepts the same argument types as `add`/`multiply` (BigNumber, number, or string).
|
|
1736
|
-
* Named `gt` for Decimal.js / mathjs formatter compatibility.
|
|
1737
|
-
*/
|
|
1738
|
-
gt(other) {
|
|
1739
|
-
return this.greaterThan(this.ensureBigNumber(other));
|
|
1740
|
-
}
|
|
1741
|
-
// ============================================================
|
|
1742
|
-
// Rounding Methods
|
|
1743
|
-
// ============================================================
|
|
1744
|
-
/**
|
|
1745
|
-
* Round to specified decimal places
|
|
1746
|
-
*/
|
|
1747
|
-
round(decimalPlaces = 0, mode = globalConfig.rounding) {
|
|
1748
|
-
if (this._isNaN || this._isInfinite || this._sign === 0) return this;
|
|
1749
|
-
const targetExp = -decimalPlaces;
|
|
1750
|
-
if (this._exponent >= targetExp) return this;
|
|
1751
|
-
const shift = targetExp - this._exponent;
|
|
1752
|
-
const divisor = BigInt(10) ** BigInt(shift);
|
|
1753
|
-
const quotient = this._coefficient / divisor;
|
|
1754
|
-
const remainder = this._coefficient % divisor;
|
|
1755
|
-
let rounded = quotient;
|
|
1756
|
-
const halfDivisor = divisor / 2n;
|
|
1757
|
-
const shouldRoundUp = this.shouldRound(remainder, halfDivisor, divisor, quotient, mode);
|
|
1758
|
-
if (shouldRoundUp) {
|
|
1759
|
-
rounded += 1n;
|
|
1760
|
-
}
|
|
1761
|
-
return this.normalize(rounded === 0n ? 0 : this._sign, rounded, targetExp);
|
|
1762
|
-
}
|
|
1763
|
-
shouldRound(remainder, halfDivisor, divisor, quotient, mode) {
|
|
1764
|
-
const isPositive = this._sign === 1;
|
|
1765
|
-
const isExactlyHalf = remainder === halfDivisor && divisor % 2n === 0n;
|
|
1766
|
-
const isMoreThanHalf = remainder > halfDivisor;
|
|
1767
|
-
switch (mode) {
|
|
1768
|
-
case "up":
|
|
1769
|
-
return remainder > 0n;
|
|
1770
|
-
case "down":
|
|
1771
|
-
return false;
|
|
1772
|
-
case "ceil":
|
|
1773
|
-
return isPositive && remainder > 0n;
|
|
1774
|
-
case "floor":
|
|
1775
|
-
return !isPositive && remainder > 0n;
|
|
1776
|
-
case "halfUp":
|
|
1777
|
-
return isMoreThanHalf || isExactlyHalf;
|
|
1778
|
-
case "halfDown":
|
|
1779
|
-
return isMoreThanHalf;
|
|
1780
|
-
case "halfEven":
|
|
1781
|
-
return isMoreThanHalf || isExactlyHalf && quotient % 2n !== 0n;
|
|
1782
|
-
case "halfCeil":
|
|
1783
|
-
return isMoreThanHalf || isExactlyHalf && isPositive;
|
|
1784
|
-
case "halfFloor":
|
|
1785
|
-
return isMoreThanHalf || isExactlyHalf && !isPositive;
|
|
1786
|
-
default:
|
|
1787
|
-
return isMoreThanHalf || isExactlyHalf;
|
|
1788
|
-
}
|
|
1789
|
-
}
|
|
1790
|
-
/**
|
|
1791
|
-
* Round to specified precision (significant digits)
|
|
1792
|
-
*/
|
|
1793
|
-
roundToPrecision(precision, mode = globalConfig.rounding) {
|
|
1794
|
-
if (this._isNaN || this._isInfinite || this._sign === 0) return this;
|
|
1795
|
-
const digits = this._coefficient.toString();
|
|
1796
|
-
if (digits.length <= precision) return this;
|
|
1797
|
-
const digitsToRemove = digits.length - precision;
|
|
1798
|
-
const divisor = BigInt(10) ** BigInt(digitsToRemove);
|
|
1799
|
-
const quotient = this._coefficient / divisor;
|
|
1800
|
-
const remainder = this._coefficient % divisor;
|
|
1801
|
-
const halfDivisor = divisor / 2n;
|
|
1802
|
-
let rounded = quotient;
|
|
1803
|
-
const shouldRoundUp = this.shouldRound(remainder, halfDivisor, divisor, quotient, mode);
|
|
1804
|
-
if (shouldRoundUp) {
|
|
1805
|
-
rounded += 1n;
|
|
1806
|
-
}
|
|
1807
|
-
const newExponent = this._exponent + digitsToRemove;
|
|
1808
|
-
return this.normalize(rounded === 0n ? 0 : this._sign, rounded, newExponent);
|
|
93
|
+
sub(o) {
|
|
94
|
+
return new _Dual(this.value - o.value, this.deriv - o.deriv);
|
|
1809
95
|
}
|
|
1810
|
-
|
|
1811
|
-
return this.
|
|
96
|
+
mul(o) {
|
|
97
|
+
return new _Dual(this.value * o.value, this.deriv * o.value + this.value * o.deriv);
|
|
1812
98
|
}
|
|
1813
|
-
|
|
1814
|
-
|
|
99
|
+
div(o) {
|
|
100
|
+
const d = (this.deriv * o.value - this.value * o.deriv) / (o.value * o.value);
|
|
101
|
+
return new _Dual(this.value / o.value, d);
|
|
1815
102
|
}
|
|
1816
|
-
|
|
1817
|
-
return this.
|
|
103
|
+
neg() {
|
|
104
|
+
return new _Dual(-this.value, -this.deriv);
|
|
1818
105
|
}
|
|
1819
|
-
/**
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
* an explicit `roundingMode` is supplied.
|
|
1823
|
-
*
|
|
1824
|
-
* Named `toSignificantDigits` for Decimal.js / mathjs formatter compatibility.
|
|
1825
|
-
* When `n` is undefined the value is returned unchanged (no rounding).
|
|
1826
|
-
*/
|
|
1827
|
-
toSignificantDigits(n, roundingMode) {
|
|
1828
|
-
if (n === void 0) return this.clone();
|
|
1829
|
-
return this.roundToPrecision(n, roundingMode ?? globalConfig.rounding);
|
|
106
|
+
/** Power with a constant real exponent: d(xᵏ) = k·xᵏ⁻¹·dx. */
|
|
107
|
+
powConst(k) {
|
|
108
|
+
return new _Dual(Math.pow(this.value, k), this.deriv * k * Math.pow(this.value, k - 1));
|
|
1830
109
|
}
|
|
1831
|
-
/**
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
* - `0.0123` → `-2` (first significant digit is at 10^-2)
|
|
1837
|
-
* - `100` → `2`
|
|
1838
|
-
* - `0.01` → `-2`
|
|
1839
|
-
* - `0` → `0` (by convention; `isZero()` can be used to distinguish)
|
|
1840
|
-
*
|
|
1841
|
-
* For special values (NaN, ±Infinity) returns 0 — callers check
|
|
1842
|
-
* `isFinite()` / `isNaN()` before using `.e`.
|
|
1843
|
-
*/
|
|
1844
|
-
get e() {
|
|
1845
|
-
if (this._isNaN || this._isInfinite || this._sign === 0) return 0;
|
|
1846
|
-
const d = this._coefficient.toString().length;
|
|
1847
|
-
return d - 1 + this._exponent;
|
|
110
|
+
/** General power a^b: d = a^b·(b'·ln a + b·a'/a). */
|
|
111
|
+
pow(o) {
|
|
112
|
+
const v = Math.pow(this.value, o.value);
|
|
113
|
+
const d = v * (o.deriv * Math.log(this.value) + o.value * this.deriv / this.value);
|
|
114
|
+
return new _Dual(v, d);
|
|
1848
115
|
}
|
|
1849
|
-
//
|
|
1850
|
-
//
|
|
1851
|
-
//
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
mod(other) {
|
|
1857
|
-
const b = this.ensureBigNumber(other);
|
|
1858
|
-
if (this._isNaN || b._isNaN || b._sign === 0) return new _BigNumber(0, 0n, 0, true);
|
|
1859
|
-
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1860
|
-
if (b._isInfinite) return this;
|
|
1861
|
-
if (this._sign === 0) return this;
|
|
1862
|
-
const quotient = this.divide(b).trunc();
|
|
1863
|
-
return this.subtract(b.multiply(quotient));
|
|
116
|
+
// --- elementary functions ------------------------------------------------
|
|
117
|
+
// Each applies the shared chain rule (value, deriv) ↦ (f(v), deriv·f′(v))
|
|
118
|
+
// using the canonical rule from `DUAL_UNARY_RULES`, so the scalar and tensor
|
|
119
|
+
// AD paths can never drift apart.
|
|
120
|
+
unary(rule) {
|
|
121
|
+
const y = rule.primal(this.value);
|
|
122
|
+
return new _Dual(y, this.deriv * rule.deriv(this.value, y));
|
|
1864
123
|
}
|
|
1865
|
-
// ============================================================
|
|
1866
|
-
// Trigonometric Functions
|
|
1867
|
-
// ============================================================
|
|
1868
|
-
/**
|
|
1869
|
-
* Sine of this BigNumber (in radians)
|
|
1870
|
-
* Uses Taylor series: sin(x) = x - x^3/3! + x^5/5! - ...
|
|
1871
|
-
*/
|
|
1872
124
|
sin() {
|
|
1873
|
-
|
|
1874
|
-
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1875
|
-
if (this._sign === 0) return this;
|
|
1876
|
-
const x = this._reduceAngle();
|
|
1877
|
-
return x._sinTaylor();
|
|
125
|
+
return this.unary(DUAL_UNARY_RULES.sin);
|
|
1878
126
|
}
|
|
1879
|
-
/**
|
|
1880
|
-
* Cosine of this BigNumber (in radians)
|
|
1881
|
-
* Uses Taylor series: cos(x) = 1 - x^2/2! + x^4/4! - ...
|
|
1882
|
-
*/
|
|
1883
127
|
cos() {
|
|
1884
|
-
|
|
1885
|
-
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1886
|
-
if (this._sign === 0) return _BigNumber.fromNumber(1);
|
|
1887
|
-
const x = this._reduceAngle();
|
|
1888
|
-
return x._cosTaylor();
|
|
128
|
+
return this.unary(DUAL_UNARY_RULES.cos);
|
|
1889
129
|
}
|
|
1890
|
-
/**
|
|
1891
|
-
* Tangent of this BigNumber (in radians)
|
|
1892
|
-
* tan(x) = sin(x) / cos(x)
|
|
1893
|
-
*/
|
|
1894
130
|
tan() {
|
|
1895
|
-
|
|
1896
|
-
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1897
|
-
if (this._sign === 0) return this;
|
|
1898
|
-
const x = this._reduceAngle();
|
|
1899
|
-
return x._sinTaylor().divide(x._cosTaylor());
|
|
131
|
+
return this.unary(DUAL_UNARY_RULES.tan);
|
|
1900
132
|
}
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
* Returns value in [-PI/2, PI/2]
|
|
1904
|
-
*/
|
|
1905
|
-
asin() {
|
|
1906
|
-
if (this._isNaN) return this;
|
|
1907
|
-
const one = _BigNumber.fromNumber(1);
|
|
1908
|
-
if (this.abs().compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
|
|
1909
|
-
if (this._sign === 0) return this;
|
|
1910
|
-
const xSquared = this.multiply(this);
|
|
1911
|
-
const denominator = one.subtract(xSquared).sqrt();
|
|
1912
|
-
if (denominator.isZero()) {
|
|
1913
|
-
return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
|
|
1914
|
-
}
|
|
1915
|
-
return this.divide(denominator).atan();
|
|
133
|
+
exp() {
|
|
134
|
+
return this.unary(DUAL_UNARY_RULES.exp);
|
|
1916
135
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
* Returns value in [0, PI]
|
|
1920
|
-
*/
|
|
1921
|
-
acos() {
|
|
1922
|
-
if (this._isNaN) return this;
|
|
1923
|
-
const one = _BigNumber.fromNumber(1);
|
|
1924
|
-
if (this.abs().compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
|
|
1925
|
-
return BIGNUMBER_PI.divide(2).subtract(this.asin());
|
|
136
|
+
log() {
|
|
137
|
+
return this.unary(DUAL_UNARY_RULES.log);
|
|
1926
138
|
}
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
* Returns value in (-PI/2, PI/2)
|
|
1930
|
-
* Uses Taylor series with argument reduction for convergence.
|
|
1931
|
-
*/
|
|
1932
|
-
atan() {
|
|
1933
|
-
if (this._isNaN) return this;
|
|
1934
|
-
if (this._sign === 0) return this;
|
|
1935
|
-
if (this._isInfinite) {
|
|
1936
|
-
return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
|
|
1937
|
-
}
|
|
1938
|
-
const one = _BigNumber.fromNumber(1);
|
|
1939
|
-
if (this.abs().compareTo(one) > 0) {
|
|
1940
|
-
const reciprocal = one.divide(this);
|
|
1941
|
-
const piHalf = BIGNUMBER_PI.divide(2);
|
|
1942
|
-
return this._sign === 1 ? piHalf.subtract(reciprocal.atan()) : piHalf.negate().subtract(reciprocal.atan());
|
|
1943
|
-
}
|
|
1944
|
-
const half = _BigNumber.fromNumber(0.5);
|
|
1945
|
-
if (this.abs().compareTo(half) > 0) {
|
|
1946
|
-
const xSq = this.multiply(this);
|
|
1947
|
-
const reduced = this.divide(one.add(one.add(xSq).sqrt()));
|
|
1948
|
-
return reduced.atan().multiply(_BigNumber.fromNumber(2));
|
|
1949
|
-
}
|
|
1950
|
-
return this._atanTaylor();
|
|
139
|
+
sqrt() {
|
|
140
|
+
return this.unary(DUAL_UNARY_RULES.sqrt);
|
|
1951
141
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
atan2(x) {
|
|
1958
|
-
if (this._isNaN || x._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1959
|
-
if (this._sign === 0 && x._sign === 0) return _BigNumber.fromNumber(0);
|
|
1960
|
-
if (x._sign === 0) {
|
|
1961
|
-
return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
|
|
1962
|
-
}
|
|
1963
|
-
const angle = this.divide(x).atan();
|
|
1964
|
-
if (x.isPositive()) {
|
|
1965
|
-
return angle;
|
|
1966
|
-
} else if (this.isNegative()) {
|
|
1967
|
-
return angle.subtract(BIGNUMBER_PI);
|
|
1968
|
-
} else {
|
|
1969
|
-
return angle.add(BIGNUMBER_PI);
|
|
1970
|
-
}
|
|
142
|
+
square() {
|
|
143
|
+
return this.unary(DUAL_UNARY_RULES.square);
|
|
144
|
+
}
|
|
145
|
+
abs() {
|
|
146
|
+
return this.unary(DUAL_UNARY_RULES.abs);
|
|
1971
147
|
}
|
|
1972
|
-
// ============================================================
|
|
1973
|
-
// Hyperbolic Functions
|
|
1974
|
-
// ============================================================
|
|
1975
|
-
/**
|
|
1976
|
-
* Hyperbolic sine: sinh(x) = (e^x - e^(-x)) / 2
|
|
1977
|
-
*/
|
|
1978
148
|
sinh() {
|
|
1979
|
-
|
|
1980
|
-
if (this._isInfinite) return this;
|
|
1981
|
-
if (this._sign === 0) return this;
|
|
1982
|
-
const ex = this.exp();
|
|
1983
|
-
const enx = this.negate().exp();
|
|
1984
|
-
return ex.subtract(enx).divide(_BigNumber.fromNumber(2));
|
|
149
|
+
return this.unary(DUAL_UNARY_RULES.sinh);
|
|
1985
150
|
}
|
|
1986
|
-
/**
|
|
1987
|
-
* Hyperbolic cosine: cosh(x) = (e^x + e^(-x)) / 2
|
|
1988
|
-
*/
|
|
1989
151
|
cosh() {
|
|
1990
|
-
|
|
1991
|
-
if (this._isInfinite) return new _BigNumber(1, 0n, 0, false, true);
|
|
1992
|
-
if (this._sign === 0) return _BigNumber.fromNumber(1);
|
|
1993
|
-
const ex = this.exp();
|
|
1994
|
-
const enx = this.negate().exp();
|
|
1995
|
-
return ex.add(enx).divide(_BigNumber.fromNumber(2));
|
|
152
|
+
return this.unary(DUAL_UNARY_RULES.cosh);
|
|
1996
153
|
}
|
|
1997
|
-
/**
|
|
1998
|
-
* Hyperbolic tangent: tanh(x) = sinh(x) / cosh(x)
|
|
1999
|
-
*/
|
|
2000
154
|
tanh() {
|
|
2001
|
-
|
|
2002
|
-
if (this._sign === 0) return this;
|
|
2003
|
-
if (this._isInfinite) return _BigNumber.fromNumber(this._sign);
|
|
2004
|
-
const ex = this.exp();
|
|
2005
|
-
const enx = this.negate().exp();
|
|
2006
|
-
return ex.subtract(enx).divide(ex.add(enx));
|
|
2007
|
-
}
|
|
2008
|
-
/**
|
|
2009
|
-
* Inverse hyperbolic sine: asinh(x) = ln(x + sqrt(x^2 + 1))
|
|
2010
|
-
*/
|
|
2011
|
-
asinh() {
|
|
2012
|
-
if (this._isNaN) return this;
|
|
2013
|
-
if (this._isInfinite) return this;
|
|
2014
|
-
if (this._sign === 0) return this;
|
|
2015
|
-
const one = _BigNumber.fromNumber(1);
|
|
2016
|
-
return this.add(this.multiply(this).add(one).sqrt()).ln();
|
|
2017
|
-
}
|
|
2018
|
-
/**
|
|
2019
|
-
* Inverse hyperbolic cosine: acosh(x) = ln(x + sqrt(x^2 - 1))
|
|
2020
|
-
* Domain: x >= 1
|
|
2021
|
-
*/
|
|
2022
|
-
acosh() {
|
|
2023
|
-
if (this._isNaN) return this;
|
|
2024
|
-
const one = _BigNumber.fromNumber(1);
|
|
2025
|
-
if (this.compareTo(one) < 0) return new _BigNumber(0, 0n, 0, true);
|
|
2026
|
-
if (this._isInfinite) return this;
|
|
2027
|
-
return this.add(this.multiply(this).subtract(one).sqrt()).ln();
|
|
2028
|
-
}
|
|
2029
|
-
/**
|
|
2030
|
-
* Inverse hyperbolic tangent: atanh(x) = 0.5 * ln((1+x)/(1-x))
|
|
2031
|
-
* Domain: -1 < x < 1
|
|
2032
|
-
*/
|
|
2033
|
-
atanh() {
|
|
2034
|
-
if (this._isNaN) return this;
|
|
2035
|
-
const one = _BigNumber.fromNumber(1);
|
|
2036
|
-
const absVal = this.abs();
|
|
2037
|
-
if (absVal.compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
|
|
2038
|
-
if (absVal.equals(one)) {
|
|
2039
|
-
return this._sign === 1 ? new _BigNumber(1, 0n, 0, false, true) : new _BigNumber(-1, 0n, 0, false, true);
|
|
2040
|
-
}
|
|
2041
|
-
if (this._sign === 0) return this;
|
|
2042
|
-
const half = _BigNumber.fromNumber(0.5);
|
|
2043
|
-
return one.add(this).divide(one.subtract(this)).ln().multiply(half);
|
|
2044
|
-
}
|
|
2045
|
-
// ============================================================
|
|
2046
|
-
// Transcendental Functions
|
|
2047
|
-
// ============================================================
|
|
2048
|
-
/**
|
|
2049
|
-
* Exponential function: e^x
|
|
2050
|
-
* Uses Taylor series: e^x = 1 + x + x^2/2! + x^3/3! + ...
|
|
2051
|
-
* With argument reduction: e^x = (e^(x/2^k))^(2^k) for faster convergence.
|
|
2052
|
-
*/
|
|
2053
|
-
exp() {
|
|
2054
|
-
if (this._isNaN) return this;
|
|
2055
|
-
if (this._sign === 0) return _BigNumber.fromNumber(1);
|
|
2056
|
-
if (this._isInfinite) {
|
|
2057
|
-
return this._sign === 1 ? this : _BigNumber.fromNumber(0);
|
|
2058
|
-
}
|
|
2059
|
-
const precision = globalConfig.precision;
|
|
2060
|
-
const val = Math.abs(this.valueOf());
|
|
2061
|
-
let k = 0;
|
|
2062
|
-
if (val > 0.5) {
|
|
2063
|
-
k = Math.ceil(Math.log2(val * 2));
|
|
2064
|
-
}
|
|
2065
|
-
const divisor = _BigNumber.fromNumber(2).pow(k);
|
|
2066
|
-
const reduced = this.divide(divisor);
|
|
2067
|
-
let sum = _BigNumber.fromNumber(1);
|
|
2068
|
-
let term = _BigNumber.fromNumber(1);
|
|
2069
|
-
const maxIter = precision + 20;
|
|
2070
|
-
for (let n = 1; n <= maxIter; n++) {
|
|
2071
|
-
term = term.multiply(reduced).divide(_BigNumber.fromNumber(n));
|
|
2072
|
-
const newSum = sum.add(term);
|
|
2073
|
-
if (sum.equals(newSum)) break;
|
|
2074
|
-
sum = newSum;
|
|
2075
|
-
}
|
|
2076
|
-
for (let i = 0; i < k; i++) {
|
|
2077
|
-
sum = sum.multiply(sum);
|
|
2078
|
-
}
|
|
2079
|
-
return sum.roundToPrecision(precision);
|
|
2080
|
-
}
|
|
2081
|
-
/**
|
|
2082
|
-
* Natural logarithm: ln(x)
|
|
2083
|
-
* Uses the AGM (arithmetic-geometric mean) method for fast convergence.
|
|
2084
|
-
* Fallback: series ln((1+y)/(1-y)) = 2*(y + y^3/3 + y^5/5 + ...) where y = (x-1)/(x+1)
|
|
2085
|
-
*/
|
|
2086
|
-
ln() {
|
|
2087
|
-
if (this._isNaN) return this;
|
|
2088
|
-
if (this._sign === -1) return new _BigNumber(0, 0n, 0, true);
|
|
2089
|
-
if (this._sign === 0) return new _BigNumber(-1, 0n, 0, false, true);
|
|
2090
|
-
if (this._isInfinite) return this;
|
|
2091
|
-
const one = _BigNumber.fromNumber(1);
|
|
2092
|
-
if (this.equals(one)) return _BigNumber.fromNumber(0);
|
|
2093
|
-
const precision = globalConfig.precision;
|
|
2094
|
-
let x = this.clone();
|
|
2095
|
-
let k = 0;
|
|
2096
|
-
const two = _BigNumber.fromNumber(2);
|
|
2097
|
-
const half = _BigNumber.fromNumber(0.5);
|
|
2098
|
-
while (x.compareTo(two) > 0) {
|
|
2099
|
-
x = x.divide(two);
|
|
2100
|
-
k++;
|
|
2101
|
-
}
|
|
2102
|
-
while (x.compareTo(half) < 0) {
|
|
2103
|
-
x = x.multiply(two);
|
|
2104
|
-
k--;
|
|
2105
|
-
}
|
|
2106
|
-
const y = x.subtract(one).divide(x.add(one));
|
|
2107
|
-
const ySq = y.multiply(y);
|
|
2108
|
-
let term = y;
|
|
2109
|
-
let sum = y;
|
|
2110
|
-
const maxIter = precision + 20;
|
|
2111
|
-
for (let n = 1; n <= maxIter; n++) {
|
|
2112
|
-
term = term.multiply(ySq);
|
|
2113
|
-
const contribution = term.divide(_BigNumber.fromNumber(2 * n + 1));
|
|
2114
|
-
const newSum = sum.add(contribution);
|
|
2115
|
-
if (sum.equals(newSum)) break;
|
|
2116
|
-
sum = newSum;
|
|
2117
|
-
}
|
|
2118
|
-
sum = sum.multiply(two);
|
|
2119
|
-
if (k !== 0) {
|
|
2120
|
-
sum = sum.add(BIGNUMBER_LN2.multiply(_BigNumber.fromNumber(k)));
|
|
2121
|
-
}
|
|
2122
|
-
return sum.roundToPrecision(precision);
|
|
2123
|
-
}
|
|
2124
|
-
/**
|
|
2125
|
-
* Base-10 logarithm: log10(x) = ln(x) / ln(10)
|
|
2126
|
-
*/
|
|
2127
|
-
log10() {
|
|
2128
|
-
return this.ln().divide(BIGNUMBER_LN10);
|
|
2129
|
-
}
|
|
2130
|
-
/**
|
|
2131
|
-
* Base-2 logarithm: log2(x) = ln(x) / ln(2)
|
|
2132
|
-
*/
|
|
2133
|
-
log2() {
|
|
2134
|
-
return this.ln().divide(BIGNUMBER_LN2);
|
|
2135
|
-
}
|
|
2136
|
-
/**
|
|
2137
|
-
* Cube root
|
|
2138
|
-
* Uses Newton-Raphson iteration.
|
|
2139
|
-
*/
|
|
2140
|
-
cbrt() {
|
|
2141
|
-
if (this._isNaN) return this;
|
|
2142
|
-
if (this._sign === 0) return this;
|
|
2143
|
-
if (this._isInfinite) return this;
|
|
2144
|
-
if (this._sign === -1) {
|
|
2145
|
-
return this.negate().cbrt().negate();
|
|
2146
|
-
}
|
|
2147
|
-
const precision = globalConfig.precision;
|
|
2148
|
-
const three = _BigNumber.fromNumber(3);
|
|
2149
|
-
let guess = _BigNumber.fromNumber(Math.cbrt(this.valueOf()));
|
|
2150
|
-
for (let i = 0; i < 100; i++) {
|
|
2151
|
-
const guessSquared = guess.multiply(guess);
|
|
2152
|
-
const newGuess = guess.multiply(_BigNumber.fromNumber(2)).add(this.divide(guessSquared)).divide(three);
|
|
2153
|
-
if (guess.subtract(newGuess).abs().compareTo(guess.abs().multiply(_BigNumber.parse("1e-" + (precision + 5)))) <= 0) {
|
|
2154
|
-
return newGuess.roundToPrecision(precision);
|
|
2155
|
-
}
|
|
2156
|
-
guess = newGuess;
|
|
2157
|
-
}
|
|
2158
|
-
return guess.roundToPrecision(precision);
|
|
2159
|
-
}
|
|
2160
|
-
/**
|
|
2161
|
-
* e^x - 1 (more precise than exp(x) - 1 for small x)
|
|
2162
|
-
* Uses Taylor series directly: expm1(x) = x + x^2/2! + x^3/3! + ...
|
|
2163
|
-
*/
|
|
2164
|
-
expm1() {
|
|
2165
|
-
if (this._isNaN) return this;
|
|
2166
|
-
if (this._sign === 0) return this;
|
|
2167
|
-
if (this._isInfinite) {
|
|
2168
|
-
return this._sign === 1 ? this : _BigNumber.fromNumber(-1);
|
|
2169
|
-
}
|
|
2170
|
-
if (Math.abs(this.valueOf()) > 0.5) {
|
|
2171
|
-
return this.exp().subtract(_BigNumber.fromNumber(1));
|
|
2172
|
-
}
|
|
2173
|
-
const precision = globalConfig.precision;
|
|
2174
|
-
let term = this.clone();
|
|
2175
|
-
let sum = this.clone();
|
|
2176
|
-
const maxIter = precision + 20;
|
|
2177
|
-
for (let n = 2; n <= maxIter; n++) {
|
|
2178
|
-
term = term.multiply(this).divide(_BigNumber.fromNumber(n));
|
|
2179
|
-
const newSum = sum.add(term);
|
|
2180
|
-
if (sum.equals(newSum)) break;
|
|
2181
|
-
sum = newSum;
|
|
2182
|
-
}
|
|
2183
|
-
return sum.roundToPrecision(precision);
|
|
2184
|
-
}
|
|
2185
|
-
/**
|
|
2186
|
-
* ln(1 + x) (more precise than ln(1 + x) for small x)
|
|
2187
|
-
*/
|
|
2188
|
-
log1p() {
|
|
2189
|
-
if (this._isNaN) return this;
|
|
2190
|
-
const one = _BigNumber.fromNumber(1);
|
|
2191
|
-
const negOne = _BigNumber.fromNumber(-1);
|
|
2192
|
-
if (this.compareTo(negOne) < 0) return new _BigNumber(0, 0n, 0, true);
|
|
2193
|
-
if (this.equals(negOne)) return new _BigNumber(-1, 0n, 0, false, true);
|
|
2194
|
-
if (this._sign === 0) return this;
|
|
2195
|
-
return one.add(this).ln();
|
|
2196
|
-
}
|
|
2197
|
-
/**
|
|
2198
|
-
* Hypotenuse: sqrt(this^2 + other^2)
|
|
2199
|
-
*/
|
|
2200
|
-
hypot(other) {
|
|
2201
|
-
if (this._isNaN || other._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
2202
|
-
if (this._isInfinite || other._isInfinite) return new _BigNumber(1, 0n, 0, false, true);
|
|
2203
|
-
return this.multiply(this).add(other.multiply(other)).sqrt();
|
|
2204
|
-
}
|
|
2205
|
-
// ============================================================
|
|
2206
|
-
// Private Taylor Series Helpers
|
|
2207
|
-
// ============================================================
|
|
2208
|
-
/** Reduce angle to [-PI, PI] range */
|
|
2209
|
-
_reduceAngle() {
|
|
2210
|
-
const twoPi = BIGNUMBER_PI.multiply(_BigNumber.fromNumber(2));
|
|
2211
|
-
if (this.abs().compareTo(BIGNUMBER_PI) <= 0) {
|
|
2212
|
-
return this;
|
|
2213
|
-
}
|
|
2214
|
-
const quotient = this.divide(twoPi).round(0, "halfUp");
|
|
2215
|
-
let reduced = this.subtract(twoPi.multiply(quotient));
|
|
2216
|
-
if (reduced.compareTo(BIGNUMBER_PI) > 0) {
|
|
2217
|
-
reduced = reduced.subtract(twoPi);
|
|
2218
|
-
} else if (reduced.compareTo(BIGNUMBER_PI.negate()) < 0) {
|
|
2219
|
-
reduced = reduced.add(twoPi);
|
|
2220
|
-
}
|
|
2221
|
-
return reduced;
|
|
2222
|
-
}
|
|
2223
|
-
/** Taylor series for sin(x), assumes x is in [-PI, PI] */
|
|
2224
|
-
_sinTaylor() {
|
|
2225
|
-
const precision = globalConfig.precision;
|
|
2226
|
-
let term = this.clone();
|
|
2227
|
-
let sum = this.clone();
|
|
2228
|
-
const xSquared = this.multiply(this);
|
|
2229
|
-
const maxIter = precision + 20;
|
|
2230
|
-
for (let n = 1; n <= maxIter; n++) {
|
|
2231
|
-
term = term.multiply(xSquared).divide(_BigNumber.fromNumber(2 * n * (2 * n + 1))).negate();
|
|
2232
|
-
const newSum = sum.add(term);
|
|
2233
|
-
if (sum.equals(newSum)) break;
|
|
2234
|
-
sum = newSum;
|
|
2235
|
-
}
|
|
2236
|
-
return sum.roundToPrecision(precision);
|
|
2237
|
-
}
|
|
2238
|
-
/** Taylor series for cos(x), assumes x is in [-PI, PI] */
|
|
2239
|
-
_cosTaylor() {
|
|
2240
|
-
const precision = globalConfig.precision;
|
|
2241
|
-
let term = _BigNumber.fromNumber(1);
|
|
2242
|
-
let sum = _BigNumber.fromNumber(1);
|
|
2243
|
-
const xSquared = this.multiply(this);
|
|
2244
|
-
const maxIter = precision + 20;
|
|
2245
|
-
for (let n = 1; n <= maxIter; n++) {
|
|
2246
|
-
term = term.multiply(xSquared).divide(_BigNumber.fromNumber((2 * n - 1) * (2 * n))).negate();
|
|
2247
|
-
const newSum = sum.add(term);
|
|
2248
|
-
if (sum.equals(newSum)) break;
|
|
2249
|
-
sum = newSum;
|
|
2250
|
-
}
|
|
2251
|
-
return sum.roundToPrecision(precision);
|
|
2252
|
-
}
|
|
2253
|
-
/** Taylor series for atan(x), assumes |x| <= 0.5 */
|
|
2254
|
-
_atanTaylor() {
|
|
2255
|
-
const precision = globalConfig.precision;
|
|
2256
|
-
const xSquared = this.multiply(this);
|
|
2257
|
-
let term = this.clone();
|
|
2258
|
-
let sum = this.clone();
|
|
2259
|
-
const maxIter = precision + 20;
|
|
2260
|
-
for (let n = 1; n <= maxIter; n++) {
|
|
2261
|
-
term = term.multiply(xSquared).negate();
|
|
2262
|
-
const contribution = term.divide(_BigNumber.fromNumber(2 * n + 1));
|
|
2263
|
-
const newSum = sum.add(contribution);
|
|
2264
|
-
if (sum.equals(newSum)) break;
|
|
2265
|
-
sum = newSum;
|
|
2266
|
-
}
|
|
2267
|
-
return sum.roundToPrecision(precision);
|
|
2268
|
-
}
|
|
2269
|
-
// ============================================================
|
|
2270
|
-
// Utility Methods
|
|
2271
|
-
// ============================================================
|
|
2272
|
-
isNaN() {
|
|
2273
|
-
return this._isNaN;
|
|
2274
|
-
}
|
|
2275
|
-
isFinite() {
|
|
2276
|
-
return !this._isNaN && !this._isInfinite;
|
|
2277
|
-
}
|
|
2278
|
-
isInfinite() {
|
|
2279
|
-
return this._isInfinite;
|
|
2280
|
-
}
|
|
2281
|
-
isZero() {
|
|
2282
|
-
return this._sign === 0 && !this._isNaN;
|
|
2283
|
-
}
|
|
2284
|
-
isPositive() {
|
|
2285
|
-
return this._sign === 1;
|
|
2286
|
-
}
|
|
2287
|
-
isNegative() {
|
|
2288
|
-
return this._sign === -1;
|
|
2289
|
-
}
|
|
2290
|
-
isInteger() {
|
|
2291
|
-
if (this._isNaN || this._isInfinite || this._sign === 0) return this._sign === 0;
|
|
2292
|
-
return this._exponent >= 0;
|
|
2293
|
-
}
|
|
2294
|
-
sign() {
|
|
2295
|
-
return this._sign;
|
|
2296
|
-
}
|
|
2297
|
-
clone() {
|
|
2298
|
-
return new _BigNumber(
|
|
2299
|
-
this._sign,
|
|
2300
|
-
this._coefficient,
|
|
2301
|
-
this._exponent,
|
|
2302
|
-
this._isNaN,
|
|
2303
|
-
this._isInfinite
|
|
2304
|
-
);
|
|
2305
|
-
}
|
|
2306
|
-
// ============================================================
|
|
2307
|
-
// Private Helper Methods
|
|
2308
|
-
// ============================================================
|
|
2309
|
-
ensureBigNumber(value) {
|
|
2310
|
-
if (value instanceof _BigNumber) return value;
|
|
2311
|
-
if (typeof value === "number") return _BigNumber.fromNumber(value);
|
|
2312
|
-
if (typeof value === "string") return _BigNumber.parse(value);
|
|
2313
|
-
return _BigNumber.fromNumber(Number(value.valueOf()));
|
|
2314
|
-
}
|
|
2315
|
-
alignExponents(a, b) {
|
|
2316
|
-
const minExp = Math.min(a._exponent, b._exponent);
|
|
2317
|
-
const aShift = a._exponent - minExp;
|
|
2318
|
-
const bShift = b._exponent - minExp;
|
|
2319
|
-
const aCoef = aShift > 0 ? a._coefficient * BigInt(10) ** BigInt(aShift) : a._coefficient;
|
|
2320
|
-
const bCoef = bShift > 0 ? b._coefficient * BigInt(10) ** BigInt(bShift) : b._coefficient;
|
|
2321
|
-
return [aCoef, bCoef, minExp];
|
|
155
|
+
return this.unary(DUAL_UNARY_RULES.tanh);
|
|
2322
156
|
}
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
return new _BigNumber(0, 0n, 0);
|
|
2326
|
-
}
|
|
2327
|
-
let coef = coefficient;
|
|
2328
|
-
let exp = exponent;
|
|
2329
|
-
while (coef % 10n === 0n && coef !== 0n) {
|
|
2330
|
-
coef = coef / 10n;
|
|
2331
|
-
exp++;
|
|
2332
|
-
}
|
|
2333
|
-
return new _BigNumber(sign, coef, exp);
|
|
157
|
+
toString() {
|
|
158
|
+
return `Dual(${this.value}, ${this.deriv})`;
|
|
2334
159
|
}
|
|
2335
160
|
};
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
var
|
|
2342
|
-
var
|
|
2343
|
-
|
|
2344
|
-
);
|
|
2345
|
-
var
|
|
2346
|
-
|
|
2347
|
-
|
|
161
|
+
function isDual(x) {
|
|
162
|
+
return x instanceof Dual;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/constants.ts
|
|
166
|
+
var PI = Math.PI;
|
|
167
|
+
var E = Math.E;
|
|
168
|
+
var TAU = 2 * Math.PI;
|
|
169
|
+
var PHI = (1 + Math.sqrt(5)) / 2;
|
|
170
|
+
var SQRT2 = Math.SQRT2;
|
|
171
|
+
var SQRT1_2 = Math.SQRT1_2;
|
|
172
|
+
var LN2 = Math.LN2;
|
|
173
|
+
var LN10 = Math.LN10;
|
|
174
|
+
var LOG2E = Math.LOG2E;
|
|
175
|
+
var LOG10E = Math.LOG10E;
|
|
2348
176
|
|
|
2349
177
|
// src/types/unit-definitions.ts
|
|
2350
178
|
var DIMENSIONLESS = Object.freeze({
|
|
@@ -2574,449 +402,6 @@ function getPrefix(name) {
|
|
|
2574
402
|
return SI_PREFIXES[name];
|
|
2575
403
|
}
|
|
2576
404
|
|
|
2577
|
-
// src/types/unit.ts
|
|
2578
|
-
var DimensionMismatchError = class extends Error {
|
|
2579
|
-
constructor(left, right, op) {
|
|
2580
|
-
super(
|
|
2581
|
-
`Dimension mismatch in ${op}: ${formatDimensions(left)} vs ${formatDimensions(right)}`
|
|
2582
|
-
);
|
|
2583
|
-
this.left = left;
|
|
2584
|
-
this.right = right;
|
|
2585
|
-
}
|
|
2586
|
-
left;
|
|
2587
|
-
right;
|
|
2588
|
-
name = "DimensionMismatchError";
|
|
2589
|
-
};
|
|
2590
|
-
var UnitParseError = class extends Error {
|
|
2591
|
-
name = "UnitParseError";
|
|
2592
|
-
constructor(notation, reason) {
|
|
2593
|
-
super(`Cannot parse unit notation "${notation}": ${reason}`);
|
|
2594
|
-
}
|
|
2595
|
-
};
|
|
2596
|
-
var DIM_KEYS = [
|
|
2597
|
-
"length",
|
|
2598
|
-
"mass",
|
|
2599
|
-
"time",
|
|
2600
|
-
"current",
|
|
2601
|
-
"temperature",
|
|
2602
|
-
"amount",
|
|
2603
|
-
"luminosity"
|
|
2604
|
-
];
|
|
2605
|
-
function dimsEqual(a, b) {
|
|
2606
|
-
for (const k of DIM_KEYS) {
|
|
2607
|
-
if (a[k] !== b[k]) return false;
|
|
2608
|
-
}
|
|
2609
|
-
return true;
|
|
2610
|
-
}
|
|
2611
|
-
function dimsAdd(a, b) {
|
|
2612
|
-
return {
|
|
2613
|
-
length: a.length + b.length,
|
|
2614
|
-
mass: a.mass + b.mass,
|
|
2615
|
-
time: a.time + b.time,
|
|
2616
|
-
current: a.current + b.current,
|
|
2617
|
-
temperature: a.temperature + b.temperature,
|
|
2618
|
-
amount: a.amount + b.amount,
|
|
2619
|
-
luminosity: a.luminosity + b.luminosity
|
|
2620
|
-
};
|
|
2621
|
-
}
|
|
2622
|
-
function dimsSub(a, b) {
|
|
2623
|
-
return {
|
|
2624
|
-
length: a.length - b.length,
|
|
2625
|
-
mass: a.mass - b.mass,
|
|
2626
|
-
time: a.time - b.time,
|
|
2627
|
-
current: a.current - b.current,
|
|
2628
|
-
temperature: a.temperature - b.temperature,
|
|
2629
|
-
amount: a.amount - b.amount,
|
|
2630
|
-
luminosity: a.luminosity - b.luminosity
|
|
2631
|
-
};
|
|
2632
|
-
}
|
|
2633
|
-
function dimsScale(a, n) {
|
|
2634
|
-
return {
|
|
2635
|
-
length: a.length * n,
|
|
2636
|
-
mass: a.mass * n,
|
|
2637
|
-
time: a.time * n,
|
|
2638
|
-
current: a.current * n,
|
|
2639
|
-
temperature: a.temperature * n,
|
|
2640
|
-
amount: a.amount * n,
|
|
2641
|
-
luminosity: a.luminosity * n
|
|
2642
|
-
};
|
|
2643
|
-
}
|
|
2644
|
-
function isDimensionless(d) {
|
|
2645
|
-
return dimsEqual(d, DIMENSIONLESS);
|
|
2646
|
-
}
|
|
2647
|
-
function formatDimensions(d) {
|
|
2648
|
-
const parts = [];
|
|
2649
|
-
for (const k of DIM_KEYS) {
|
|
2650
|
-
const e = d[k];
|
|
2651
|
-
if (e !== 0) parts.push(`${k}^${e}`);
|
|
2652
|
-
}
|
|
2653
|
-
return parts.length === 0 ? "dimensionless" : parts.join("\xB7");
|
|
2654
|
-
}
|
|
2655
|
-
function resolveAtom(token) {
|
|
2656
|
-
const aliased = UNIT_ALIASES[token] ?? token;
|
|
2657
|
-
const direct = getUnitDef(aliased);
|
|
2658
|
-
if (direct) {
|
|
2659
|
-
return {
|
|
2660
|
-
multiplier: direct.multiplier,
|
|
2661
|
-
offset: direct.offset ?? 0,
|
|
2662
|
-
dimensions: direct.dimensions,
|
|
2663
|
-
prefix: "",
|
|
2664
|
-
base: aliased
|
|
2665
|
-
};
|
|
2666
|
-
}
|
|
2667
|
-
for (const prefix of SI_PREFIX_KEYS) {
|
|
2668
|
-
if (!aliased.startsWith(prefix) || aliased.length === prefix.length) continue;
|
|
2669
|
-
const rest = aliased.slice(prefix.length);
|
|
2670
|
-
const baseDef = getUnitDef(rest);
|
|
2671
|
-
if (!baseDef) continue;
|
|
2672
|
-
if (!baseDef.prefixable) continue;
|
|
2673
|
-
return {
|
|
2674
|
-
multiplier: baseDef.multiplier * SI_PREFIXES[prefix],
|
|
2675
|
-
// Offset is in base units, so prefix the multiplier but not the offset
|
|
2676
|
-
// (we never apply prefixes to temperature units in practice anyway).
|
|
2677
|
-
offset: baseDef.offset ?? 0,
|
|
2678
|
-
dimensions: baseDef.dimensions,
|
|
2679
|
-
prefix,
|
|
2680
|
-
base: rest
|
|
2681
|
-
};
|
|
2682
|
-
}
|
|
2683
|
-
throw new UnitParseError(token, `unknown unit "${token}"`);
|
|
2684
|
-
}
|
|
2685
|
-
function splitScalar(input) {
|
|
2686
|
-
const m = input.match(/^\s*([+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\s+(.*)$/);
|
|
2687
|
-
if (m) {
|
|
2688
|
-
return { scalar: parseFloat(m[1]), rest: m[2].trim() };
|
|
2689
|
-
}
|
|
2690
|
-
const scalarOnly = input.match(/^\s*([+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\s*$/);
|
|
2691
|
-
if (scalarOnly) {
|
|
2692
|
-
return { scalar: parseFloat(scalarOnly[1]), rest: "" };
|
|
2693
|
-
}
|
|
2694
|
-
return { scalar: 1, rest: input.trim() };
|
|
2695
|
-
}
|
|
2696
|
-
function parseUnitExpr(expr) {
|
|
2697
|
-
if (expr === "" || expr === "1") return [];
|
|
2698
|
-
const normalized = expr.replace(/[·⋅]/g, "*");
|
|
2699
|
-
const atoms = [];
|
|
2700
|
-
let pos = 0;
|
|
2701
|
-
let nextSign = 1;
|
|
2702
|
-
while (pos < normalized.length) {
|
|
2703
|
-
while (pos < normalized.length && /\s/.test(normalized[pos])) pos++;
|
|
2704
|
-
if (pos >= normalized.length) break;
|
|
2705
|
-
const ch = normalized[pos];
|
|
2706
|
-
if (ch === "*") {
|
|
2707
|
-
pos++;
|
|
2708
|
-
continue;
|
|
2709
|
-
}
|
|
2710
|
-
if (ch === "/") {
|
|
2711
|
-
nextSign = -1;
|
|
2712
|
-
pos++;
|
|
2713
|
-
continue;
|
|
2714
|
-
}
|
|
2715
|
-
if (ch === "1") {
|
|
2716
|
-
const next = normalized[pos + 1];
|
|
2717
|
-
if (next === void 0 || next === " " || next === "/" || next === "*") {
|
|
2718
|
-
pos++;
|
|
2719
|
-
continue;
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
if (!/[A-Za-z°µΩ]/.test(ch)) {
|
|
2723
|
-
throw new UnitParseError(expr, `unexpected character "${ch}" at position ${pos}`);
|
|
2724
|
-
}
|
|
2725
|
-
const idStart = pos;
|
|
2726
|
-
while (pos < normalized.length && /[A-Za-z°µΩ]/.test(normalized[pos])) pos++;
|
|
2727
|
-
const identifier = normalized.slice(idStart, pos);
|
|
2728
|
-
let exponent = 1;
|
|
2729
|
-
if (pos < normalized.length && normalized[pos] === "^") {
|
|
2730
|
-
pos++;
|
|
2731
|
-
const expMatch = normalized.slice(pos).match(/^([+-]?\d+(?:\.\d+)?)/);
|
|
2732
|
-
if (!expMatch) {
|
|
2733
|
-
throw new UnitParseError(expr, `expected exponent after "^" at position ${pos}`);
|
|
2734
|
-
}
|
|
2735
|
-
exponent = parseFloat(expMatch[1]);
|
|
2736
|
-
pos += expMatch[1].length;
|
|
2737
|
-
} else {
|
|
2738
|
-
const supMatch = normalized.slice(pos).match(/^([²³⁴⁵⁶⁷⁸⁹⁰¹]+)/);
|
|
2739
|
-
if (supMatch) {
|
|
2740
|
-
exponent = parseSuperscript(supMatch[1]);
|
|
2741
|
-
pos += supMatch[1].length;
|
|
2742
|
-
}
|
|
2743
|
-
}
|
|
2744
|
-
const resolved = resolveAtom(identifier);
|
|
2745
|
-
atoms.push({
|
|
2746
|
-
multiplier: resolved.multiplier,
|
|
2747
|
-
offset: resolved.offset,
|
|
2748
|
-
dimensions: resolved.dimensions,
|
|
2749
|
-
exponent: nextSign * exponent,
|
|
2750
|
-
source: identifier
|
|
2751
|
-
});
|
|
2752
|
-
nextSign = 1;
|
|
2753
|
-
}
|
|
2754
|
-
return atoms;
|
|
2755
|
-
}
|
|
2756
|
-
var SUPERSCRIPT_MAP = {
|
|
2757
|
-
"\u2070": "0",
|
|
2758
|
-
"\xB9": "1",
|
|
2759
|
-
"\xB2": "2",
|
|
2760
|
-
"\xB3": "3",
|
|
2761
|
-
"\u2074": "4",
|
|
2762
|
-
"\u2075": "5",
|
|
2763
|
-
"\u2076": "6",
|
|
2764
|
-
"\u2077": "7",
|
|
2765
|
-
"\u2078": "8",
|
|
2766
|
-
"\u2079": "9"
|
|
2767
|
-
};
|
|
2768
|
-
function parseSuperscript(s) {
|
|
2769
|
-
let out = "";
|
|
2770
|
-
for (const ch of s) out += SUPERSCRIPT_MAP[ch] ?? ch;
|
|
2771
|
-
return parseInt(out, 10);
|
|
2772
|
-
}
|
|
2773
|
-
function parse(input) {
|
|
2774
|
-
const { scalar, rest } = splitScalar(input);
|
|
2775
|
-
return { scalar, atoms: parseUnitExpr(rest) };
|
|
2776
|
-
}
|
|
2777
|
-
var Unit = class _Unit {
|
|
2778
|
-
/** Discriminator (matches the prototype-flag convention). */
|
|
2779
|
-
type = "Unit";
|
|
2780
|
-
/** Used by `isUnit()` and typed-function dispatch. */
|
|
2781
|
-
isUnit = true;
|
|
2782
|
-
/** Numeric magnitude in **SI base units**. */
|
|
2783
|
-
value;
|
|
2784
|
-
/** Dimensional signature. */
|
|
2785
|
-
dimensions;
|
|
2786
|
-
/** Original notation string, preserved for `toString()` round-trip. */
|
|
2787
|
-
notation;
|
|
2788
|
-
constructor(value, notationOrDims, notation) {
|
|
2789
|
-
if (typeof notationOrDims === "string") {
|
|
2790
|
-
const parsed = parse(notationOrDims);
|
|
2791
|
-
const composed = composeAtoms(parsed.atoms);
|
|
2792
|
-
const inputValue = parsed.scalar * value;
|
|
2793
|
-
let canonical;
|
|
2794
|
-
if (parsed.atoms.length === 1 && parsed.atoms[0].exponent === 1) {
|
|
2795
|
-
const a = parsed.atoms[0];
|
|
2796
|
-
canonical = inputValue * a.multiplier + a.offset;
|
|
2797
|
-
} else {
|
|
2798
|
-
canonical = inputValue * composed.multiplier;
|
|
2799
|
-
}
|
|
2800
|
-
this.value = canonical;
|
|
2801
|
-
this.dimensions = composed.dimensions;
|
|
2802
|
-
this.notation = notationOrDims;
|
|
2803
|
-
} else {
|
|
2804
|
-
this.value = value;
|
|
2805
|
-
this.dimensions = notationOrDims;
|
|
2806
|
-
this.notation = notation ?? "";
|
|
2807
|
-
}
|
|
2808
|
-
}
|
|
2809
|
-
// -------------------------------------------------------------------------
|
|
2810
|
-
// Arithmetic
|
|
2811
|
-
// -------------------------------------------------------------------------
|
|
2812
|
-
/**
|
|
2813
|
-
* Add two units. Requires identical dimensions.
|
|
2814
|
-
*
|
|
2815
|
-
* @throws {DimensionMismatchError} if dimensions differ.
|
|
2816
|
-
*/
|
|
2817
|
-
add(other) {
|
|
2818
|
-
if (!dimsEqual(this.dimensions, other.dimensions)) {
|
|
2819
|
-
throw new DimensionMismatchError(this.dimensions, other.dimensions, "add");
|
|
2820
|
-
}
|
|
2821
|
-
return new _Unit(this.value + other.value, this.dimensions, this.notation);
|
|
2822
|
-
}
|
|
2823
|
-
/**
|
|
2824
|
-
* Subtract two units. Requires identical dimensions.
|
|
2825
|
-
*
|
|
2826
|
-
* @throws {DimensionMismatchError} if dimensions differ.
|
|
2827
|
-
*/
|
|
2828
|
-
sub(other) {
|
|
2829
|
-
if (!dimsEqual(this.dimensions, other.dimensions)) {
|
|
2830
|
-
throw new DimensionMismatchError(this.dimensions, other.dimensions, "sub");
|
|
2831
|
-
}
|
|
2832
|
-
return new _Unit(this.value - other.value, this.dimensions, this.notation);
|
|
2833
|
-
}
|
|
2834
|
-
/**
|
|
2835
|
-
* Multiply by another unit or a scalar. Dimensions add when multiplying by
|
|
2836
|
-
* another unit; unchanged when multiplying by a scalar.
|
|
2837
|
-
*/
|
|
2838
|
-
mul(other) {
|
|
2839
|
-
if (typeof other === "number") {
|
|
2840
|
-
return new _Unit(this.value * other, this.dimensions, this.notation);
|
|
2841
|
-
}
|
|
2842
|
-
return new _Unit(
|
|
2843
|
-
this.value * other.value,
|
|
2844
|
-
dimsAdd(this.dimensions, other.dimensions),
|
|
2845
|
-
composeNotation(this.notation, other.notation, "*")
|
|
2846
|
-
);
|
|
2847
|
-
}
|
|
2848
|
-
/**
|
|
2849
|
-
* Divide by another unit or a scalar. Dimensions subtract when dividing by
|
|
2850
|
-
* another unit; unchanged when dividing by a scalar.
|
|
2851
|
-
*/
|
|
2852
|
-
div(other) {
|
|
2853
|
-
if (typeof other === "number") {
|
|
2854
|
-
return new _Unit(this.value / other, this.dimensions, this.notation);
|
|
2855
|
-
}
|
|
2856
|
-
return new _Unit(
|
|
2857
|
-
this.value / other.value,
|
|
2858
|
-
dimsSub(this.dimensions, other.dimensions),
|
|
2859
|
-
composeNotation(this.notation, other.notation, "/")
|
|
2860
|
-
);
|
|
2861
|
-
}
|
|
2862
|
-
/**
|
|
2863
|
-
* Raise to an integer or rational power. Dimensions scale by `n`.
|
|
2864
|
-
*/
|
|
2865
|
-
pow(n) {
|
|
2866
|
-
return new _Unit(
|
|
2867
|
-
this.value ** n,
|
|
2868
|
-
dimsScale(this.dimensions, n),
|
|
2869
|
-
this.notation ? `(${this.notation})^${n}` : ""
|
|
2870
|
-
);
|
|
2871
|
-
}
|
|
2872
|
-
// -------------------------------------------------------------------------
|
|
2873
|
-
// Conversion
|
|
2874
|
-
// -------------------------------------------------------------------------
|
|
2875
|
-
/**
|
|
2876
|
-
* Convert to a target unit. Dimensions must match.
|
|
2877
|
-
*
|
|
2878
|
-
* @throws {DimensionMismatchError} if `targetNotation`'s dimensions differ
|
|
2879
|
-
* from this unit's.
|
|
2880
|
-
*/
|
|
2881
|
-
to(targetNotation) {
|
|
2882
|
-
const parsed = parse(targetNotation);
|
|
2883
|
-
const composed = composeAtoms(parsed.atoms);
|
|
2884
|
-
if (!dimsEqual(this.dimensions, composed.dimensions)) {
|
|
2885
|
-
throw new DimensionMismatchError(
|
|
2886
|
-
this.dimensions,
|
|
2887
|
-
composed.dimensions,
|
|
2888
|
-
`to("${targetNotation}")`
|
|
2889
|
-
);
|
|
2890
|
-
}
|
|
2891
|
-
return new _Unit(this.value, composed.dimensions, targetNotation);
|
|
2892
|
-
}
|
|
2893
|
-
/**
|
|
2894
|
-
* Pick a unit (with SI prefix) that gives a magnitude closest to 1.
|
|
2895
|
-
*
|
|
2896
|
-
* Searches the unit registry for entries matching this unit's dimensions,
|
|
2897
|
-
* then applies each SI prefix in {@link BEST_PREFIXES} to find the
|
|
2898
|
-
* representation minimising `|log10(displayed value)|`.
|
|
2899
|
-
*
|
|
2900
|
-
* If no registered unit matches the dimensions, falls back to a synthetic
|
|
2901
|
-
* notation describing the dimensional vector.
|
|
2902
|
-
*/
|
|
2903
|
-
toBest() {
|
|
2904
|
-
if (isDimensionless(this.dimensions)) {
|
|
2905
|
-
return new _Unit(this.value, this.dimensions, "");
|
|
2906
|
-
}
|
|
2907
|
-
let bestNotation;
|
|
2908
|
-
let bestScore = Infinity;
|
|
2909
|
-
for (const [name, def] of Object.entries(ALL_UNITS)) {
|
|
2910
|
-
if (name === "kg") continue;
|
|
2911
|
-
if (!dimsEqual(def.dimensions, this.dimensions)) continue;
|
|
2912
|
-
if (def.offset !== void 0) continue;
|
|
2913
|
-
const candidatePrefixes = def.prefixable ? BEST_PREFIXES : [""];
|
|
2914
|
-
for (const prefix of candidatePrefixes) {
|
|
2915
|
-
const factor = prefix === "" ? def.multiplier : def.multiplier * SI_PREFIXES[prefix];
|
|
2916
|
-
if (factor === 0) continue;
|
|
2917
|
-
const displayed = this.value / factor;
|
|
2918
|
-
if (displayed === 0) continue;
|
|
2919
|
-
const score = Math.abs(Math.log10(Math.abs(displayed)));
|
|
2920
|
-
if (score < bestScore) {
|
|
2921
|
-
bestScore = score;
|
|
2922
|
-
bestNotation = prefix + name;
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
|
-
if (bestNotation === void 0) {
|
|
2927
|
-
return new _Unit(
|
|
2928
|
-
this.value,
|
|
2929
|
-
this.dimensions,
|
|
2930
|
-
this.notation || formatDimensions(this.dimensions)
|
|
2931
|
-
);
|
|
2932
|
-
}
|
|
2933
|
-
return new _Unit(this.value, this.dimensions, bestNotation);
|
|
2934
|
-
}
|
|
2935
|
-
// -------------------------------------------------------------------------
|
|
2936
|
-
// Comparison
|
|
2937
|
-
// -------------------------------------------------------------------------
|
|
2938
|
-
/** True iff dimensions and canonical value are equal. */
|
|
2939
|
-
equals(other) {
|
|
2940
|
-
return dimsEqual(this.dimensions, other.dimensions) && this.value === other.value;
|
|
2941
|
-
}
|
|
2942
|
-
/** True iff dimensions match (values may differ). */
|
|
2943
|
-
dimensionsEqual(other) {
|
|
2944
|
-
return dimsEqual(this.dimensions, other.dimensions);
|
|
2945
|
-
}
|
|
2946
|
-
// -------------------------------------------------------------------------
|
|
2947
|
-
// Formatting
|
|
2948
|
-
// -------------------------------------------------------------------------
|
|
2949
|
-
/**
|
|
2950
|
-
* Pretty-print. If `notation` is set (the common case), display the value
|
|
2951
|
-
* in that notation — otherwise emit a dimensional signature.
|
|
2952
|
-
*/
|
|
2953
|
-
toString() {
|
|
2954
|
-
if (this.notation === "") {
|
|
2955
|
-
if (isDimensionless(this.dimensions)) return String(this.value);
|
|
2956
|
-
return `${this.value} ${formatDimensions(this.dimensions)}`;
|
|
2957
|
-
}
|
|
2958
|
-
const displayed = displayedValue(this.value, this.notation);
|
|
2959
|
-
return `${formatNumber(displayed)} ${this.notation}`;
|
|
2960
|
-
}
|
|
2961
|
-
/** JSON-serialisable record. */
|
|
2962
|
-
toJSON() {
|
|
2963
|
-
return { mathts: "Unit", value: this.value, notation: this.notation };
|
|
2964
|
-
}
|
|
2965
|
-
/**
|
|
2966
|
-
* Rehydrate from a JSON record produced by {@link toJSON}.
|
|
2967
|
-
*
|
|
2968
|
-
* @throws {UnitParseError} if `json.notation` cannot be parsed.
|
|
2969
|
-
*/
|
|
2970
|
-
static fromJSON(json) {
|
|
2971
|
-
const parsed = parse(json.notation);
|
|
2972
|
-
const composed = composeAtoms(parsed.atoms);
|
|
2973
|
-
return new _Unit(json.value, composed.dimensions, json.notation);
|
|
2974
|
-
}
|
|
2975
|
-
/**
|
|
2976
|
-
* Parse a full unit expression (with optional leading numeric coefficient).
|
|
2977
|
-
*
|
|
2978
|
-
* Example: `Unit.parse('5 km/h')`.
|
|
2979
|
-
*/
|
|
2980
|
-
static parse(input) {
|
|
2981
|
-
const { scalar, rest } = splitScalar(input);
|
|
2982
|
-
return new _Unit(scalar, rest);
|
|
2983
|
-
}
|
|
2984
|
-
};
|
|
2985
|
-
Unit.prototype.isUnit = true;
|
|
2986
|
-
function composeAtoms(atoms) {
|
|
2987
|
-
let multiplier = 1;
|
|
2988
|
-
let dimensions = { ...DIMENSIONLESS };
|
|
2989
|
-
for (const a of atoms) {
|
|
2990
|
-
multiplier *= a.multiplier ** a.exponent;
|
|
2991
|
-
dimensions = dimsAdd(dimensions, dimsScale(a.dimensions, a.exponent));
|
|
2992
|
-
}
|
|
2993
|
-
return { multiplier, dimensions };
|
|
2994
|
-
}
|
|
2995
|
-
function displayedValue(canonical, notation) {
|
|
2996
|
-
const parsed = parse(notation);
|
|
2997
|
-
const composed = composeAtoms(parsed.atoms);
|
|
2998
|
-
if (parsed.atoms.length === 1 && parsed.atoms[0].exponent === 1) {
|
|
2999
|
-
const a = parsed.atoms[0];
|
|
3000
|
-
return (canonical - a.offset) / a.multiplier;
|
|
3001
|
-
}
|
|
3002
|
-
return canonical / composed.multiplier;
|
|
3003
|
-
}
|
|
3004
|
-
function formatNumber(n) {
|
|
3005
|
-
if (Number.isInteger(n)) return n.toString();
|
|
3006
|
-
const rounded = Number(n.toPrecision(12));
|
|
3007
|
-
return rounded.toString();
|
|
3008
|
-
}
|
|
3009
|
-
function composeNotation(a, b, op) {
|
|
3010
|
-
if (a === "" && b === "") return "";
|
|
3011
|
-
if (a === "") return op === "*" ? b : `1/${b}`;
|
|
3012
|
-
if (b === "") return a;
|
|
3013
|
-
const sep = op === "*" ? "*" : "/";
|
|
3014
|
-
return `${a}${sep}${b}`;
|
|
3015
|
-
}
|
|
3016
|
-
function isUnit(value) {
|
|
3017
|
-
return value instanceof Unit;
|
|
3018
|
-
}
|
|
3019
|
-
|
|
3020
405
|
// src/typed/mathts-typed.ts
|
|
3021
406
|
import typed, { create } from "typed-function";
|
|
3022
407
|
var wasmInitialized = false;
|
|
@@ -3520,6 +905,7 @@ export {
|
|
|
3520
905
|
DEFAULT_CONFIG,
|
|
3521
906
|
DERIVED_UNITS,
|
|
3522
907
|
DIMENSIONLESS,
|
|
908
|
+
DUAL_UNARY_RULES,
|
|
3523
909
|
DimensionMismatchError,
|
|
3524
910
|
Dual,
|
|
3525
911
|
E,
|
|
@@ -3549,11 +935,16 @@ export {
|
|
|
3549
935
|
Unit,
|
|
3550
936
|
UnitParseError,
|
|
3551
937
|
VERSION,
|
|
938
|
+
abs,
|
|
939
|
+
addScalar,
|
|
3552
940
|
create,
|
|
3553
941
|
createFactory,
|
|
3554
942
|
createMathTSTyped,
|
|
3555
943
|
createTypedFunction,
|
|
3556
944
|
dim,
|
|
945
|
+
divideScalar,
|
|
946
|
+
equal,
|
|
947
|
+
fix,
|
|
3557
948
|
getPrefix,
|
|
3558
949
|
getUnitDef,
|
|
3559
950
|
initTypedWasm,
|
|
@@ -3569,6 +960,7 @@ export {
|
|
|
3569
960
|
isMatrix,
|
|
3570
961
|
isNull,
|
|
3571
962
|
isNumber,
|
|
963
|
+
isNumeric,
|
|
3572
964
|
isObject,
|
|
3573
965
|
isSparseMatrix,
|
|
3574
966
|
isString,
|
|
@@ -3578,7 +970,12 @@ export {
|
|
|
3578
970
|
isUnit as isUnitValue,
|
|
3579
971
|
math,
|
|
3580
972
|
mathTyped,
|
|
973
|
+
multiplyScalar,
|
|
974
|
+
number,
|
|
975
|
+
pow,
|
|
3581
976
|
registerNativeTypes,
|
|
3582
977
|
registry,
|
|
978
|
+
round,
|
|
979
|
+
subtractScalar,
|
|
3583
980
|
typed
|
|
3584
981
|
};
|