@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/index.js CHANGED
@@ -1,557 +1,72 @@
1
- // src/types/complex.ts
2
- function isComplex(value) {
3
- return value instanceof Complex;
4
- }
5
- var Complex = class _Complex {
6
- type = "Complex";
7
- re;
8
- im;
9
- constructor(re, im = 0) {
10
- this.re = re;
11
- this.im = im;
12
- }
13
- // ============================================================
14
- // Static Factory Methods
15
- // ============================================================
16
- /**
17
- * Create a Complex from polar form (r, θ)
18
- * @param r - magnitude (radius)
19
- * @param theta - angle in radians
20
- */
21
- static fromPolar(r, theta) {
22
- return new _Complex(r * Math.cos(theta), r * Math.sin(theta));
23
- }
24
- /**
25
- * Create a Complex from a real number
26
- */
27
- static fromNumber(n) {
28
- return new _Complex(n, 0);
29
- }
30
- /**
31
- * Create a Complex from a JSON object
32
- */
33
- static fromJSON(json) {
34
- return new _Complex(json.re, json.im);
35
- }
36
- /**
37
- * Parse a complex number from a string
38
- * Supports formats: "3+4i", "3-4i", "3", "4i", "-4i", "i", "-i"
39
- */
40
- static parse(str) {
41
- str = str.replace(/\s/g, "");
42
- const match = str.match(/^([+-]?[\d.]+)([+-])([\d.]*)i$/);
43
- if (match) {
44
- const re = parseFloat(match[1]);
45
- const sign = match[2] === "-" ? -1 : 1;
46
- const imMag = match[3] === "" ? 1 : parseFloat(match[3]);
47
- return new _Complex(re, sign * imMag);
48
- }
49
- if (str.endsWith("i")) {
50
- const imStr = str.slice(0, -1);
51
- if (imStr === "" || imStr === "+") return new _Complex(0, 1);
52
- if (imStr === "-") return new _Complex(0, -1);
53
- return new _Complex(0, parseFloat(imStr));
54
- }
55
- return new _Complex(parseFloat(str), 0);
56
- }
57
- /**
58
- * Compare two complex numbers lexicographically (re first, then im)
59
- * @returns -1, 0, or 1
60
- */
61
- static compare(a, b) {
62
- if (a.re > b.re) return 1;
63
- if (a.re < b.re) return -1;
64
- if (a.im > b.im) return 1;
65
- if (a.im < b.im) return -1;
66
- return 0;
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
- floor() {
1811
- return this.round(0, "floor");
96
+ mul(o) {
97
+ return new _Dual(this.value * o.value, this.deriv * o.value + this.value * o.deriv);
1812
98
  }
1813
- ceil() {
1814
- return this.round(0, "ceil");
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
- trunc() {
1817
- return this.round(0, "down");
103
+ neg() {
104
+ return new _Dual(-this.value, -this.deriv);
1818
105
  }
1819
- /**
1820
- * Round to `n` significant decimal digits and return a new BigNumber.
1821
- * Delegates to `roundToPrecision`, using the global rounding mode unless
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
- * The decimal exponent of this number: `floor(log10(|x|))`.
1833
- *
1834
- * Matches Decimal.js semantics:
1835
- * - `12345` → `4` (5 digits → the most-significant place is 10^4)
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
- // Modular Arithmetic
1851
- // ============================================================
1852
- /**
1853
- * Modulo (remainder after division)
1854
- * Result has the same sign as the dividend (this).
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
- if (this._isNaN) return this;
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
- if (this._isNaN) return this;
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
- if (this._isNaN) return this;
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
- * Arcsine of this BigNumber
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
- * Arccosine of this BigNumber
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
- * Arctangent of this BigNumber
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
- * Two-argument arctangent: atan2(y, x)
1954
- * this = y, argument = x
1955
- * Returns angle in (-PI, PI]
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
- if (this._isNaN) return this;
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
- if (this._isNaN) return this;
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
- if (this._isNaN) return this;
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
- normalize(sign, coefficient, exponent) {
2324
- if (coefficient === 0n) {
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
- var BIGNUMBER_ZERO = BigNumber.fromNumber(0);
2337
- var BIGNUMBER_ONE = BigNumber.fromNumber(1);
2338
- var BIGNUMBER_NEG_ONE = BigNumber.fromNumber(-1);
2339
- var BIGNUMBER_TEN = BigNumber.fromNumber(10);
2340
- var BIGNUMBER_PI = BigNumber.parse("3.14159265358979323846264338327950288419716939937510");
2341
- var BIGNUMBER_E = BigNumber.parse("2.71828182845904523536028747135266249775724709369995");
2342
- var BIGNUMBER_LN2 = BigNumber.parse(
2343
- "0.69314718055994530941723212145817656807550013436026"
2344
- );
2345
- var BIGNUMBER_LN10 = BigNumber.parse(
2346
- "2.30258509299404568401799145468436420760110148862877"
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
  };