@danielsimonjr/mathts-core 0.3.0 → 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,1767 +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
- let num = typeof numerator === "bigint" ? numerator : BigInt(numerator);
679
- let den = typeof denominator === "bigint" ? denominator : BigInt(denominator);
680
- if (den === 0n) {
681
- throw new Error("Fraction denominator cannot be zero");
682
- }
683
- if (den < 0n) {
684
- num = -num;
685
- den = -den;
686
- }
687
- const g = gcd(num, den);
688
- this.numerator = num / g;
689
- this.denominator = den / g;
690
- }
691
- // ============================================================
692
- // Static Factory Methods
693
- // ============================================================
694
- /**
695
- * Create a Fraction from a number (with optional precision)
696
- */
697
- static fromNumber(n, maxDenominator = 1000000n) {
698
- if (!Number.isFinite(n)) {
699
- throw new Error("Cannot create fraction from non-finite number");
700
- }
701
- if (Number.isInteger(n)) {
702
- return new _Fraction(BigInt(n), 1n);
703
- }
704
- const sign = n < 0 ? -1n : 1n;
705
- n = Math.abs(n);
706
- let h1 = 1n, h2 = 0n;
707
- let k1 = 0n, k2 = 1n;
708
- let b = n;
709
- do {
710
- const a = BigInt(Math.floor(b));
711
- let aux = h1;
712
- h1 = a * h1 + h2;
713
- h2 = aux;
714
- aux = k1;
715
- k1 = a * k1 + k2;
716
- k2 = aux;
717
- b = 1 / (b - Number(a));
718
- } while (Math.abs(n - Number(h1) / Number(k1)) > Number.EPSILON && k1 < maxDenominator);
719
- return new _Fraction(sign * h1, k1);
720
- }
721
- /**
722
- * Create a Fraction from a decimal string
723
- */
724
- static fromDecimalString(str) {
725
- str = str.trim();
726
- const repeatingMatch = str.match(/^(-?\d*)\.(\d*)\((\d+)\)$/);
727
- if (repeatingMatch) {
728
- const sign2 = str.startsWith("-") ? -1n : 1n;
729
- const intPart2 = repeatingMatch[1] === "-" ? "0" : repeatingMatch[1] || "0";
730
- const nonRepeating = repeatingMatch[2] || "";
731
- const repeating = repeatingMatch[3];
732
- const fullDigits = intPart2 + nonRepeating + repeating;
733
- const nonRepDigits = intPart2 + nonRepeating;
734
- const fullNum = BigInt(fullDigits.replace("-", ""));
735
- const nonRepNum = BigInt(nonRepDigits.replace("-", "") || "0");
736
- const nines = BigInt("9".repeat(repeating.length));
737
- const zeros = BigInt("1" + "0".repeat(nonRepeating.length));
738
- const num2 = fullNum - nonRepNum;
739
- const den2 = nines * zeros;
740
- return new _Fraction(sign2 * num2, den2);
741
- }
742
- const [intPart, decPart = ""] = str.split(".");
743
- const sign = str.startsWith("-") ? -1n : 1n;
744
- const absInt = intPart.replace("-", "") || "0";
745
- const combined = absInt + decPart;
746
- const num = BigInt(combined);
747
- const den = BigInt("1" + "0".repeat(decPart.length));
748
- return new _Fraction(sign * num, den);
749
- }
750
- /**
751
- * Parse a fraction from a string
752
- * Supports formats: "3/4", "-3/4", "3", "3.14", "0.(3)"
753
- */
754
- static parse(str) {
755
- str = str.trim();
756
- if (str.includes("/")) {
757
- const [numStr, denStr] = str.split("/");
758
- return new _Fraction(BigInt(numStr.trim()), BigInt(denStr.trim()));
759
- }
760
- if (str.includes(".") || str.includes("(")) {
761
- return _Fraction.fromDecimalString(str);
762
- }
763
- return new _Fraction(BigInt(str), 1n);
764
- }
765
- /**
766
- * Create a Fraction from a JSON object
767
- */
768
- static fromJSON(json) {
769
- if ("n" in json) {
770
- return new _Fraction(BigInt(json.n), BigInt(json.d));
771
- }
772
- return new _Fraction(BigInt(json.numerator), BigInt(json.denominator));
773
- }
774
- /**
775
- * Compare two fractions
776
- * @returns -1, 0, or 1
777
- */
778
- static compare(a, b) {
779
- const diff = a.numerator * b.denominator - b.numerator * a.denominator;
780
- if (diff < 0n) return -1;
781
- if (diff > 0n) return 1;
782
- return 0;
783
- }
784
- // ============================================================
785
- // Conversion Methods
786
- // ============================================================
787
- valueOf() {
788
- return Number(this.numerator) / Number(this.denominator);
789
- }
790
- toString() {
791
- if (this.denominator === 1n) {
792
- return this.numerator.toString();
793
- }
794
- return `${this.numerator}/${this.denominator}`;
795
- }
796
- toJSON() {
797
- return {
798
- mathjs: "Fraction",
799
- n: this.numerator.toString(),
800
- d: this.denominator.toString()
801
- };
802
- }
803
- /**
804
- * Convert to number
805
- */
806
- toNumber() {
807
- return this.valueOf();
808
- }
809
- /**
810
- * Convert to decimal string with specified precision
811
- */
812
- toDecimal(precision = 10) {
813
- const sign = this.numerator < 0n ? "-" : "";
814
- let num = this.numerator < 0n ? -this.numerator : this.numerator;
815
- const den = this.denominator;
816
- const intPart = num / den;
817
- num = num % den;
818
- if (num === 0n || precision === 0) {
819
- return sign + intPart.toString();
820
- }
821
- let decPart = "";
822
- for (let i = 0; i < precision && num !== 0n; i++) {
823
- num *= 10n;
824
- decPart += (num / den).toString();
825
- num = num % den;
826
- }
827
- return sign + intPart.toString() + "." + decPart;
828
- }
829
- /**
830
- * Convert to LaTeX string
831
- */
832
- toLatex() {
833
- if (this.denominator === 1n) {
834
- return this.numerator.toString();
835
- }
836
- const sign = this.numerator < 0n ? "-" : "";
837
- const absNum = this.numerator < 0n ? -this.numerator : this.numerator;
838
- return `${sign}\\frac{${absNum}}{${this.denominator}}`;
839
- }
840
- /**
841
- * Convert to mixed number representation
842
- */
843
- toMixed() {
844
- const sign = this.numerator < 0n ? -1n : 1n;
845
- const absNum = this.numerator < 0n ? -this.numerator : this.numerator;
846
- const whole = sign * (absNum / this.denominator);
847
- const remainder = absNum % this.denominator;
848
- return {
849
- whole,
850
- numerator: remainder,
851
- denominator: this.denominator
852
- };
853
- }
854
- // ============================================================
855
- // Arithmetic Operations (Scalar interface)
856
- // ============================================================
857
- /**
858
- * Addition: a/b + c/d = (ad + bc) / bd
859
- */
860
- add(other) {
861
- if (other instanceof _Fraction) {
862
- const num = this.numerator * other.denominator + other.numerator * this.denominator;
863
- const den = this.denominator * other.denominator;
864
- return new _Fraction(num, den);
865
- }
866
- return this.add(_Fraction.fromNumber(Number(other.valueOf())));
867
- }
868
- /**
869
- * Subtraction: a/b - c/d = (ad - bc) / bd
870
- */
871
- subtract(other) {
872
- if (other instanceof _Fraction) {
873
- const num = this.numerator * other.denominator - other.numerator * this.denominator;
874
- const den = this.denominator * other.denominator;
875
- return new _Fraction(num, den);
876
- }
877
- return this.subtract(_Fraction.fromNumber(Number(other.valueOf())));
878
- }
879
- /**
880
- * Multiplication: a/b * c/d = ac / bd
881
- */
882
- multiply(other) {
883
- if (other instanceof _Fraction) {
884
- return new _Fraction(this.numerator * other.numerator, this.denominator * other.denominator);
885
- }
886
- return this.multiply(_Fraction.fromNumber(Number(other.valueOf())));
887
- }
888
- /**
889
- * Division: a/b ÷ c/d = ad / bc
890
- */
891
- divide(other) {
892
- if (other instanceof _Fraction) {
893
- if (other.numerator === 0n) {
894
- throw new Error("Division by zero");
895
- }
896
- return new _Fraction(this.numerator * other.denominator, this.denominator * other.numerator);
897
- }
898
- return this.divide(_Fraction.fromNumber(Number(other.valueOf())));
899
- }
900
- // Short-name aliases (mathjs Fraction API). Ported mathjs functions such as
901
- // multiplyScalar/subtractScalar/divideScalar call x.mul/x.sub/x.div; without
902
- // these, mixed number/Fraction dispatch (e.g. affine unit conversion like
903
- // celsius→fahrenheit) threw "x.mul is not a function".
904
- mul(other) {
905
- return this.multiply(other);
906
- }
907
- sub(other) {
908
- return this.subtract(other);
909
- }
910
- div(other) {
911
- return this.divide(other);
912
- }
913
- /**
914
- * Negation: -(a/b) = -a/b
915
- */
916
- negate() {
917
- return new _Fraction(-this.numerator, this.denominator);
918
- }
919
- /**
920
- * Absolute value: |a/b|
921
- */
922
- abs() {
923
- return new _Fraction(this.numerator < 0n ? -this.numerator : this.numerator, this.denominator);
924
- }
925
- /**
926
- * Reciprocal: b/a
927
- */
928
- inverse() {
929
- if (this.numerator === 0n) {
930
- throw new Error("Cannot invert zero");
931
- }
932
- return new _Fraction(this.denominator, this.numerator);
933
- }
934
- /**
935
- * Power (integer exponent)
936
- */
937
- pow(n) {
938
- const exp = typeof n === "bigint" ? n : BigInt(n);
939
- if (exp === 0n) {
940
- return new _Fraction(1n, 1n);
941
- }
942
- if (exp < 0n) {
943
- return this.inverse().pow(-exp);
944
- }
945
- let result = new _Fraction(1n, 1n);
946
- let base = this.clone();
947
- let e = exp;
948
- while (e > 0n) {
949
- if (e % 2n === 1n) {
950
- result = result.multiply(base);
951
- }
952
- base = base.multiply(base);
953
- e = e / 2n;
954
- }
955
- return result;
956
- }
957
- /**
958
- * Modulo operation
959
- */
960
- mod(other) {
961
- const quotient = this.divide(other);
962
- const floorQuot = quotient.floor();
963
- return this.subtract(other.multiply(floorQuot));
964
- }
965
- // ============================================================
966
- // Comparison Methods
967
- // ============================================================
968
- /**
969
- * Check equality
970
- */
971
- equals(other) {
972
- return this.numerator === other.numerator && this.denominator === other.denominator;
973
- }
974
- /**
975
- * Check if less than
976
- */
977
- lessThan(other) {
978
- return _Fraction.compare(this, other) < 0;
979
- }
980
- /**
981
- * Check if less than or equal
982
- */
983
- lessThanOrEqual(other) {
984
- return _Fraction.compare(this, other) <= 0;
985
- }
986
- /**
987
- * Check if greater than
988
- */
989
- greaterThan(other) {
990
- return _Fraction.compare(this, other) > 0;
991
- }
992
- /**
993
- * Check if greater than or equal
994
- */
995
- greaterThanOrEqual(other) {
996
- return _Fraction.compare(this, other) >= 0;
997
- }
998
- /**
999
- * Compare with another fraction
1000
- * @returns -1, 0, or 1
1001
- */
1002
- compareTo(other) {
1003
- return _Fraction.compare(this, other);
1004
- }
1005
- compare(other) {
1006
- return this.compareTo(other);
1007
- }
1008
- // ============================================================
1009
- // Utility Methods
1010
- // ============================================================
1011
- /**
1012
- * Return fraction already in lowest terms (no-op since constructor reduces)
1013
- */
1014
- simplify() {
1015
- return this;
1016
- }
1017
- /**
1018
- * Check if this is zero
1019
- */
1020
- isZero() {
1021
- return this.numerator === 0n;
1022
- }
1023
- /**
1024
- * Check if this is positive
1025
- */
1026
- isPositive() {
1027
- return this.numerator > 0n;
1028
- }
1029
- /**
1030
- * Check if this is negative
1031
- */
1032
- isNegative() {
1033
- return this.numerator < 0n;
1034
- }
1035
- /**
1036
- * Check if this is an integer
1037
- */
1038
- isInteger() {
1039
- return this.denominator === 1n;
1040
- }
1041
- /**
1042
- * Check if this is a unit fraction (1/n)
1043
- */
1044
- isUnit() {
1045
- return this.numerator === 1n || this.numerator === -1n;
1046
- }
1047
- /**
1048
- * Floor: largest integer ≤ this
1049
- */
1050
- floor() {
1051
- if (this.denominator === 1n) {
1052
- return this;
1053
- }
1054
- const quot = this.numerator / this.denominator;
1055
- if (this.numerator >= 0n || this.numerator % this.denominator === 0n) {
1056
- return new _Fraction(quot, 1n);
1057
- }
1058
- return new _Fraction(quot - 1n, 1n);
1059
- }
1060
- /**
1061
- * Ceiling: smallest integer ≥ this
1062
- */
1063
- ceil() {
1064
- if (this.denominator === 1n) {
1065
- return this;
1066
- }
1067
- const quot = this.numerator / this.denominator;
1068
- if (this.numerator <= 0n || this.numerator % this.denominator === 0n) {
1069
- return new _Fraction(quot, 1n);
1070
- }
1071
- return new _Fraction(quot + 1n, 1n);
1072
- }
1073
- /**
1074
- * Round to nearest integer
1075
- */
1076
- round() {
1077
- const floor = this.floor();
1078
- const diff = this.subtract(floor);
1079
- const half = new _Fraction(1n, 2n);
1080
- if (diff.greaterThanOrEqual(half)) {
1081
- return floor.add(new _Fraction(1n, 1n));
1082
- }
1083
- return floor;
1084
- }
1085
- /**
1086
- * Truncate (round toward zero)
1087
- */
1088
- trunc() {
1089
- return new _Fraction(this.numerator / this.denominator, 1n);
1090
- }
1091
- /**
1092
- * Get the sign: -1, 0, or 1
1093
- */
1094
- sign() {
1095
- if (this.numerator < 0n) return -1;
1096
- if (this.numerator > 0n) return 1;
1097
- return 0;
1098
- }
1099
- /**
1100
- * Clone this fraction
1101
- */
1102
- clone() {
1103
- return new _Fraction(this.numerator, this.denominator);
1104
- }
1105
- /**
1106
- * Get the GCD of numerator and denominator (always 1 since we reduce)
1107
- */
1108
- gcd() {
1109
- return 1n;
1110
- }
1111
- /**
1112
- * Get continued fraction representation
1113
- */
1114
- toContinuedFraction() {
1115
- const result = [];
1116
- let num = this.numerator < 0n ? -this.numerator : this.numerator;
1117
- let den = this.denominator;
1118
- while (den !== 0n) {
1119
- result.push(num / den);
1120
- const temp = num % den;
1121
- num = den;
1122
- den = temp;
1123
- }
1124
- if (this.numerator < 0n && result.length > 0) {
1125
- result[0] = -result[0];
1126
- }
1127
- return result;
1128
- }
1129
- /**
1130
- * Create fraction from continued fraction
1131
- */
1132
- static fromContinuedFraction(cf) {
1133
- if (cf.length === 0) {
1134
- return new _Fraction(0n, 1n);
1135
- }
1136
- let num = cf[cf.length - 1];
1137
- let den = 1n;
1138
- for (let i = cf.length - 2; i >= 0; i--) {
1139
- const temp = num;
1140
- num = cf[i] * num + den;
1141
- den = temp;
1142
- }
1143
- return new _Fraction(num, den);
1144
- }
1145
- /**
1146
- * Mediant of two fractions: (a+c)/(b+d)
1147
- * Used in Stern-Brocot tree and Farey sequences
1148
- */
1149
- mediant(other) {
1150
- return new _Fraction(this.numerator + other.numerator, this.denominator + other.denominator);
1151
- }
1152
- };
1153
- var FRACTION_ZERO = new Fraction(0n, 1n);
1154
- var FRACTION_ONE = new Fraction(1n, 1n);
1155
- var FRACTION_NEG_ONE = new Fraction(-1n, 1n);
1156
- var FRACTION_HALF = new Fraction(1n, 2n);
1157
- var FRACTION_THIRD = new Fraction(1n, 3n);
1158
- var FRACTION_QUARTER = new Fraction(1n, 4n);
1159
-
1160
- // src/types/bignumber.ts
1161
- function isBigNumber(value) {
1162
- return value instanceof BigNumber;
1163
- }
1164
- var defaultConfig = {
1165
- precision: 64,
1166
- rounding: "halfUp",
1167
- minExponent: -1e9,
1168
- maxExponent: 1e9
1169
- };
1170
- var globalConfig = { ...defaultConfig };
1171
- var BigNumber = class _BigNumber {
1172
- type = "BigNumber";
1173
- /**
1174
- * Duck-typing marker for Decimal.js / mathjs formatter compatibility.
1175
- * Allows external code that checks `obj.isBigNumber === true` to identify
1176
- * this class without an `instanceof` check.
1177
- */
1178
- isBigNumber = true;
1179
- // Internal representation: sign * coefficient * 10^exponent
1180
- _sign;
1181
- _coefficient;
1182
- // Absolute value, normalized
1183
- _exponent;
1184
- // Power of 10
1185
- // Special values
1186
- _isNaN = false;
1187
- _isInfinite = false;
1188
- constructor(sign, coefficient, exponent, isNaN2 = false, isInfinite = false) {
1189
- this._sign = sign;
1190
- this._coefficient = coefficient;
1191
- this._exponent = exponent;
1192
- this._isNaN = isNaN2;
1193
- this._isInfinite = isInfinite;
1194
- }
1195
- // ============================================================
1196
- // Static Factory Methods
1197
- // ============================================================
1198
- /**
1199
- * Create a BigNumber from a number
1200
- */
1201
- static fromNumber(n) {
1202
- if (Number.isNaN(n)) {
1203
- return new _BigNumber(0, 0n, 0, true, false);
1204
- }
1205
- if (!Number.isFinite(n)) {
1206
- return new _BigNumber(n > 0 ? 1 : -1, 0n, 0, false, true);
1207
- }
1208
- if (n === 0) {
1209
- return new _BigNumber(0, 0n, 0);
1210
- }
1211
- return _BigNumber.parse(n.toString());
1212
- }
1213
- /**
1214
- * Create a BigNumber from a string
1215
- */
1216
- static parse(str) {
1217
- str = str.trim().toLowerCase();
1218
- if (str === "nan") {
1219
- return new _BigNumber(0, 0n, 0, true, false);
1220
- }
1221
- if (str === "infinity" || str === "+infinity") {
1222
- return new _BigNumber(1, 0n, 0, false, true);
1223
- }
1224
- if (str === "-infinity") {
1225
- return new _BigNumber(-1, 0n, 0, false, true);
1226
- }
1227
- let sign = 1;
1228
- if (str.startsWith("-")) {
1229
- sign = -1;
1230
- str = str.slice(1);
1231
- } else if (str.startsWith("+")) {
1232
- str = str.slice(1);
1233
- }
1234
- let exponentPart = 0;
1235
- const eIndex = str.indexOf("e");
1236
- if (eIndex !== -1) {
1237
- exponentPart = parseInt(str.slice(eIndex + 1), 10);
1238
- str = str.slice(0, eIndex);
1239
- }
1240
- const dotIndex = str.indexOf(".");
1241
- let coefficient;
1242
- let decimalPlaces = 0;
1243
- if (dotIndex !== -1) {
1244
- coefficient = str.slice(0, dotIndex) + str.slice(dotIndex + 1);
1245
- decimalPlaces = str.length - dotIndex - 1;
1246
- } else {
1247
- coefficient = str;
1248
- }
1249
- coefficient = coefficient.replace(/^0+/, "") || "0";
1250
- if (coefficient === "0") {
1251
- return new _BigNumber(0, 0n, 0);
1252
- }
1253
- let trailingZeros = 0;
1254
- for (let i = coefficient.length - 1; i >= 0; i--) {
1255
- if (coefficient[i] === "0") {
1256
- trailingZeros++;
1257
- } else {
1258
- break;
1259
- }
1260
- }
1261
- if (trailingZeros > 0) {
1262
- coefficient = coefficient.slice(0, -trailingZeros);
1263
- }
1264
- const finalExponent = exponentPart - decimalPlaces + trailingZeros;
1265
- return new _BigNumber(sign, BigInt(coefficient), finalExponent);
1266
- }
1267
- /**
1268
- * Create from bigint
1269
- */
1270
- static fromBigInt(n) {
1271
- if (n === 0n) {
1272
- return new _BigNumber(0, 0n, 0);
1273
- }
1274
- const sign = n < 0n ? -1 : 1;
1275
- let str = (n < 0n ? -n : n).toString();
1276
- let trailingZeros = 0;
1277
- for (let i = str.length - 1; i >= 0; i--) {
1278
- if (str[i] === "0") {
1279
- trailingZeros++;
1280
- } else {
1281
- break;
1282
- }
1283
- }
1284
- if (trailingZeros > 0) {
1285
- str = str.slice(0, -trailingZeros);
1286
- }
1287
- return new _BigNumber(sign, BigInt(str), trailingZeros);
1288
- }
1289
- /**
1290
- * Create a BigNumber from a JSON object
1291
- */
1292
- static fromJSON(json) {
1293
- return _BigNumber.parse(json.value);
1294
- }
1295
- /**
1296
- * Get/set global configuration
1297
- */
1298
- static config(newConfig) {
1299
- if (newConfig) {
1300
- globalConfig = { ...globalConfig, ...newConfig };
1301
- }
1302
- return { ...globalConfig };
1303
- }
1304
- /**
1305
- * Reset configuration to defaults
1306
- */
1307
- static resetConfig() {
1308
- globalConfig = { ...defaultConfig };
1309
- }
1310
- /**
1311
- * Compare two BigNumbers
1312
- * @returns -1, 0, or 1
1313
- */
1314
- static compare(a, b) {
1315
- if (a._isNaN || b._isNaN) return NaN;
1316
- if (a._isInfinite && b._isInfinite) {
1317
- if (a._sign === b._sign) return 0;
1318
- return a._sign > b._sign ? 1 : -1;
1319
- }
1320
- if (a._isInfinite) return a._sign;
1321
- if (b._isInfinite) return -b._sign;
1322
- if (a._sign === 0 && b._sign === 0) return 0;
1323
- if (a._sign === 0) return -b._sign;
1324
- if (b._sign === 0) return a._sign;
1325
- if (a._sign !== b._sign) return a._sign > b._sign ? 1 : -1;
1326
- const result = _BigNumber.compareMagnitude(a, b);
1327
- return a._sign === 1 ? result : -result;
1328
- }
1329
- static compareMagnitude(a, b) {
1330
- const aDigits = a._coefficient.toString();
1331
- const bDigits = b._coefficient.toString();
1332
- const aOrder = aDigits.length + a._exponent;
1333
- const bOrder = bDigits.length + b._exponent;
1334
- if (aOrder !== bOrder) {
1335
- return aOrder > bOrder ? 1 : -1;
1336
- }
1337
- const aFull = aDigits + "0".repeat(Math.max(0, a._exponent));
1338
- const bFull = bDigits + "0".repeat(Math.max(0, b._exponent));
1339
- if (aFull === bFull) return 0;
1340
- return aFull > bFull ? 1 : -1;
1341
- }
1342
- // ============================================================
1343
- // Conversion Methods
1344
- // ============================================================
1345
- valueOf() {
1346
- if (this._isNaN) return NaN;
1347
- if (this._isInfinite) return this._sign === 1 ? Infinity : -Infinity;
1348
- if (this._sign === 0) return 0;
1349
- const str = this.toString();
1350
- return parseFloat(str);
1351
- }
1352
- /**
1353
- * Convert to a JS number.
1354
- * Alias for `valueOf()` — provided for Decimal.js / mathjs formatter
1355
- * duck-typing compatibility.
1356
- */
1357
- toNumber() {
1358
- return this.valueOf();
1359
- }
1360
- toString() {
1361
- if (this._isNaN) return "NaN";
1362
- if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
1363
- if (this._sign === 0) return "0";
1364
- const sign = this._sign === -1 ? "-" : "";
1365
- const digits = this._coefficient.toString();
1366
- if (this._exponent >= 0) {
1367
- return sign + digits + "0".repeat(this._exponent);
1368
- } else if (-this._exponent < digits.length) {
1369
- const insertPos = digits.length + this._exponent;
1370
- return sign + digits.slice(0, insertPos) + "." + digits.slice(insertPos);
1371
- } else {
1372
- return sign + "0." + "0".repeat(-this._exponent - digits.length) + digits;
1373
- }
1374
- }
1375
- toJSON() {
1376
- return {
1377
- mathjs: "BigNumber",
1378
- value: this.toString()
1379
- };
1380
- }
1381
- /**
1382
- * Convert to fixed-point notation.
1383
- *
1384
- * When called with no argument (or `undefined`) returns the full fixed-point
1385
- * string representation without rounding — matching Decimal.js semantics where
1386
- * `toFixed()` is equivalent to a lossless fixed-point stringify.
1387
- * When called with a non-negative integer `decimalPlaces`, rounds and formats
1388
- * to exactly that many digits after the decimal point.
1389
- */
1390
- toFixed(decimalPlaces) {
1391
- if (decimalPlaces === void 0) {
1392
- return this.toFixedInternal(void 0);
1393
- }
1394
- return this.round(decimalPlaces).toFixedInternal(decimalPlaces);
1395
- }
1396
- toFixedInternal(decimalPlaces) {
1397
- if (this._isNaN) return "NaN";
1398
- if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
1399
- const dp = decimalPlaces ?? -1;
1400
- const allDigits = dp < 0;
1401
- if (this._sign === 0) return allDigits ? "0" : dp > 0 ? "0." + "0".repeat(dp) : "0";
1402
- const sign = this._sign === -1 ? "-" : "";
1403
- const digits = this._coefficient.toString();
1404
- if (this._exponent >= 0) {
1405
- const intPart = digits + "0".repeat(this._exponent);
1406
- if (allDigits) return sign + intPart;
1407
- return sign + intPart + (dp > 0 ? "." + "0".repeat(dp) : "");
1408
- } else if (-this._exponent <= digits.length) {
1409
- const insertPos = digits.length + this._exponent;
1410
- const intPart = digits.slice(0, insertPos) || "0";
1411
- const decPart = digits.slice(insertPos);
1412
- if (allDigits) {
1413
- return sign + intPart + (decPart.length > 0 ? "." + decPart : "");
1414
- }
1415
- let paddedDec = decPart;
1416
- if (paddedDec.length < dp) {
1417
- paddedDec += "0".repeat(dp - paddedDec.length);
1418
- }
1419
- return sign + intPart + (dp > 0 ? "." + paddedDec.slice(0, dp) : "");
1420
- } else {
1421
- const leadingZeros = -this._exponent - digits.length;
1422
- const decPart = "0".repeat(leadingZeros) + digits;
1423
- if (allDigits) {
1424
- return sign + "0." + decPart;
1425
- }
1426
- let paddedDec = decPart;
1427
- if (paddedDec.length < dp) {
1428
- paddedDec += "0".repeat(dp - paddedDec.length);
1429
- }
1430
- return sign + "0" + (dp > 0 ? "." + paddedDec.slice(0, dp) : "");
1431
- }
1432
- }
1433
- /**
1434
- * Convert to exponential notation
1435
- */
1436
- toExponential(decimalPlaces) {
1437
- if (this._isNaN) return "NaN";
1438
- if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
1439
- if (this._sign === 0) {
1440
- const dp = decimalPlaces ?? 0;
1441
- return dp > 0 ? "0." + "0".repeat(dp) + "e+0" : "0e+0";
1442
- }
1443
- const sign = this._sign === -1 ? "-" : "";
1444
- const digits = this._coefficient.toString();
1445
- const exp = digits.length - 1 + this._exponent;
1446
- const expSign = exp >= 0 ? "+" : "";
1447
- if (decimalPlaces === void 0) {
1448
- if (digits.length === 1) {
1449
- return `${sign}${digits}e${expSign}${exp}`;
1450
- }
1451
- return `${sign}${digits[0]}.${digits.slice(1)}e${expSign}${exp}`;
1452
- }
1453
- if (decimalPlaces === 0) {
1454
- return `${sign}${digits[0]}e${expSign}${exp}`;
1455
- }
1456
- let decPart = digits.slice(1);
1457
- if (decPart.length < decimalPlaces) {
1458
- decPart += "0".repeat(decimalPlaces - decPart.length);
1459
- } else {
1460
- decPart = decPart.slice(0, decimalPlaces);
1461
- }
1462
- return `${sign}${digits[0]}.${decPart}e${expSign}${exp}`;
1463
- }
1464
- /**
1465
- * Convert to precision
1466
- */
1467
- toPrecision(significantDigits) {
1468
- if (significantDigits === void 0) {
1469
- return this.toString();
1470
- }
1471
- if (this._isNaN) return "NaN";
1472
- if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
1473
- if (this._sign === 0) {
1474
- return significantDigits > 1 ? "0." + "0".repeat(significantDigits - 1) : "0";
1475
- }
1476
- const digits = this._coefficient.toString();
1477
- const order = digits.length + this._exponent;
1478
- if (order > significantDigits || order < -6) {
1479
- return this.toExponential(significantDigits - 1);
1480
- }
1481
- return this.toFixed(significantDigits - order);
1482
- }
1483
- /**
1484
- * Convert to bigint (truncated)
1485
- */
1486
- toBigInt() {
1487
- if (this._isNaN || this._isInfinite) {
1488
- throw new Error("Cannot convert NaN or Infinity to bigint");
1489
- }
1490
- if (this._sign === 0) return 0n;
1491
- const digits = this._coefficient.toString();
1492
- if (this._exponent >= 0) {
1493
- return BigInt(this._sign) * BigInt(digits + "0".repeat(this._exponent));
1494
- } else if (-this._exponent < digits.length) {
1495
- return BigInt(this._sign) * BigInt(digits.slice(0, digits.length + this._exponent));
1496
- }
1497
- return 0n;
1498
- }
1499
- /**
1500
- * Binary string representation, e.g. `255 -> '0b11111111'`, `0.5 -> '0b0.1'`.
1501
- * Mirrors Decimal.js `toBinary()`. Negatives carry a leading `-`.
1502
- */
1503
- toBinary() {
1504
- return this.toRadixString(2, "0b");
1505
- }
1506
- /**
1507
- * Octal string representation, e.g. `8 -> '0o10'`.
1508
- * Mirrors Decimal.js `toOctal()`.
1509
- */
1510
- toOctal() {
1511
- return this.toRadixString(8, "0o");
1512
- }
1513
- /**
1514
- * Hexadecimal string representation, e.g. `255 -> '0xff'`, `10.5 -> '0xa.8'`.
1515
- * Mirrors Decimal.js `toHexadecimal()`.
1516
- */
1517
- toHexadecimal() {
1518
- return this.toRadixString(16, "0x");
1519
- }
1520
- /**
1521
- * Shared radix formatter for {@link toBinary}/{@link toOctal}/{@link toHexadecimal}.
1522
- * Integers and terminating fractions are exact; a non-terminating fraction is
1523
- * truncated at `maxFractionDigits` radix digits (a safety bound — the common
1524
- * use is integer formatting).
1525
- */
1526
- toRadixString(radix, prefix, maxFractionDigits = 1100) {
1527
- if (this._isNaN) return "NaN";
1528
- if (this._isInfinite) return (this._sign < 0 ? "-" : "") + "Infinity";
1529
- if (this._sign === 0) return prefix + "0";
1530
- const negative = this._sign < 0;
1531
- const absVal = this.abs();
1532
- const intPart = absVal.toBigInt();
1533
- let out = prefix + intPart.toString(radix);
1534
- let frac = absVal.subtract(_BigNumber.fromBigInt(intPart));
1535
- if (!frac.isZero()) {
1536
- const radixBN = _BigNumber.fromNumber(radix);
1537
- let digits = "";
1538
- for (let i = 0; i < maxFractionDigits && !frac.isZero(); i++) {
1539
- frac = frac.multiply(radixBN);
1540
- const digit = frac.toBigInt();
1541
- digits += Number(digit).toString(radix);
1542
- frac = frac.subtract(_BigNumber.fromBigInt(digit));
1543
- }
1544
- out += "." + digits;
1545
- }
1546
- return (negative ? "-" : "") + out;
1547
- }
1548
- // ============================================================
1549
- // Arithmetic Operations
1550
- // ============================================================
1551
- /**
1552
- * Addition
1553
- */
1554
- add(other) {
1555
- const b = this.ensureBigNumber(other);
1556
- if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
1557
- if (this._isInfinite && b._isInfinite) {
1558
- if (this._sign === b._sign) return this;
1559
- return new _BigNumber(0, 0n, 0, true);
1560
- }
1561
- if (this._isInfinite) return this;
1562
- if (b._isInfinite) return b;
1563
- if (this._sign === 0) return b;
1564
- if (b._sign === 0) return this;
1565
- const [aCoef, bCoef, exp] = this.alignExponents(this, b);
1566
- if (this._sign === b._sign) {
1567
- return this.normalize(this._sign, aCoef + bCoef, exp);
1568
- } else {
1569
- if (aCoef >= bCoef) {
1570
- const diff = aCoef - bCoef;
1571
- return this.normalize(diff === 0n ? 0 : this._sign, diff, exp);
1572
- } else {
1573
- return this.normalize(b._sign, bCoef - aCoef, exp);
1574
- }
1575
- }
1576
- }
1577
- /**
1578
- * Subtraction
1579
- */
1580
- subtract(other) {
1581
- const b = this.ensureBigNumber(other);
1582
- return this.add(b.negate());
1583
- }
1584
- /**
1585
- * Alias for subtract — mathjs / Decimal.js compatibility.
1586
- */
1587
- sub(other) {
1588
- return this.subtract(other);
1589
- }
1590
- /**
1591
- * Multiplication
1592
- */
1593
- multiply(other) {
1594
- const b = this.ensureBigNumber(other);
1595
- if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
1596
- if (this._isInfinite || b._isInfinite) {
1597
- if (this._sign === 0 || b._sign === 0) return new _BigNumber(0, 0n, 0, true);
1598
- const sign2 = this._sign * b._sign;
1599
- return new _BigNumber(sign2, 0n, 0, false, true);
1600
- }
1601
- if (this._sign === 0 || b._sign === 0) return new _BigNumber(0, 0n, 0);
1602
- const sign = this._sign * b._sign;
1603
- const coefficient = this._coefficient * b._coefficient;
1604
- const exponent = this._exponent + b._exponent;
1605
- return this.normalize(sign, coefficient, exponent);
1606
- }
1607
- /**
1608
- * Alias for multiply — mathjs / Decimal.js compatibility.
1609
- */
1610
- mul(other) {
1611
- return this.multiply(other);
1612
- }
1613
- /**
1614
- * Division
1615
- */
1616
- divide(other) {
1617
- const b = this.ensureBigNumber(other);
1618
- if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
1619
- if (this._isInfinite && b._isInfinite) return new _BigNumber(0, 0n, 0, true);
1620
- if (b._sign === 0) {
1621
- if (this._sign === 0) return new _BigNumber(0, 0n, 0, true);
1622
- return new _BigNumber(this._sign, 0n, 0, false, true);
1623
- }
1624
- if (this._isInfinite) {
1625
- const sign2 = this._sign * b._sign;
1626
- return new _BigNumber(sign2, 0n, 0, false, true);
1627
- }
1628
- if (b._isInfinite) return new _BigNumber(0, 0n, 0);
1629
- if (this._sign === 0) return new _BigNumber(0, 0n, 0);
1630
- const sign = this._sign * b._sign;
1631
- const precision = globalConfig.precision;
1632
- const scale = BigInt(10) ** BigInt(precision + 10);
1633
- const scaledDividend = this._coefficient * scale;
1634
- const quotient = scaledDividend / b._coefficient;
1635
- const exponent = this._exponent - b._exponent - precision - 10;
1636
- return this.normalize(sign, quotient, exponent).roundToPrecision(precision);
1637
- }
1638
- /**
1639
- * Negation
1640
- */
1641
- negate() {
1642
- if (this._isNaN) return this;
1643
- if (this._sign === 0) return this;
1644
- const newSign = this._sign === 1 ? -1 : 1;
1645
- return new _BigNumber(newSign, this._coefficient, this._exponent, false, this._isInfinite);
1646
- }
1647
- /**
1648
- * Absolute value
1649
- */
1650
- abs() {
1651
- if (this._isNaN) return this;
1652
- if (this._sign === 0) return this;
1653
- return new _BigNumber(1, this._coefficient, this._exponent, false, this._isInfinite);
1654
- }
1655
- /**
1656
- * Power (integer exponent)
1657
- */
1658
- pow(n) {
1659
- const exp = typeof n === "bigint" ? Number(n) : n;
1660
- if (this._isNaN) return this;
1661
- if (exp === 0) return _BigNumber.fromNumber(1);
1662
- if (this._sign === 0) {
1663
- if (exp < 0) return new _BigNumber(1, 0n, 0, false, true);
1664
- return this;
1665
- }
1666
- if (exp < 0) {
1667
- return _BigNumber.fromNumber(1).divide(this.pow(-exp));
1668
- }
1669
- let result = _BigNumber.fromNumber(1);
1670
- let base = this.clone();
1671
- let e = exp;
1672
- while (e > 0) {
1673
- if (e % 2 === 1) {
1674
- result = result.multiply(base);
1675
- }
1676
- base = base.multiply(base);
1677
- e = Math.floor(e / 2);
1678
- }
1679
- return result.roundToPrecision(globalConfig.precision);
1680
- }
1681
- /**
1682
- * Square root
1683
- */
1684
- sqrt() {
1685
- if (this._isNaN) return this;
1686
- if (this._sign === -1) return new _BigNumber(0, 0n, 0, true);
1687
- if (this._sign === 0) return this;
1688
- if (this._isInfinite) return this;
1689
- const precision = globalConfig.precision;
1690
- let guess = _BigNumber.fromNumber(Math.sqrt(this.valueOf()));
1691
- for (let i = 0; i < 100; i++) {
1692
- const newGuess = guess.add(this.divide(guess)).divide(_BigNumber.fromNumber(2));
1693
- if (guess.subtract(newGuess).abs().compareTo(guess.multiply(_BigNumber.parse("1e-" + (precision + 5)))) <= 0) {
1694
- return newGuess.roundToPrecision(precision);
1695
- }
1696
- guess = newGuess;
1697
- }
1698
- return guess.roundToPrecision(precision);
1699
- }
1700
- // ============================================================
1701
- // Comparison Methods
1702
- // ============================================================
1703
- equals(other) {
1704
- return _BigNumber.compare(this, other) === 0;
1705
- }
1706
- lessThan(other) {
1707
- return _BigNumber.compare(this, other) < 0;
1708
- }
1709
- lessThanOrEqual(other) {
1710
- return _BigNumber.compare(this, other) <= 0;
1711
- }
1712
- greaterThan(other) {
1713
- return _BigNumber.compare(this, other) > 0;
1714
- }
1715
- greaterThanOrEqual(other) {
1716
- return _BigNumber.compare(this, other) >= 0;
1717
- }
1718
- compareTo(other) {
1719
- return _BigNumber.compare(this, other);
1720
- }
1721
- compare(other) {
1722
- return this.compareTo(other);
1723
- }
1724
- /**
1725
- * Returns true iff this > other.
1726
- * Accepts the same argument types as `add`/`multiply` (BigNumber, number, or string).
1727
- * Named `gt` for Decimal.js / mathjs formatter compatibility.
1728
- */
1729
- gt(other) {
1730
- return this.greaterThan(this.ensureBigNumber(other));
1731
- }
1732
- // ============================================================
1733
- // Rounding Methods
1734
- // ============================================================
1735
- /**
1736
- * Round to specified decimal places
1737
- */
1738
- round(decimalPlaces = 0, mode = globalConfig.rounding) {
1739
- if (this._isNaN || this._isInfinite || this._sign === 0) return this;
1740
- const targetExp = -decimalPlaces;
1741
- if (this._exponent >= targetExp) return this;
1742
- const shift = targetExp - this._exponent;
1743
- const divisor = BigInt(10) ** BigInt(shift);
1744
- const quotient = this._coefficient / divisor;
1745
- const remainder = this._coefficient % divisor;
1746
- let rounded = quotient;
1747
- const halfDivisor = divisor / 2n;
1748
- const shouldRoundUp = this.shouldRound(remainder, halfDivisor, divisor, quotient, mode);
1749
- if (shouldRoundUp) {
1750
- rounded += 1n;
1751
- }
1752
- return this.normalize(rounded === 0n ? 0 : this._sign, rounded, targetExp);
1753
- }
1754
- shouldRound(remainder, halfDivisor, divisor, quotient, mode) {
1755
- const isPositive = this._sign === 1;
1756
- const isExactlyHalf = remainder === halfDivisor && divisor % 2n === 0n;
1757
- const isMoreThanHalf = remainder > halfDivisor;
1758
- switch (mode) {
1759
- case "up":
1760
- return remainder > 0n;
1761
- case "down":
1762
- return false;
1763
- case "ceil":
1764
- return isPositive && remainder > 0n;
1765
- case "floor":
1766
- return !isPositive && remainder > 0n;
1767
- case "halfUp":
1768
- return isMoreThanHalf || isExactlyHalf;
1769
- case "halfDown":
1770
- return isMoreThanHalf;
1771
- case "halfEven":
1772
- return isMoreThanHalf || isExactlyHalf && quotient % 2n !== 0n;
1773
- case "halfCeil":
1774
- return isMoreThanHalf || isExactlyHalf && isPositive;
1775
- case "halfFloor":
1776
- return isMoreThanHalf || isExactlyHalf && !isPositive;
1777
- default:
1778
- return isMoreThanHalf || isExactlyHalf;
1779
- }
1780
- }
1781
- /**
1782
- * Round to specified precision (significant digits)
1783
- */
1784
- roundToPrecision(precision, mode = globalConfig.rounding) {
1785
- if (this._isNaN || this._isInfinite || this._sign === 0) return this;
1786
- const digits = this._coefficient.toString();
1787
- if (digits.length <= precision) return this;
1788
- const digitsToRemove = digits.length - precision;
1789
- const divisor = BigInt(10) ** BigInt(digitsToRemove);
1790
- const quotient = this._coefficient / divisor;
1791
- const remainder = this._coefficient % divisor;
1792
- const halfDivisor = divisor / 2n;
1793
- let rounded = quotient;
1794
- const shouldRoundUp = this.shouldRound(remainder, halfDivisor, divisor, quotient, mode);
1795
- if (shouldRoundUp) {
1796
- rounded += 1n;
1797
- }
1798
- const newExponent = this._exponent + digitsToRemove;
1799
- 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);
1800
95
  }
1801
- floor() {
1802
- return this.round(0, "floor");
96
+ mul(o) {
97
+ return new _Dual(this.value * o.value, this.deriv * o.value + this.value * o.deriv);
1803
98
  }
1804
- ceil() {
1805
- 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);
1806
102
  }
1807
- trunc() {
1808
- return this.round(0, "down");
103
+ neg() {
104
+ return new _Dual(-this.value, -this.deriv);
1809
105
  }
1810
- /**
1811
- * Round to `n` significant decimal digits and return a new BigNumber.
1812
- * Delegates to `roundToPrecision`, using the global rounding mode unless
1813
- * an explicit `roundingMode` is supplied.
1814
- *
1815
- * Named `toSignificantDigits` for Decimal.js / mathjs formatter compatibility.
1816
- * When `n` is undefined the value is returned unchanged (no rounding).
1817
- */
1818
- toSignificantDigits(n, roundingMode) {
1819
- if (n === void 0) return this.clone();
1820
- 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));
1821
109
  }
1822
- /**
1823
- * The decimal exponent of this number: `floor(log10(|x|))`.
1824
- *
1825
- * Matches Decimal.js semantics:
1826
- * - `12345` → `4` (5 digits → the most-significant place is 10^4)
1827
- * - `0.0123` → `-2` (first significant digit is at 10^-2)
1828
- * - `100` → `2`
1829
- * - `0.01` → `-2`
1830
- * - `0` → `0` (by convention; `isZero()` can be used to distinguish)
1831
- *
1832
- * For special values (NaN, ±Infinity) returns 0 — callers check
1833
- * `isFinite()` / `isNaN()` before using `.e`.
1834
- */
1835
- get e() {
1836
- if (this._isNaN || this._isInfinite || this._sign === 0) return 0;
1837
- const d = this._coefficient.toString().length;
1838
- 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);
1839
115
  }
1840
- // ============================================================
1841
- // Modular Arithmetic
1842
- // ============================================================
1843
- /**
1844
- * Modulo (remainder after division)
1845
- * Result has the same sign as the dividend (this).
1846
- */
1847
- mod(other) {
1848
- const b = this.ensureBigNumber(other);
1849
- if (this._isNaN || b._isNaN || b._sign === 0) return new _BigNumber(0, 0n, 0, true);
1850
- if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
1851
- if (b._isInfinite) return this;
1852
- if (this._sign === 0) return this;
1853
- const quotient = this.divide(b).trunc();
1854
- 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));
1855
123
  }
1856
- // ============================================================
1857
- // Trigonometric Functions
1858
- // ============================================================
1859
- /**
1860
- * Sine of this BigNumber (in radians)
1861
- * Uses Taylor series: sin(x) = x - x^3/3! + x^5/5! - ...
1862
- */
1863
124
  sin() {
1864
- if (this._isNaN) return this;
1865
- if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
1866
- if (this._sign === 0) return this;
1867
- const x = this._reduceAngle();
1868
- return x._sinTaylor();
125
+ return this.unary(DUAL_UNARY_RULES.sin);
1869
126
  }
1870
- /**
1871
- * Cosine of this BigNumber (in radians)
1872
- * Uses Taylor series: cos(x) = 1 - x^2/2! + x^4/4! - ...
1873
- */
1874
127
  cos() {
1875
- if (this._isNaN) return this;
1876
- if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
1877
- if (this._sign === 0) return _BigNumber.fromNumber(1);
1878
- const x = this._reduceAngle();
1879
- return x._cosTaylor();
128
+ return this.unary(DUAL_UNARY_RULES.cos);
1880
129
  }
1881
- /**
1882
- * Tangent of this BigNumber (in radians)
1883
- * tan(x) = sin(x) / cos(x)
1884
- */
1885
130
  tan() {
1886
- if (this._isNaN) return this;
1887
- if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
1888
- if (this._sign === 0) return this;
1889
- const x = this._reduceAngle();
1890
- return x._sinTaylor().divide(x._cosTaylor());
131
+ return this.unary(DUAL_UNARY_RULES.tan);
1891
132
  }
1892
- /**
1893
- * Arcsine of this BigNumber
1894
- * Returns value in [-PI/2, PI/2]
1895
- */
1896
- asin() {
1897
- if (this._isNaN) return this;
1898
- const one = _BigNumber.fromNumber(1);
1899
- if (this.abs().compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
1900
- if (this._sign === 0) return this;
1901
- const xSquared = this.multiply(this);
1902
- const denominator = one.subtract(xSquared).sqrt();
1903
- if (denominator.isZero()) {
1904
- return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
1905
- }
1906
- return this.divide(denominator).atan();
133
+ exp() {
134
+ return this.unary(DUAL_UNARY_RULES.exp);
1907
135
  }
1908
- /**
1909
- * Arccosine of this BigNumber
1910
- * Returns value in [0, PI]
1911
- */
1912
- acos() {
1913
- if (this._isNaN) return this;
1914
- const one = _BigNumber.fromNumber(1);
1915
- if (this.abs().compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
1916
- return BIGNUMBER_PI.divide(2).subtract(this.asin());
136
+ log() {
137
+ return this.unary(DUAL_UNARY_RULES.log);
1917
138
  }
1918
- /**
1919
- * Arctangent of this BigNumber
1920
- * Returns value in (-PI/2, PI/2)
1921
- * Uses Taylor series with argument reduction for convergence.
1922
- */
1923
- atan() {
1924
- if (this._isNaN) return this;
1925
- if (this._sign === 0) return this;
1926
- if (this._isInfinite) {
1927
- return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
1928
- }
1929
- const one = _BigNumber.fromNumber(1);
1930
- if (this.abs().compareTo(one) > 0) {
1931
- const reciprocal = one.divide(this);
1932
- const piHalf = BIGNUMBER_PI.divide(2);
1933
- return this._sign === 1 ? piHalf.subtract(reciprocal.atan()) : piHalf.negate().subtract(reciprocal.atan());
1934
- }
1935
- const half = _BigNumber.fromNumber(0.5);
1936
- if (this.abs().compareTo(half) > 0) {
1937
- const xSq = this.multiply(this);
1938
- const reduced = this.divide(one.add(one.add(xSq).sqrt()));
1939
- return reduced.atan().multiply(_BigNumber.fromNumber(2));
1940
- }
1941
- return this._atanTaylor();
139
+ sqrt() {
140
+ return this.unary(DUAL_UNARY_RULES.sqrt);
1942
141
  }
1943
- /**
1944
- * Two-argument arctangent: atan2(y, x)
1945
- * this = y, argument = x
1946
- * Returns angle in (-PI, PI]
1947
- */
1948
- atan2(x) {
1949
- if (this._isNaN || x._isNaN) return new _BigNumber(0, 0n, 0, true);
1950
- if (this._sign === 0 && x._sign === 0) return _BigNumber.fromNumber(0);
1951
- if (x._sign === 0) {
1952
- return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
1953
- }
1954
- const angle = this.divide(x).atan();
1955
- if (x.isPositive()) {
1956
- return angle;
1957
- } else if (this.isNegative()) {
1958
- return angle.subtract(BIGNUMBER_PI);
1959
- } else {
1960
- return angle.add(BIGNUMBER_PI);
1961
- }
142
+ square() {
143
+ return this.unary(DUAL_UNARY_RULES.square);
144
+ }
145
+ abs() {
146
+ return this.unary(DUAL_UNARY_RULES.abs);
1962
147
  }
1963
- // ============================================================
1964
- // Hyperbolic Functions
1965
- // ============================================================
1966
- /**
1967
- * Hyperbolic sine: sinh(x) = (e^x - e^(-x)) / 2
1968
- */
1969
148
  sinh() {
1970
- if (this._isNaN) return this;
1971
- if (this._isInfinite) return this;
1972
- if (this._sign === 0) return this;
1973
- const ex = this.exp();
1974
- const enx = this.negate().exp();
1975
- return ex.subtract(enx).divide(_BigNumber.fromNumber(2));
149
+ return this.unary(DUAL_UNARY_RULES.sinh);
1976
150
  }
1977
- /**
1978
- * Hyperbolic cosine: cosh(x) = (e^x + e^(-x)) / 2
1979
- */
1980
151
  cosh() {
1981
- if (this._isNaN) return this;
1982
- if (this._isInfinite) return new _BigNumber(1, 0n, 0, false, true);
1983
- if (this._sign === 0) return _BigNumber.fromNumber(1);
1984
- const ex = this.exp();
1985
- const enx = this.negate().exp();
1986
- return ex.add(enx).divide(_BigNumber.fromNumber(2));
152
+ return this.unary(DUAL_UNARY_RULES.cosh);
1987
153
  }
1988
- /**
1989
- * Hyperbolic tangent: tanh(x) = sinh(x) / cosh(x)
1990
- */
1991
154
  tanh() {
1992
- if (this._isNaN) return this;
1993
- if (this._sign === 0) return this;
1994
- if (this._isInfinite) return _BigNumber.fromNumber(this._sign);
1995
- const ex = this.exp();
1996
- const enx = this.negate().exp();
1997
- return ex.subtract(enx).divide(ex.add(enx));
1998
- }
1999
- /**
2000
- * Inverse hyperbolic sine: asinh(x) = ln(x + sqrt(x^2 + 1))
2001
- */
2002
- asinh() {
2003
- if (this._isNaN) return this;
2004
- if (this._isInfinite) return this;
2005
- if (this._sign === 0) return this;
2006
- const one = _BigNumber.fromNumber(1);
2007
- return this.add(this.multiply(this).add(one).sqrt()).ln();
2008
- }
2009
- /**
2010
- * Inverse hyperbolic cosine: acosh(x) = ln(x + sqrt(x^2 - 1))
2011
- * Domain: x >= 1
2012
- */
2013
- acosh() {
2014
- if (this._isNaN) return this;
2015
- const one = _BigNumber.fromNumber(1);
2016
- if (this.compareTo(one) < 0) return new _BigNumber(0, 0n, 0, true);
2017
- if (this._isInfinite) return this;
2018
- return this.add(this.multiply(this).subtract(one).sqrt()).ln();
2019
- }
2020
- /**
2021
- * Inverse hyperbolic tangent: atanh(x) = 0.5 * ln((1+x)/(1-x))
2022
- * Domain: -1 < x < 1
2023
- */
2024
- atanh() {
2025
- if (this._isNaN) return this;
2026
- const one = _BigNumber.fromNumber(1);
2027
- const absVal = this.abs();
2028
- if (absVal.compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
2029
- if (absVal.equals(one)) {
2030
- return this._sign === 1 ? new _BigNumber(1, 0n, 0, false, true) : new _BigNumber(-1, 0n, 0, false, true);
2031
- }
2032
- if (this._sign === 0) return this;
2033
- const half = _BigNumber.fromNumber(0.5);
2034
- return one.add(this).divide(one.subtract(this)).ln().multiply(half);
2035
- }
2036
- // ============================================================
2037
- // Transcendental Functions
2038
- // ============================================================
2039
- /**
2040
- * Exponential function: e^x
2041
- * Uses Taylor series: e^x = 1 + x + x^2/2! + x^3/3! + ...
2042
- * With argument reduction: e^x = (e^(x/2^k))^(2^k) for faster convergence.
2043
- */
2044
- exp() {
2045
- if (this._isNaN) return this;
2046
- if (this._sign === 0) return _BigNumber.fromNumber(1);
2047
- if (this._isInfinite) {
2048
- return this._sign === 1 ? this : _BigNumber.fromNumber(0);
2049
- }
2050
- const precision = globalConfig.precision;
2051
- const val = Math.abs(this.valueOf());
2052
- let k = 0;
2053
- if (val > 0.5) {
2054
- k = Math.ceil(Math.log2(val * 2));
2055
- }
2056
- const divisor = _BigNumber.fromNumber(2).pow(k);
2057
- const reduced = this.divide(divisor);
2058
- let sum = _BigNumber.fromNumber(1);
2059
- let term = _BigNumber.fromNumber(1);
2060
- const maxIter = precision + 20;
2061
- for (let n = 1; n <= maxIter; n++) {
2062
- term = term.multiply(reduced).divide(_BigNumber.fromNumber(n));
2063
- const newSum = sum.add(term);
2064
- if (sum.equals(newSum)) break;
2065
- sum = newSum;
2066
- }
2067
- for (let i = 0; i < k; i++) {
2068
- sum = sum.multiply(sum);
2069
- }
2070
- return sum.roundToPrecision(precision);
2071
- }
2072
- /**
2073
- * Natural logarithm: ln(x)
2074
- * Uses the AGM (arithmetic-geometric mean) method for fast convergence.
2075
- * Fallback: series ln((1+y)/(1-y)) = 2*(y + y^3/3 + y^5/5 + ...) where y = (x-1)/(x+1)
2076
- */
2077
- ln() {
2078
- if (this._isNaN) return this;
2079
- if (this._sign === -1) return new _BigNumber(0, 0n, 0, true);
2080
- if (this._sign === 0) return new _BigNumber(-1, 0n, 0, false, true);
2081
- if (this._isInfinite) return this;
2082
- const one = _BigNumber.fromNumber(1);
2083
- if (this.equals(one)) return _BigNumber.fromNumber(0);
2084
- const precision = globalConfig.precision;
2085
- let x = this.clone();
2086
- let k = 0;
2087
- const two = _BigNumber.fromNumber(2);
2088
- const half = _BigNumber.fromNumber(0.5);
2089
- while (x.compareTo(two) > 0) {
2090
- x = x.divide(two);
2091
- k++;
2092
- }
2093
- while (x.compareTo(half) < 0) {
2094
- x = x.multiply(two);
2095
- k--;
2096
- }
2097
- const y = x.subtract(one).divide(x.add(one));
2098
- const ySq = y.multiply(y);
2099
- let term = y;
2100
- let sum = y;
2101
- const maxIter = precision + 20;
2102
- for (let n = 1; n <= maxIter; n++) {
2103
- term = term.multiply(ySq);
2104
- const contribution = term.divide(_BigNumber.fromNumber(2 * n + 1));
2105
- const newSum = sum.add(contribution);
2106
- if (sum.equals(newSum)) break;
2107
- sum = newSum;
2108
- }
2109
- sum = sum.multiply(two);
2110
- if (k !== 0) {
2111
- sum = sum.add(BIGNUMBER_LN2.multiply(_BigNumber.fromNumber(k)));
2112
- }
2113
- return sum.roundToPrecision(precision);
2114
- }
2115
- /**
2116
- * Base-10 logarithm: log10(x) = ln(x) / ln(10)
2117
- */
2118
- log10() {
2119
- return this.ln().divide(BIGNUMBER_LN10);
2120
- }
2121
- /**
2122
- * Base-2 logarithm: log2(x) = ln(x) / ln(2)
2123
- */
2124
- log2() {
2125
- return this.ln().divide(BIGNUMBER_LN2);
2126
- }
2127
- /**
2128
- * Cube root
2129
- * Uses Newton-Raphson iteration.
2130
- */
2131
- cbrt() {
2132
- if (this._isNaN) return this;
2133
- if (this._sign === 0) return this;
2134
- if (this._isInfinite) return this;
2135
- if (this._sign === -1) {
2136
- return this.negate().cbrt().negate();
2137
- }
2138
- const precision = globalConfig.precision;
2139
- const three = _BigNumber.fromNumber(3);
2140
- let guess = _BigNumber.fromNumber(Math.cbrt(this.valueOf()));
2141
- for (let i = 0; i < 100; i++) {
2142
- const guessSquared = guess.multiply(guess);
2143
- const newGuess = guess.multiply(_BigNumber.fromNumber(2)).add(this.divide(guessSquared)).divide(three);
2144
- if (guess.subtract(newGuess).abs().compareTo(guess.abs().multiply(_BigNumber.parse("1e-" + (precision + 5)))) <= 0) {
2145
- return newGuess.roundToPrecision(precision);
2146
- }
2147
- guess = newGuess;
2148
- }
2149
- return guess.roundToPrecision(precision);
2150
- }
2151
- /**
2152
- * e^x - 1 (more precise than exp(x) - 1 for small x)
2153
- * Uses Taylor series directly: expm1(x) = x + x^2/2! + x^3/3! + ...
2154
- */
2155
- expm1() {
2156
- if (this._isNaN) return this;
2157
- if (this._sign === 0) return this;
2158
- if (this._isInfinite) {
2159
- return this._sign === 1 ? this : _BigNumber.fromNumber(-1);
2160
- }
2161
- if (Math.abs(this.valueOf()) > 0.5) {
2162
- return this.exp().subtract(_BigNumber.fromNumber(1));
2163
- }
2164
- const precision = globalConfig.precision;
2165
- let term = this.clone();
2166
- let sum = this.clone();
2167
- const maxIter = precision + 20;
2168
- for (let n = 2; n <= maxIter; n++) {
2169
- term = term.multiply(this).divide(_BigNumber.fromNumber(n));
2170
- const newSum = sum.add(term);
2171
- if (sum.equals(newSum)) break;
2172
- sum = newSum;
2173
- }
2174
- return sum.roundToPrecision(precision);
2175
- }
2176
- /**
2177
- * ln(1 + x) (more precise than ln(1 + x) for small x)
2178
- */
2179
- log1p() {
2180
- if (this._isNaN) return this;
2181
- const one = _BigNumber.fromNumber(1);
2182
- const negOne = _BigNumber.fromNumber(-1);
2183
- if (this.compareTo(negOne) < 0) return new _BigNumber(0, 0n, 0, true);
2184
- if (this.equals(negOne)) return new _BigNumber(-1, 0n, 0, false, true);
2185
- if (this._sign === 0) return this;
2186
- return one.add(this).ln();
2187
- }
2188
- /**
2189
- * Hypotenuse: sqrt(this^2 + other^2)
2190
- */
2191
- hypot(other) {
2192
- if (this._isNaN || other._isNaN) return new _BigNumber(0, 0n, 0, true);
2193
- if (this._isInfinite || other._isInfinite) return new _BigNumber(1, 0n, 0, false, true);
2194
- return this.multiply(this).add(other.multiply(other)).sqrt();
2195
- }
2196
- // ============================================================
2197
- // Private Taylor Series Helpers
2198
- // ============================================================
2199
- /** Reduce angle to [-PI, PI] range */
2200
- _reduceAngle() {
2201
- const twoPi = BIGNUMBER_PI.multiply(_BigNumber.fromNumber(2));
2202
- if (this.abs().compareTo(BIGNUMBER_PI) <= 0) {
2203
- return this;
2204
- }
2205
- const quotient = this.divide(twoPi).round(0, "halfUp");
2206
- let reduced = this.subtract(twoPi.multiply(quotient));
2207
- if (reduced.compareTo(BIGNUMBER_PI) > 0) {
2208
- reduced = reduced.subtract(twoPi);
2209
- } else if (reduced.compareTo(BIGNUMBER_PI.negate()) < 0) {
2210
- reduced = reduced.add(twoPi);
2211
- }
2212
- return reduced;
2213
- }
2214
- /** Taylor series for sin(x), assumes x is in [-PI, PI] */
2215
- _sinTaylor() {
2216
- const precision = globalConfig.precision;
2217
- let term = this.clone();
2218
- let sum = this.clone();
2219
- const xSquared = this.multiply(this);
2220
- const maxIter = precision + 20;
2221
- for (let n = 1; n <= maxIter; n++) {
2222
- term = term.multiply(xSquared).divide(_BigNumber.fromNumber(2 * n * (2 * n + 1))).negate();
2223
- const newSum = sum.add(term);
2224
- if (sum.equals(newSum)) break;
2225
- sum = newSum;
2226
- }
2227
- return sum.roundToPrecision(precision);
2228
- }
2229
- /** Taylor series for cos(x), assumes x is in [-PI, PI] */
2230
- _cosTaylor() {
2231
- const precision = globalConfig.precision;
2232
- let term = _BigNumber.fromNumber(1);
2233
- let sum = _BigNumber.fromNumber(1);
2234
- const xSquared = this.multiply(this);
2235
- const maxIter = precision + 20;
2236
- for (let n = 1; n <= maxIter; n++) {
2237
- term = term.multiply(xSquared).divide(_BigNumber.fromNumber((2 * n - 1) * (2 * n))).negate();
2238
- const newSum = sum.add(term);
2239
- if (sum.equals(newSum)) break;
2240
- sum = newSum;
2241
- }
2242
- return sum.roundToPrecision(precision);
2243
- }
2244
- /** Taylor series for atan(x), assumes |x| <= 0.5 */
2245
- _atanTaylor() {
2246
- const precision = globalConfig.precision;
2247
- const xSquared = this.multiply(this);
2248
- let term = this.clone();
2249
- let sum = this.clone();
2250
- const maxIter = precision + 20;
2251
- for (let n = 1; n <= maxIter; n++) {
2252
- term = term.multiply(xSquared).negate();
2253
- const contribution = term.divide(_BigNumber.fromNumber(2 * n + 1));
2254
- const newSum = sum.add(contribution);
2255
- if (sum.equals(newSum)) break;
2256
- sum = newSum;
2257
- }
2258
- return sum.roundToPrecision(precision);
2259
- }
2260
- // ============================================================
2261
- // Utility Methods
2262
- // ============================================================
2263
- isNaN() {
2264
- return this._isNaN;
2265
- }
2266
- isFinite() {
2267
- return !this._isNaN && !this._isInfinite;
2268
- }
2269
- isInfinite() {
2270
- return this._isInfinite;
2271
- }
2272
- isZero() {
2273
- return this._sign === 0 && !this._isNaN;
2274
- }
2275
- isPositive() {
2276
- return this._sign === 1;
2277
- }
2278
- isNegative() {
2279
- return this._sign === -1;
2280
- }
2281
- isInteger() {
2282
- if (this._isNaN || this._isInfinite || this._sign === 0) return this._sign === 0;
2283
- return this._exponent >= 0;
2284
- }
2285
- sign() {
2286
- return this._sign;
2287
- }
2288
- clone() {
2289
- return new _BigNumber(
2290
- this._sign,
2291
- this._coefficient,
2292
- this._exponent,
2293
- this._isNaN,
2294
- this._isInfinite
2295
- );
2296
- }
2297
- // ============================================================
2298
- // Private Helper Methods
2299
- // ============================================================
2300
- ensureBigNumber(value) {
2301
- if (value instanceof _BigNumber) return value;
2302
- if (typeof value === "number") return _BigNumber.fromNumber(value);
2303
- if (typeof value === "string") return _BigNumber.parse(value);
2304
- return _BigNumber.fromNumber(Number(value.valueOf()));
2305
- }
2306
- alignExponents(a, b) {
2307
- const minExp = Math.min(a._exponent, b._exponent);
2308
- const aShift = a._exponent - minExp;
2309
- const bShift = b._exponent - minExp;
2310
- const aCoef = aShift > 0 ? a._coefficient * BigInt(10) ** BigInt(aShift) : a._coefficient;
2311
- const bCoef = bShift > 0 ? b._coefficient * BigInt(10) ** BigInt(bShift) : b._coefficient;
2312
- return [aCoef, bCoef, minExp];
155
+ return this.unary(DUAL_UNARY_RULES.tanh);
2313
156
  }
2314
- normalize(sign, coefficient, exponent) {
2315
- if (coefficient === 0n) {
2316
- return new _BigNumber(0, 0n, 0);
2317
- }
2318
- let coef = coefficient;
2319
- let exp = exponent;
2320
- while (coef % 10n === 0n && coef !== 0n) {
2321
- coef = coef / 10n;
2322
- exp++;
2323
- }
2324
- return new _BigNumber(sign, coef, exp);
157
+ toString() {
158
+ return `Dual(${this.value}, ${this.deriv})`;
2325
159
  }
2326
160
  };
2327
- var BIGNUMBER_ZERO = BigNumber.fromNumber(0);
2328
- var BIGNUMBER_ONE = BigNumber.fromNumber(1);
2329
- var BIGNUMBER_NEG_ONE = BigNumber.fromNumber(-1);
2330
- var BIGNUMBER_TEN = BigNumber.fromNumber(10);
2331
- var BIGNUMBER_PI = BigNumber.parse("3.14159265358979323846264338327950288419716939937510");
2332
- var BIGNUMBER_E = BigNumber.parse("2.71828182845904523536028747135266249775724709369995");
2333
- var BIGNUMBER_LN2 = BigNumber.parse(
2334
- "0.69314718055994530941723212145817656807550013436026"
2335
- );
2336
- var BIGNUMBER_LN10 = BigNumber.parse(
2337
- "2.30258509299404568401799145468436420760110148862877"
2338
- );
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;
2339
176
 
2340
177
  // src/types/unit-definitions.ts
2341
178
  var DIMENSIONLESS = Object.freeze({
@@ -2565,449 +402,6 @@ function getPrefix(name) {
2565
402
  return SI_PREFIXES[name];
2566
403
  }
2567
404
 
2568
- // src/types/unit.ts
2569
- var DimensionMismatchError = class extends Error {
2570
- constructor(left, right, op) {
2571
- super(
2572
- `Dimension mismatch in ${op}: ${formatDimensions(left)} vs ${formatDimensions(right)}`
2573
- );
2574
- this.left = left;
2575
- this.right = right;
2576
- }
2577
- left;
2578
- right;
2579
- name = "DimensionMismatchError";
2580
- };
2581
- var UnitParseError = class extends Error {
2582
- name = "UnitParseError";
2583
- constructor(notation, reason) {
2584
- super(`Cannot parse unit notation "${notation}": ${reason}`);
2585
- }
2586
- };
2587
- var DIM_KEYS = [
2588
- "length",
2589
- "mass",
2590
- "time",
2591
- "current",
2592
- "temperature",
2593
- "amount",
2594
- "luminosity"
2595
- ];
2596
- function dimsEqual(a, b) {
2597
- for (const k of DIM_KEYS) {
2598
- if (a[k] !== b[k]) return false;
2599
- }
2600
- return true;
2601
- }
2602
- function dimsAdd(a, b) {
2603
- return {
2604
- length: a.length + b.length,
2605
- mass: a.mass + b.mass,
2606
- time: a.time + b.time,
2607
- current: a.current + b.current,
2608
- temperature: a.temperature + b.temperature,
2609
- amount: a.amount + b.amount,
2610
- luminosity: a.luminosity + b.luminosity
2611
- };
2612
- }
2613
- function dimsSub(a, b) {
2614
- return {
2615
- length: a.length - b.length,
2616
- mass: a.mass - b.mass,
2617
- time: a.time - b.time,
2618
- current: a.current - b.current,
2619
- temperature: a.temperature - b.temperature,
2620
- amount: a.amount - b.amount,
2621
- luminosity: a.luminosity - b.luminosity
2622
- };
2623
- }
2624
- function dimsScale(a, n) {
2625
- return {
2626
- length: a.length * n,
2627
- mass: a.mass * n,
2628
- time: a.time * n,
2629
- current: a.current * n,
2630
- temperature: a.temperature * n,
2631
- amount: a.amount * n,
2632
- luminosity: a.luminosity * n
2633
- };
2634
- }
2635
- function isDimensionless(d) {
2636
- return dimsEqual(d, DIMENSIONLESS);
2637
- }
2638
- function formatDimensions(d) {
2639
- const parts = [];
2640
- for (const k of DIM_KEYS) {
2641
- const e = d[k];
2642
- if (e !== 0) parts.push(`${k}^${e}`);
2643
- }
2644
- return parts.length === 0 ? "dimensionless" : parts.join("\xB7");
2645
- }
2646
- function resolveAtom(token) {
2647
- const aliased = UNIT_ALIASES[token] ?? token;
2648
- const direct = getUnitDef(aliased);
2649
- if (direct) {
2650
- return {
2651
- multiplier: direct.multiplier,
2652
- offset: direct.offset ?? 0,
2653
- dimensions: direct.dimensions,
2654
- prefix: "",
2655
- base: aliased
2656
- };
2657
- }
2658
- for (const prefix of SI_PREFIX_KEYS) {
2659
- if (!aliased.startsWith(prefix) || aliased.length === prefix.length) continue;
2660
- const rest = aliased.slice(prefix.length);
2661
- const baseDef = getUnitDef(rest);
2662
- if (!baseDef) continue;
2663
- if (!baseDef.prefixable) continue;
2664
- return {
2665
- multiplier: baseDef.multiplier * SI_PREFIXES[prefix],
2666
- // Offset is in base units, so prefix the multiplier but not the offset
2667
- // (we never apply prefixes to temperature units in practice anyway).
2668
- offset: baseDef.offset ?? 0,
2669
- dimensions: baseDef.dimensions,
2670
- prefix,
2671
- base: rest
2672
- };
2673
- }
2674
- throw new UnitParseError(token, `unknown unit "${token}"`);
2675
- }
2676
- function splitScalar(input) {
2677
- const m = input.match(/^\s*([+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\s+(.*)$/);
2678
- if (m) {
2679
- return { scalar: parseFloat(m[1]), rest: m[2].trim() };
2680
- }
2681
- const scalarOnly = input.match(/^\s*([+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\s*$/);
2682
- if (scalarOnly) {
2683
- return { scalar: parseFloat(scalarOnly[1]), rest: "" };
2684
- }
2685
- return { scalar: 1, rest: input.trim() };
2686
- }
2687
- function parseUnitExpr(expr) {
2688
- if (expr === "" || expr === "1") return [];
2689
- const normalized = expr.replace(/[·⋅]/g, "*");
2690
- const atoms = [];
2691
- let pos = 0;
2692
- let nextSign = 1;
2693
- while (pos < normalized.length) {
2694
- while (pos < normalized.length && /\s/.test(normalized[pos])) pos++;
2695
- if (pos >= normalized.length) break;
2696
- const ch = normalized[pos];
2697
- if (ch === "*") {
2698
- pos++;
2699
- continue;
2700
- }
2701
- if (ch === "/") {
2702
- nextSign = -1;
2703
- pos++;
2704
- continue;
2705
- }
2706
- if (ch === "1") {
2707
- const next = normalized[pos + 1];
2708
- if (next === void 0 || next === " " || next === "/" || next === "*") {
2709
- pos++;
2710
- continue;
2711
- }
2712
- }
2713
- if (!/[A-Za-z°µΩ]/.test(ch)) {
2714
- throw new UnitParseError(expr, `unexpected character "${ch}" at position ${pos}`);
2715
- }
2716
- const idStart = pos;
2717
- while (pos < normalized.length && /[A-Za-z°µΩ]/.test(normalized[pos])) pos++;
2718
- const identifier = normalized.slice(idStart, pos);
2719
- let exponent = 1;
2720
- if (pos < normalized.length && normalized[pos] === "^") {
2721
- pos++;
2722
- const expMatch = normalized.slice(pos).match(/^([+-]?\d+(?:\.\d+)?)/);
2723
- if (!expMatch) {
2724
- throw new UnitParseError(expr, `expected exponent after "^" at position ${pos}`);
2725
- }
2726
- exponent = parseFloat(expMatch[1]);
2727
- pos += expMatch[1].length;
2728
- } else {
2729
- const supMatch = normalized.slice(pos).match(/^([²³⁴⁵⁶⁷⁸⁹⁰¹]+)/);
2730
- if (supMatch) {
2731
- exponent = parseSuperscript(supMatch[1]);
2732
- pos += supMatch[1].length;
2733
- }
2734
- }
2735
- const resolved = resolveAtom(identifier);
2736
- atoms.push({
2737
- multiplier: resolved.multiplier,
2738
- offset: resolved.offset,
2739
- dimensions: resolved.dimensions,
2740
- exponent: nextSign * exponent,
2741
- source: identifier
2742
- });
2743
- nextSign = 1;
2744
- }
2745
- return atoms;
2746
- }
2747
- var SUPERSCRIPT_MAP = {
2748
- "\u2070": "0",
2749
- "\xB9": "1",
2750
- "\xB2": "2",
2751
- "\xB3": "3",
2752
- "\u2074": "4",
2753
- "\u2075": "5",
2754
- "\u2076": "6",
2755
- "\u2077": "7",
2756
- "\u2078": "8",
2757
- "\u2079": "9"
2758
- };
2759
- function parseSuperscript(s) {
2760
- let out = "";
2761
- for (const ch of s) out += SUPERSCRIPT_MAP[ch] ?? ch;
2762
- return parseInt(out, 10);
2763
- }
2764
- function parse(input) {
2765
- const { scalar, rest } = splitScalar(input);
2766
- return { scalar, atoms: parseUnitExpr(rest) };
2767
- }
2768
- var Unit = class _Unit {
2769
- /** Discriminator (matches the prototype-flag convention). */
2770
- type = "Unit";
2771
- /** Used by `isUnit()` and typed-function dispatch. */
2772
- isUnit = true;
2773
- /** Numeric magnitude in **SI base units**. */
2774
- value;
2775
- /** Dimensional signature. */
2776
- dimensions;
2777
- /** Original notation string, preserved for `toString()` round-trip. */
2778
- notation;
2779
- constructor(value, notationOrDims, notation) {
2780
- if (typeof notationOrDims === "string") {
2781
- const parsed = parse(notationOrDims);
2782
- const composed = composeAtoms(parsed.atoms);
2783
- const inputValue = parsed.scalar * value;
2784
- let canonical;
2785
- if (parsed.atoms.length === 1 && parsed.atoms[0].exponent === 1) {
2786
- const a = parsed.atoms[0];
2787
- canonical = inputValue * a.multiplier + a.offset;
2788
- } else {
2789
- canonical = inputValue * composed.multiplier;
2790
- }
2791
- this.value = canonical;
2792
- this.dimensions = composed.dimensions;
2793
- this.notation = notationOrDims;
2794
- } else {
2795
- this.value = value;
2796
- this.dimensions = notationOrDims;
2797
- this.notation = notation ?? "";
2798
- }
2799
- }
2800
- // -------------------------------------------------------------------------
2801
- // Arithmetic
2802
- // -------------------------------------------------------------------------
2803
- /**
2804
- * Add two units. Requires identical dimensions.
2805
- *
2806
- * @throws {DimensionMismatchError} if dimensions differ.
2807
- */
2808
- add(other) {
2809
- if (!dimsEqual(this.dimensions, other.dimensions)) {
2810
- throw new DimensionMismatchError(this.dimensions, other.dimensions, "add");
2811
- }
2812
- return new _Unit(this.value + other.value, this.dimensions, this.notation);
2813
- }
2814
- /**
2815
- * Subtract two units. Requires identical dimensions.
2816
- *
2817
- * @throws {DimensionMismatchError} if dimensions differ.
2818
- */
2819
- sub(other) {
2820
- if (!dimsEqual(this.dimensions, other.dimensions)) {
2821
- throw new DimensionMismatchError(this.dimensions, other.dimensions, "sub");
2822
- }
2823
- return new _Unit(this.value - other.value, this.dimensions, this.notation);
2824
- }
2825
- /**
2826
- * Multiply by another unit or a scalar. Dimensions add when multiplying by
2827
- * another unit; unchanged when multiplying by a scalar.
2828
- */
2829
- mul(other) {
2830
- if (typeof other === "number") {
2831
- return new _Unit(this.value * other, this.dimensions, this.notation);
2832
- }
2833
- return new _Unit(
2834
- this.value * other.value,
2835
- dimsAdd(this.dimensions, other.dimensions),
2836
- composeNotation(this.notation, other.notation, "*")
2837
- );
2838
- }
2839
- /**
2840
- * Divide by another unit or a scalar. Dimensions subtract when dividing by
2841
- * another unit; unchanged when dividing by a scalar.
2842
- */
2843
- div(other) {
2844
- if (typeof other === "number") {
2845
- return new _Unit(this.value / other, this.dimensions, this.notation);
2846
- }
2847
- return new _Unit(
2848
- this.value / other.value,
2849
- dimsSub(this.dimensions, other.dimensions),
2850
- composeNotation(this.notation, other.notation, "/")
2851
- );
2852
- }
2853
- /**
2854
- * Raise to an integer or rational power. Dimensions scale by `n`.
2855
- */
2856
- pow(n) {
2857
- return new _Unit(
2858
- this.value ** n,
2859
- dimsScale(this.dimensions, n),
2860
- this.notation ? `(${this.notation})^${n}` : ""
2861
- );
2862
- }
2863
- // -------------------------------------------------------------------------
2864
- // Conversion
2865
- // -------------------------------------------------------------------------
2866
- /**
2867
- * Convert to a target unit. Dimensions must match.
2868
- *
2869
- * @throws {DimensionMismatchError} if `targetNotation`'s dimensions differ
2870
- * from this unit's.
2871
- */
2872
- to(targetNotation) {
2873
- const parsed = parse(targetNotation);
2874
- const composed = composeAtoms(parsed.atoms);
2875
- if (!dimsEqual(this.dimensions, composed.dimensions)) {
2876
- throw new DimensionMismatchError(
2877
- this.dimensions,
2878
- composed.dimensions,
2879
- `to("${targetNotation}")`
2880
- );
2881
- }
2882
- return new _Unit(this.value, composed.dimensions, targetNotation);
2883
- }
2884
- /**
2885
- * Pick a unit (with SI prefix) that gives a magnitude closest to 1.
2886
- *
2887
- * Searches the unit registry for entries matching this unit's dimensions,
2888
- * then applies each SI prefix in {@link BEST_PREFIXES} to find the
2889
- * representation minimising `|log10(displayed value)|`.
2890
- *
2891
- * If no registered unit matches the dimensions, falls back to a synthetic
2892
- * notation describing the dimensional vector.
2893
- */
2894
- toBest() {
2895
- if (isDimensionless(this.dimensions)) {
2896
- return new _Unit(this.value, this.dimensions, "");
2897
- }
2898
- let bestNotation;
2899
- let bestScore = Infinity;
2900
- for (const [name, def] of Object.entries(ALL_UNITS)) {
2901
- if (name === "kg") continue;
2902
- if (!dimsEqual(def.dimensions, this.dimensions)) continue;
2903
- if (def.offset !== void 0) continue;
2904
- const candidatePrefixes = def.prefixable ? BEST_PREFIXES : [""];
2905
- for (const prefix of candidatePrefixes) {
2906
- const factor = prefix === "" ? def.multiplier : def.multiplier * SI_PREFIXES[prefix];
2907
- if (factor === 0) continue;
2908
- const displayed = this.value / factor;
2909
- if (displayed === 0) continue;
2910
- const score = Math.abs(Math.log10(Math.abs(displayed)));
2911
- if (score < bestScore) {
2912
- bestScore = score;
2913
- bestNotation = prefix + name;
2914
- }
2915
- }
2916
- }
2917
- if (bestNotation === void 0) {
2918
- return new _Unit(
2919
- this.value,
2920
- this.dimensions,
2921
- this.notation || formatDimensions(this.dimensions)
2922
- );
2923
- }
2924
- return new _Unit(this.value, this.dimensions, bestNotation);
2925
- }
2926
- // -------------------------------------------------------------------------
2927
- // Comparison
2928
- // -------------------------------------------------------------------------
2929
- /** True iff dimensions and canonical value are equal. */
2930
- equals(other) {
2931
- return dimsEqual(this.dimensions, other.dimensions) && this.value === other.value;
2932
- }
2933
- /** True iff dimensions match (values may differ). */
2934
- dimensionsEqual(other) {
2935
- return dimsEqual(this.dimensions, other.dimensions);
2936
- }
2937
- // -------------------------------------------------------------------------
2938
- // Formatting
2939
- // -------------------------------------------------------------------------
2940
- /**
2941
- * Pretty-print. If `notation` is set (the common case), display the value
2942
- * in that notation — otherwise emit a dimensional signature.
2943
- */
2944
- toString() {
2945
- if (this.notation === "") {
2946
- if (isDimensionless(this.dimensions)) return String(this.value);
2947
- return `${this.value} ${formatDimensions(this.dimensions)}`;
2948
- }
2949
- const displayed = displayedValue(this.value, this.notation);
2950
- return `${formatNumber(displayed)} ${this.notation}`;
2951
- }
2952
- /** JSON-serialisable record. */
2953
- toJSON() {
2954
- return { mathts: "Unit", value: this.value, notation: this.notation };
2955
- }
2956
- /**
2957
- * Rehydrate from a JSON record produced by {@link toJSON}.
2958
- *
2959
- * @throws {UnitParseError} if `json.notation` cannot be parsed.
2960
- */
2961
- static fromJSON(json) {
2962
- const parsed = parse(json.notation);
2963
- const composed = composeAtoms(parsed.atoms);
2964
- return new _Unit(json.value, composed.dimensions, json.notation);
2965
- }
2966
- /**
2967
- * Parse a full unit expression (with optional leading numeric coefficient).
2968
- *
2969
- * Example: `Unit.parse('5 km/h')`.
2970
- */
2971
- static parse(input) {
2972
- const { scalar, rest } = splitScalar(input);
2973
- return new _Unit(scalar, rest);
2974
- }
2975
- };
2976
- Unit.prototype.isUnit = true;
2977
- function composeAtoms(atoms) {
2978
- let multiplier = 1;
2979
- let dimensions = { ...DIMENSIONLESS };
2980
- for (const a of atoms) {
2981
- multiplier *= a.multiplier ** a.exponent;
2982
- dimensions = dimsAdd(dimensions, dimsScale(a.dimensions, a.exponent));
2983
- }
2984
- return { multiplier, dimensions };
2985
- }
2986
- function displayedValue(canonical, notation) {
2987
- const parsed = parse(notation);
2988
- const composed = composeAtoms(parsed.atoms);
2989
- if (parsed.atoms.length === 1 && parsed.atoms[0].exponent === 1) {
2990
- const a = parsed.atoms[0];
2991
- return (canonical - a.offset) / a.multiplier;
2992
- }
2993
- return canonical / composed.multiplier;
2994
- }
2995
- function formatNumber(n) {
2996
- if (Number.isInteger(n)) return n.toString();
2997
- const rounded = Number(n.toPrecision(12));
2998
- return rounded.toString();
2999
- }
3000
- function composeNotation(a, b, op) {
3001
- if (a === "" && b === "") return "";
3002
- if (a === "") return op === "*" ? b : `1/${b}`;
3003
- if (b === "") return a;
3004
- const sep = op === "*" ? "*" : "/";
3005
- return `${a}${sep}${b}`;
3006
- }
3007
- function isUnit(value) {
3008
- return value instanceof Unit;
3009
- }
3010
-
3011
405
  // src/typed/mathts-typed.ts
3012
406
  import typed, { create } from "typed-function";
3013
407
  var wasmInitialized = false;
@@ -3511,6 +905,7 @@ export {
3511
905
  DEFAULT_CONFIG,
3512
906
  DERIVED_UNITS,
3513
907
  DIMENSIONLESS,
908
+ DUAL_UNARY_RULES,
3514
909
  DimensionMismatchError,
3515
910
  Dual,
3516
911
  E,
@@ -3540,11 +935,16 @@ export {
3540
935
  Unit,
3541
936
  UnitParseError,
3542
937
  VERSION,
938
+ abs,
939
+ addScalar,
3543
940
  create,
3544
941
  createFactory,
3545
942
  createMathTSTyped,
3546
943
  createTypedFunction,
3547
944
  dim,
945
+ divideScalar,
946
+ equal,
947
+ fix,
3548
948
  getPrefix,
3549
949
  getUnitDef,
3550
950
  initTypedWasm,
@@ -3560,6 +960,7 @@ export {
3560
960
  isMatrix,
3561
961
  isNull,
3562
962
  isNumber,
963
+ isNumeric,
3563
964
  isObject,
3564
965
  isSparseMatrix,
3565
966
  isString,
@@ -3569,7 +970,12 @@ export {
3569
970
  isUnit as isUnitValue,
3570
971
  math,
3571
972
  mathTyped,
973
+ multiplyScalar,
974
+ number,
975
+ pow,
3572
976
  registerNativeTypes,
3573
977
  registry,
978
+ round,
979
+ subtractScalar,
3574
980
  typed
3575
981
  };