@danielsimonjr/mathts-core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/index.d.ts +1236 -0
- package/dist/index.js +2608 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2608 @@
|
|
|
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
|
+
* Negation: -(a + bi) = -a - bi
|
|
222
|
+
*/
|
|
223
|
+
negate() {
|
|
224
|
+
return new _Complex(-this.re, -this.im);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Multiplicative inverse: 1/z = z̄/|z|²
|
|
228
|
+
*/
|
|
229
|
+
inverse() {
|
|
230
|
+
const denom = this.abs2();
|
|
231
|
+
if (denom === 0) {
|
|
232
|
+
return new _Complex(Infinity, Infinity);
|
|
233
|
+
}
|
|
234
|
+
return new _Complex(this.re / denom, -this.im / denom);
|
|
235
|
+
}
|
|
236
|
+
// ============================================================
|
|
237
|
+
// Transcendental Functions
|
|
238
|
+
// ============================================================
|
|
239
|
+
/**
|
|
240
|
+
* Square root using principal branch
|
|
241
|
+
* √z = √r · e^(iθ/2) where r = |z|, θ = arg(z)
|
|
242
|
+
*/
|
|
243
|
+
sqrt() {
|
|
244
|
+
const r = this.abs();
|
|
245
|
+
const theta = this.arg();
|
|
246
|
+
return _Complex.fromPolar(Math.sqrt(r), theta / 2);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* n-th root (returns principal root)
|
|
250
|
+
*/
|
|
251
|
+
nthRoot(n) {
|
|
252
|
+
const r = this.abs();
|
|
253
|
+
const theta = this.arg();
|
|
254
|
+
return _Complex.fromPolar(Math.pow(r, 1 / n), theta / n);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* All n-th roots
|
|
258
|
+
*/
|
|
259
|
+
nthRoots(n) {
|
|
260
|
+
const r = this.abs();
|
|
261
|
+
const theta = this.arg();
|
|
262
|
+
const rootR = Math.pow(r, 1 / n);
|
|
263
|
+
const roots = [];
|
|
264
|
+
for (let k = 0; k < n; k++) {
|
|
265
|
+
roots.push(_Complex.fromPolar(rootR, (theta + 2 * Math.PI * k) / n));
|
|
266
|
+
}
|
|
267
|
+
return roots;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Exponential: e^(a+bi) = e^a · (cos(b) + i·sin(b))
|
|
271
|
+
*/
|
|
272
|
+
exp() {
|
|
273
|
+
const ea = Math.exp(this.re);
|
|
274
|
+
return new _Complex(ea * Math.cos(this.im), ea * Math.sin(this.im));
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Natural logarithm: ln(z) = ln|z| + i·arg(z)
|
|
278
|
+
*/
|
|
279
|
+
log() {
|
|
280
|
+
return new _Complex(Math.log(this.abs()), this.arg());
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Logarithm base 10
|
|
284
|
+
*/
|
|
285
|
+
log10() {
|
|
286
|
+
return this.log().divide(new _Complex(Math.LN10, 0));
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Logarithm base 2
|
|
290
|
+
*/
|
|
291
|
+
log2() {
|
|
292
|
+
return this.log().divide(new _Complex(Math.LN2, 0));
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Power: z^w = e^(w·ln(z))
|
|
296
|
+
*/
|
|
297
|
+
pow(n) {
|
|
298
|
+
if (typeof n === "number") {
|
|
299
|
+
if (this.re === 0 && this.im === 0) {
|
|
300
|
+
return n === 0 ? new _Complex(1, 0) : new _Complex(0, 0);
|
|
301
|
+
}
|
|
302
|
+
const r = this.abs();
|
|
303
|
+
const theta = this.arg();
|
|
304
|
+
return _Complex.fromPolar(Math.pow(r, n), theta * n);
|
|
305
|
+
}
|
|
306
|
+
if (this.re === 0 && this.im === 0) {
|
|
307
|
+
return new _Complex(0, 0);
|
|
308
|
+
}
|
|
309
|
+
return this.log().multiply(n).exp();
|
|
310
|
+
}
|
|
311
|
+
// ============================================================
|
|
312
|
+
// Trigonometric Functions
|
|
313
|
+
// ============================================================
|
|
314
|
+
/**
|
|
315
|
+
* Sine: sin(a + bi) = sin(a)cosh(b) + i·cos(a)sinh(b)
|
|
316
|
+
*/
|
|
317
|
+
sin() {
|
|
318
|
+
return new _Complex(
|
|
319
|
+
Math.sin(this.re) * Math.cosh(this.im),
|
|
320
|
+
Math.cos(this.re) * Math.sinh(this.im)
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Cosine: cos(a + bi) = cos(a)cosh(b) - i·sin(a)sinh(b)
|
|
325
|
+
*/
|
|
326
|
+
cos() {
|
|
327
|
+
return new _Complex(
|
|
328
|
+
Math.cos(this.re) * Math.cosh(this.im),
|
|
329
|
+
-Math.sin(this.re) * Math.sinh(this.im)
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Tangent: tan(z) = sin(z) / cos(z)
|
|
334
|
+
*/
|
|
335
|
+
tan() {
|
|
336
|
+
return this.sin().divide(this.cos());
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Cotangent: cot(z) = cos(z) / sin(z)
|
|
340
|
+
*/
|
|
341
|
+
cot() {
|
|
342
|
+
return this.cos().divide(this.sin());
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Secant: sec(z) = 1 / cos(z)
|
|
346
|
+
*/
|
|
347
|
+
sec() {
|
|
348
|
+
return this.cos().inverse();
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Cosecant: csc(z) = 1 / sin(z)
|
|
352
|
+
*/
|
|
353
|
+
csc() {
|
|
354
|
+
return this.sin().inverse();
|
|
355
|
+
}
|
|
356
|
+
// ============================================================
|
|
357
|
+
// Hyperbolic Functions
|
|
358
|
+
// ============================================================
|
|
359
|
+
/**
|
|
360
|
+
* Hyperbolic sine: sinh(z) = (e^z - e^(-z)) / 2
|
|
361
|
+
*/
|
|
362
|
+
sinh() {
|
|
363
|
+
return new _Complex(
|
|
364
|
+
Math.sinh(this.re) * Math.cos(this.im),
|
|
365
|
+
Math.cosh(this.re) * Math.sin(this.im)
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Hyperbolic cosine: cosh(z) = (e^z + e^(-z)) / 2
|
|
370
|
+
*/
|
|
371
|
+
cosh() {
|
|
372
|
+
return new _Complex(
|
|
373
|
+
Math.cosh(this.re) * Math.cos(this.im),
|
|
374
|
+
Math.sinh(this.re) * Math.sin(this.im)
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Hyperbolic tangent: tanh(z) = sinh(z) / cosh(z)
|
|
379
|
+
*/
|
|
380
|
+
tanh() {
|
|
381
|
+
return this.sinh().divide(this.cosh());
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Hyperbolic cotangent: coth(z) = cosh(z) / sinh(z)
|
|
385
|
+
*/
|
|
386
|
+
coth() {
|
|
387
|
+
return this.cosh().divide(this.sinh());
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Hyperbolic secant: sech(z) = 1 / cosh(z)
|
|
391
|
+
*/
|
|
392
|
+
sech() {
|
|
393
|
+
return this.cosh().inverse();
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Hyperbolic cosecant: csch(z) = 1 / sinh(z)
|
|
397
|
+
*/
|
|
398
|
+
csch() {
|
|
399
|
+
return this.sinh().inverse();
|
|
400
|
+
}
|
|
401
|
+
// ============================================================
|
|
402
|
+
// Inverse Trigonometric Functions
|
|
403
|
+
// ============================================================
|
|
404
|
+
/**
|
|
405
|
+
* Arc sine: asin(z) = -i·ln(iz + √(1 - z²))
|
|
406
|
+
*/
|
|
407
|
+
asin() {
|
|
408
|
+
const iz = new _Complex(-this.im, this.re);
|
|
409
|
+
const one = new _Complex(1, 0);
|
|
410
|
+
const sqrt = one.subtract(this.multiply(this)).sqrt();
|
|
411
|
+
return iz.add(sqrt).log().multiply(new _Complex(0, -1));
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Arc cosine: acos(z) = π/2 - asin(z)
|
|
415
|
+
*/
|
|
416
|
+
acos() {
|
|
417
|
+
return new _Complex(Math.PI / 2, 0).subtract(this.asin());
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Arc tangent: atan(z) = (i/2)·ln((i + z)/(i - z))
|
|
421
|
+
*/
|
|
422
|
+
atan() {
|
|
423
|
+
const i = new _Complex(0, 1);
|
|
424
|
+
const iHalf = new _Complex(0, 0.5);
|
|
425
|
+
const num = i.add(this);
|
|
426
|
+
const denom = i.subtract(this);
|
|
427
|
+
return num.divide(denom).log().multiply(iHalf);
|
|
428
|
+
}
|
|
429
|
+
// ============================================================
|
|
430
|
+
// Inverse Hyperbolic Functions
|
|
431
|
+
// ============================================================
|
|
432
|
+
/**
|
|
433
|
+
* Inverse hyperbolic sine: asinh(z) = ln(z + √(z² + 1))
|
|
434
|
+
*/
|
|
435
|
+
asinh() {
|
|
436
|
+
const one = new _Complex(1, 0);
|
|
437
|
+
return this.add(this.multiply(this).add(one).sqrt()).log();
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Inverse hyperbolic cosine: acosh(z) = ln(z + √(z² - 1))
|
|
441
|
+
*/
|
|
442
|
+
acosh() {
|
|
443
|
+
const one = new _Complex(1, 0);
|
|
444
|
+
return this.add(this.multiply(this).subtract(one).sqrt()).log();
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Inverse hyperbolic tangent: atanh(z) = (1/2)·ln((1 + z)/(1 - z))
|
|
448
|
+
*/
|
|
449
|
+
atanh() {
|
|
450
|
+
const one = new _Complex(1, 0);
|
|
451
|
+
const half = new _Complex(0.5, 0);
|
|
452
|
+
return one.add(this).divide(one.subtract(this)).log().multiply(half);
|
|
453
|
+
}
|
|
454
|
+
// ============================================================
|
|
455
|
+
// Utility Methods
|
|
456
|
+
// ============================================================
|
|
457
|
+
/**
|
|
458
|
+
* Check equality within tolerance
|
|
459
|
+
*/
|
|
460
|
+
equals(other, epsilon = 1e-12) {
|
|
461
|
+
return Math.abs(this.re - other.re) < epsilon && Math.abs(this.im - other.im) < epsilon;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Check if this is a real number (im ≈ 0)
|
|
465
|
+
*/
|
|
466
|
+
isReal(epsilon = 0) {
|
|
467
|
+
return Math.abs(this.im) <= epsilon;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Check if this is purely imaginary (re ≈ 0, im ≠ 0)
|
|
471
|
+
*/
|
|
472
|
+
isImaginary(epsilon = 0) {
|
|
473
|
+
return Math.abs(this.re) <= epsilon && Math.abs(this.im) > epsilon;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Check if this is zero
|
|
477
|
+
*/
|
|
478
|
+
isZero(epsilon = 0) {
|
|
479
|
+
return Math.abs(this.re) <= epsilon && Math.abs(this.im) <= epsilon;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Check if this is NaN
|
|
483
|
+
*/
|
|
484
|
+
isNaN() {
|
|
485
|
+
return Number.isNaN(this.re) || Number.isNaN(this.im);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Check if this is infinite
|
|
489
|
+
*/
|
|
490
|
+
isInfinite() {
|
|
491
|
+
return !this.isNaN() && (!Number.isFinite(this.re) || !Number.isFinite(this.im));
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Clone this complex number
|
|
495
|
+
*/
|
|
496
|
+
clone() {
|
|
497
|
+
return new _Complex(this.re, this.im);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Round real and imaginary parts to specified decimals
|
|
501
|
+
*/
|
|
502
|
+
round(decimals = 0) {
|
|
503
|
+
const factor = Math.pow(10, decimals);
|
|
504
|
+
return new _Complex(
|
|
505
|
+
Math.round(this.re * factor) / factor,
|
|
506
|
+
Math.round(this.im * factor) / factor
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Floor real and imaginary parts
|
|
511
|
+
*/
|
|
512
|
+
floor() {
|
|
513
|
+
return new _Complex(Math.floor(this.re), Math.floor(this.im));
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Ceil real and imaginary parts
|
|
517
|
+
*/
|
|
518
|
+
ceil() {
|
|
519
|
+
return new _Complex(Math.ceil(this.re), Math.ceil(this.im));
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Sign function: z / |z| (unit complex number in same direction)
|
|
523
|
+
*/
|
|
524
|
+
sign() {
|
|
525
|
+
const r = this.abs();
|
|
526
|
+
if (r === 0) return new _Complex(0, 0);
|
|
527
|
+
return new _Complex(this.re / r, this.im / r);
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
var I = new Complex(0, 1);
|
|
531
|
+
var COMPLEX_ZERO = new Complex(0, 0);
|
|
532
|
+
var COMPLEX_ONE = new Complex(1, 0);
|
|
533
|
+
var COMPLEX_NEG_ONE = new Complex(-1, 0);
|
|
534
|
+
|
|
535
|
+
// src/types/fraction.ts
|
|
536
|
+
function isFraction(value) {
|
|
537
|
+
return value instanceof Fraction;
|
|
538
|
+
}
|
|
539
|
+
function gcd(a, b) {
|
|
540
|
+
a = a < 0n ? -a : a;
|
|
541
|
+
b = b < 0n ? -b : b;
|
|
542
|
+
while (b !== 0n) {
|
|
543
|
+
const t = b;
|
|
544
|
+
b = a % b;
|
|
545
|
+
a = t;
|
|
546
|
+
}
|
|
547
|
+
return a;
|
|
548
|
+
}
|
|
549
|
+
var Fraction = class _Fraction {
|
|
550
|
+
type = "Fraction";
|
|
551
|
+
numerator;
|
|
552
|
+
denominator;
|
|
553
|
+
constructor(numerator, denominator = 1n) {
|
|
554
|
+
let num = typeof numerator === "bigint" ? numerator : BigInt(numerator);
|
|
555
|
+
let den = typeof denominator === "bigint" ? denominator : BigInt(denominator);
|
|
556
|
+
if (den === 0n) {
|
|
557
|
+
throw new Error("Fraction denominator cannot be zero");
|
|
558
|
+
}
|
|
559
|
+
if (den < 0n) {
|
|
560
|
+
num = -num;
|
|
561
|
+
den = -den;
|
|
562
|
+
}
|
|
563
|
+
const g = gcd(num, den);
|
|
564
|
+
this.numerator = num / g;
|
|
565
|
+
this.denominator = den / g;
|
|
566
|
+
}
|
|
567
|
+
// ============================================================
|
|
568
|
+
// Static Factory Methods
|
|
569
|
+
// ============================================================
|
|
570
|
+
/**
|
|
571
|
+
* Create a Fraction from a number (with optional precision)
|
|
572
|
+
*/
|
|
573
|
+
static fromNumber(n, maxDenominator = 1000000n) {
|
|
574
|
+
if (!Number.isFinite(n)) {
|
|
575
|
+
throw new Error("Cannot create fraction from non-finite number");
|
|
576
|
+
}
|
|
577
|
+
if (Number.isInteger(n)) {
|
|
578
|
+
return new _Fraction(BigInt(n), 1n);
|
|
579
|
+
}
|
|
580
|
+
const sign = n < 0 ? -1n : 1n;
|
|
581
|
+
n = Math.abs(n);
|
|
582
|
+
let h1 = 1n, h2 = 0n;
|
|
583
|
+
let k1 = 0n, k2 = 1n;
|
|
584
|
+
let b = n;
|
|
585
|
+
do {
|
|
586
|
+
const a = BigInt(Math.floor(b));
|
|
587
|
+
let aux = h1;
|
|
588
|
+
h1 = a * h1 + h2;
|
|
589
|
+
h2 = aux;
|
|
590
|
+
aux = k1;
|
|
591
|
+
k1 = a * k1 + k2;
|
|
592
|
+
k2 = aux;
|
|
593
|
+
b = 1 / (b - Number(a));
|
|
594
|
+
} while (Math.abs(n - Number(h1) / Number(k1)) > Number.EPSILON && k1 < maxDenominator);
|
|
595
|
+
return new _Fraction(sign * h1, k1);
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Create a Fraction from a decimal string
|
|
599
|
+
*/
|
|
600
|
+
static fromDecimalString(str) {
|
|
601
|
+
str = str.trim();
|
|
602
|
+
const repeatingMatch = str.match(/^(-?\d*)\.(\d*)\((\d+)\)$/);
|
|
603
|
+
if (repeatingMatch) {
|
|
604
|
+
const sign2 = str.startsWith("-") ? -1n : 1n;
|
|
605
|
+
const intPart2 = repeatingMatch[1] === "-" ? "0" : repeatingMatch[1] || "0";
|
|
606
|
+
const nonRepeating = repeatingMatch[2] || "";
|
|
607
|
+
const repeating = repeatingMatch[3];
|
|
608
|
+
const fullDigits = intPart2 + nonRepeating + repeating;
|
|
609
|
+
const nonRepDigits = intPart2 + nonRepeating;
|
|
610
|
+
const fullNum = BigInt(fullDigits.replace("-", ""));
|
|
611
|
+
const nonRepNum = BigInt(nonRepDigits.replace("-", "") || "0");
|
|
612
|
+
const nines = BigInt("9".repeat(repeating.length));
|
|
613
|
+
const zeros = BigInt("1" + "0".repeat(nonRepeating.length));
|
|
614
|
+
const num2 = fullNum - nonRepNum;
|
|
615
|
+
const den2 = nines * zeros;
|
|
616
|
+
return new _Fraction(sign2 * num2, den2);
|
|
617
|
+
}
|
|
618
|
+
const [intPart, decPart = ""] = str.split(".");
|
|
619
|
+
const sign = str.startsWith("-") ? -1n : 1n;
|
|
620
|
+
const absInt = intPart.replace("-", "") || "0";
|
|
621
|
+
const combined = absInt + decPart;
|
|
622
|
+
const num = BigInt(combined);
|
|
623
|
+
const den = BigInt("1" + "0".repeat(decPart.length));
|
|
624
|
+
return new _Fraction(sign * num, den);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Parse a fraction from a string
|
|
628
|
+
* Supports formats: "3/4", "-3/4", "3", "3.14", "0.(3)"
|
|
629
|
+
*/
|
|
630
|
+
static parse(str) {
|
|
631
|
+
str = str.trim();
|
|
632
|
+
if (str.includes("/")) {
|
|
633
|
+
const [numStr, denStr] = str.split("/");
|
|
634
|
+
return new _Fraction(BigInt(numStr.trim()), BigInt(denStr.trim()));
|
|
635
|
+
}
|
|
636
|
+
if (str.includes(".") || str.includes("(")) {
|
|
637
|
+
return _Fraction.fromDecimalString(str);
|
|
638
|
+
}
|
|
639
|
+
return new _Fraction(BigInt(str), 1n);
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Create a Fraction from a JSON object
|
|
643
|
+
*/
|
|
644
|
+
static fromJSON(json) {
|
|
645
|
+
if ("n" in json) {
|
|
646
|
+
return new _Fraction(BigInt(json.n), BigInt(json.d));
|
|
647
|
+
}
|
|
648
|
+
return new _Fraction(BigInt(json.numerator), BigInt(json.denominator));
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Compare two fractions
|
|
652
|
+
* @returns -1, 0, or 1
|
|
653
|
+
*/
|
|
654
|
+
static compare(a, b) {
|
|
655
|
+
const diff = a.numerator * b.denominator - b.numerator * a.denominator;
|
|
656
|
+
if (diff < 0n) return -1;
|
|
657
|
+
if (diff > 0n) return 1;
|
|
658
|
+
return 0;
|
|
659
|
+
}
|
|
660
|
+
// ============================================================
|
|
661
|
+
// Conversion Methods
|
|
662
|
+
// ============================================================
|
|
663
|
+
valueOf() {
|
|
664
|
+
return Number(this.numerator) / Number(this.denominator);
|
|
665
|
+
}
|
|
666
|
+
toString() {
|
|
667
|
+
if (this.denominator === 1n) {
|
|
668
|
+
return this.numerator.toString();
|
|
669
|
+
}
|
|
670
|
+
return `${this.numerator}/${this.denominator}`;
|
|
671
|
+
}
|
|
672
|
+
toJSON() {
|
|
673
|
+
return {
|
|
674
|
+
mathjs: "Fraction",
|
|
675
|
+
n: this.numerator.toString(),
|
|
676
|
+
d: this.denominator.toString()
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Convert to number
|
|
681
|
+
*/
|
|
682
|
+
toNumber() {
|
|
683
|
+
return this.valueOf();
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Convert to decimal string with specified precision
|
|
687
|
+
*/
|
|
688
|
+
toDecimal(precision = 10) {
|
|
689
|
+
const sign = this.numerator < 0n ? "-" : "";
|
|
690
|
+
let num = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
691
|
+
const den = this.denominator;
|
|
692
|
+
const intPart = num / den;
|
|
693
|
+
num = num % den;
|
|
694
|
+
if (num === 0n || precision === 0) {
|
|
695
|
+
return sign + intPart.toString();
|
|
696
|
+
}
|
|
697
|
+
let decPart = "";
|
|
698
|
+
for (let i = 0; i < precision && num !== 0n; i++) {
|
|
699
|
+
num *= 10n;
|
|
700
|
+
decPart += (num / den).toString();
|
|
701
|
+
num = num % den;
|
|
702
|
+
}
|
|
703
|
+
return sign + intPart.toString() + "." + decPart;
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Convert to LaTeX string
|
|
707
|
+
*/
|
|
708
|
+
toLatex() {
|
|
709
|
+
if (this.denominator === 1n) {
|
|
710
|
+
return this.numerator.toString();
|
|
711
|
+
}
|
|
712
|
+
const sign = this.numerator < 0n ? "-" : "";
|
|
713
|
+
const absNum = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
714
|
+
return `${sign}\\frac{${absNum}}{${this.denominator}}`;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Convert to mixed number representation
|
|
718
|
+
*/
|
|
719
|
+
toMixed() {
|
|
720
|
+
const sign = this.numerator < 0n ? -1n : 1n;
|
|
721
|
+
const absNum = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
722
|
+
const whole = sign * (absNum / this.denominator);
|
|
723
|
+
const remainder = absNum % this.denominator;
|
|
724
|
+
return {
|
|
725
|
+
whole,
|
|
726
|
+
numerator: remainder,
|
|
727
|
+
denominator: this.denominator
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
// ============================================================
|
|
731
|
+
// Arithmetic Operations (Scalar interface)
|
|
732
|
+
// ============================================================
|
|
733
|
+
/**
|
|
734
|
+
* Addition: a/b + c/d = (ad + bc) / bd
|
|
735
|
+
*/
|
|
736
|
+
add(other) {
|
|
737
|
+
if (other instanceof _Fraction) {
|
|
738
|
+
const num = this.numerator * other.denominator + other.numerator * this.denominator;
|
|
739
|
+
const den = this.denominator * other.denominator;
|
|
740
|
+
return new _Fraction(num, den);
|
|
741
|
+
}
|
|
742
|
+
return this.add(_Fraction.fromNumber(Number(other.valueOf())));
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Subtraction: a/b - c/d = (ad - bc) / bd
|
|
746
|
+
*/
|
|
747
|
+
subtract(other) {
|
|
748
|
+
if (other instanceof _Fraction) {
|
|
749
|
+
const num = this.numerator * other.denominator - other.numerator * this.denominator;
|
|
750
|
+
const den = this.denominator * other.denominator;
|
|
751
|
+
return new _Fraction(num, den);
|
|
752
|
+
}
|
|
753
|
+
return this.subtract(_Fraction.fromNumber(Number(other.valueOf())));
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Multiplication: a/b * c/d = ac / bd
|
|
757
|
+
*/
|
|
758
|
+
multiply(other) {
|
|
759
|
+
if (other instanceof _Fraction) {
|
|
760
|
+
return new _Fraction(
|
|
761
|
+
this.numerator * other.numerator,
|
|
762
|
+
this.denominator * other.denominator
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
return this.multiply(_Fraction.fromNumber(Number(other.valueOf())));
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Division: a/b ÷ c/d = ad / bc
|
|
769
|
+
*/
|
|
770
|
+
divide(other) {
|
|
771
|
+
if (other instanceof _Fraction) {
|
|
772
|
+
if (other.numerator === 0n) {
|
|
773
|
+
throw new Error("Division by zero");
|
|
774
|
+
}
|
|
775
|
+
return new _Fraction(
|
|
776
|
+
this.numerator * other.denominator,
|
|
777
|
+
this.denominator * other.numerator
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
return this.divide(_Fraction.fromNumber(Number(other.valueOf())));
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Negation: -(a/b) = -a/b
|
|
784
|
+
*/
|
|
785
|
+
negate() {
|
|
786
|
+
return new _Fraction(-this.numerator, this.denominator);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Absolute value: |a/b|
|
|
790
|
+
*/
|
|
791
|
+
abs() {
|
|
792
|
+
return new _Fraction(
|
|
793
|
+
this.numerator < 0n ? -this.numerator : this.numerator,
|
|
794
|
+
this.denominator
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Reciprocal: b/a
|
|
799
|
+
*/
|
|
800
|
+
inverse() {
|
|
801
|
+
if (this.numerator === 0n) {
|
|
802
|
+
throw new Error("Cannot invert zero");
|
|
803
|
+
}
|
|
804
|
+
return new _Fraction(this.denominator, this.numerator);
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Power (integer exponent)
|
|
808
|
+
*/
|
|
809
|
+
pow(n) {
|
|
810
|
+
const exp = typeof n === "bigint" ? n : BigInt(n);
|
|
811
|
+
if (exp === 0n) {
|
|
812
|
+
return new _Fraction(1n, 1n);
|
|
813
|
+
}
|
|
814
|
+
if (exp < 0n) {
|
|
815
|
+
return this.inverse().pow(-exp);
|
|
816
|
+
}
|
|
817
|
+
let result = new _Fraction(1n, 1n);
|
|
818
|
+
let base = this;
|
|
819
|
+
let e = exp;
|
|
820
|
+
while (e > 0n) {
|
|
821
|
+
if (e % 2n === 1n) {
|
|
822
|
+
result = result.multiply(base);
|
|
823
|
+
}
|
|
824
|
+
base = base.multiply(base);
|
|
825
|
+
e = e / 2n;
|
|
826
|
+
}
|
|
827
|
+
return result;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Modulo operation
|
|
831
|
+
*/
|
|
832
|
+
mod(other) {
|
|
833
|
+
const quotient = this.divide(other);
|
|
834
|
+
const floorQuot = quotient.floor();
|
|
835
|
+
return this.subtract(other.multiply(floorQuot));
|
|
836
|
+
}
|
|
837
|
+
// ============================================================
|
|
838
|
+
// Comparison Methods
|
|
839
|
+
// ============================================================
|
|
840
|
+
/**
|
|
841
|
+
* Check equality
|
|
842
|
+
*/
|
|
843
|
+
equals(other) {
|
|
844
|
+
return this.numerator === other.numerator && this.denominator === other.denominator;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Check if less than
|
|
848
|
+
*/
|
|
849
|
+
lessThan(other) {
|
|
850
|
+
return _Fraction.compare(this, other) < 0;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Check if less than or equal
|
|
854
|
+
*/
|
|
855
|
+
lessThanOrEqual(other) {
|
|
856
|
+
return _Fraction.compare(this, other) <= 0;
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Check if greater than
|
|
860
|
+
*/
|
|
861
|
+
greaterThan(other) {
|
|
862
|
+
return _Fraction.compare(this, other) > 0;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Check if greater than or equal
|
|
866
|
+
*/
|
|
867
|
+
greaterThanOrEqual(other) {
|
|
868
|
+
return _Fraction.compare(this, other) >= 0;
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Compare with another fraction
|
|
872
|
+
* @returns -1, 0, or 1
|
|
873
|
+
*/
|
|
874
|
+
compareTo(other) {
|
|
875
|
+
return _Fraction.compare(this, other);
|
|
876
|
+
}
|
|
877
|
+
compare(other) {
|
|
878
|
+
return this.compareTo(other);
|
|
879
|
+
}
|
|
880
|
+
// ============================================================
|
|
881
|
+
// Utility Methods
|
|
882
|
+
// ============================================================
|
|
883
|
+
/**
|
|
884
|
+
* Return fraction already in lowest terms (no-op since constructor reduces)
|
|
885
|
+
*/
|
|
886
|
+
simplify() {
|
|
887
|
+
return this;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Check if this is zero
|
|
891
|
+
*/
|
|
892
|
+
isZero() {
|
|
893
|
+
return this.numerator === 0n;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Check if this is positive
|
|
897
|
+
*/
|
|
898
|
+
isPositive() {
|
|
899
|
+
return this.numerator > 0n;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Check if this is negative
|
|
903
|
+
*/
|
|
904
|
+
isNegative() {
|
|
905
|
+
return this.numerator < 0n;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Check if this is an integer
|
|
909
|
+
*/
|
|
910
|
+
isInteger() {
|
|
911
|
+
return this.denominator === 1n;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Check if this is a unit fraction (1/n)
|
|
915
|
+
*/
|
|
916
|
+
isUnit() {
|
|
917
|
+
return this.numerator === 1n || this.numerator === -1n;
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Floor: largest integer ≤ this
|
|
921
|
+
*/
|
|
922
|
+
floor() {
|
|
923
|
+
if (this.denominator === 1n) {
|
|
924
|
+
return this;
|
|
925
|
+
}
|
|
926
|
+
const quot = this.numerator / this.denominator;
|
|
927
|
+
if (this.numerator >= 0n || this.numerator % this.denominator === 0n) {
|
|
928
|
+
return new _Fraction(quot, 1n);
|
|
929
|
+
}
|
|
930
|
+
return new _Fraction(quot - 1n, 1n);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Ceiling: smallest integer ≥ this
|
|
934
|
+
*/
|
|
935
|
+
ceil() {
|
|
936
|
+
if (this.denominator === 1n) {
|
|
937
|
+
return this;
|
|
938
|
+
}
|
|
939
|
+
const quot = this.numerator / this.denominator;
|
|
940
|
+
if (this.numerator <= 0n || this.numerator % this.denominator === 0n) {
|
|
941
|
+
return new _Fraction(quot, 1n);
|
|
942
|
+
}
|
|
943
|
+
return new _Fraction(quot + 1n, 1n);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Round to nearest integer
|
|
947
|
+
*/
|
|
948
|
+
round() {
|
|
949
|
+
const floor = this.floor();
|
|
950
|
+
const diff = this.subtract(floor);
|
|
951
|
+
const half = new _Fraction(1n, 2n);
|
|
952
|
+
if (diff.greaterThanOrEqual(half)) {
|
|
953
|
+
return floor.add(new _Fraction(1n, 1n));
|
|
954
|
+
}
|
|
955
|
+
return floor;
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Truncate (round toward zero)
|
|
959
|
+
*/
|
|
960
|
+
trunc() {
|
|
961
|
+
return new _Fraction(this.numerator / this.denominator, 1n);
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Get the sign: -1, 0, or 1
|
|
965
|
+
*/
|
|
966
|
+
sign() {
|
|
967
|
+
if (this.numerator < 0n) return -1;
|
|
968
|
+
if (this.numerator > 0n) return 1;
|
|
969
|
+
return 0;
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Clone this fraction
|
|
973
|
+
*/
|
|
974
|
+
clone() {
|
|
975
|
+
return new _Fraction(this.numerator, this.denominator);
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Get the GCD of numerator and denominator (always 1 since we reduce)
|
|
979
|
+
*/
|
|
980
|
+
gcd() {
|
|
981
|
+
return 1n;
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Get continued fraction representation
|
|
985
|
+
*/
|
|
986
|
+
toContinuedFraction() {
|
|
987
|
+
const result = [];
|
|
988
|
+
let num = this.numerator < 0n ? -this.numerator : this.numerator;
|
|
989
|
+
let den = this.denominator;
|
|
990
|
+
while (den !== 0n) {
|
|
991
|
+
result.push(num / den);
|
|
992
|
+
const temp = num % den;
|
|
993
|
+
num = den;
|
|
994
|
+
den = temp;
|
|
995
|
+
}
|
|
996
|
+
if (this.numerator < 0n && result.length > 0) {
|
|
997
|
+
result[0] = -result[0];
|
|
998
|
+
}
|
|
999
|
+
return result;
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Create fraction from continued fraction
|
|
1003
|
+
*/
|
|
1004
|
+
static fromContinuedFraction(cf) {
|
|
1005
|
+
if (cf.length === 0) {
|
|
1006
|
+
return new _Fraction(0n, 1n);
|
|
1007
|
+
}
|
|
1008
|
+
let num = cf[cf.length - 1];
|
|
1009
|
+
let den = 1n;
|
|
1010
|
+
for (let i = cf.length - 2; i >= 0; i--) {
|
|
1011
|
+
const temp = num;
|
|
1012
|
+
num = cf[i] * num + den;
|
|
1013
|
+
den = temp;
|
|
1014
|
+
}
|
|
1015
|
+
return new _Fraction(num, den);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Mediant of two fractions: (a+c)/(b+d)
|
|
1019
|
+
* Used in Stern-Brocot tree and Farey sequences
|
|
1020
|
+
*/
|
|
1021
|
+
mediant(other) {
|
|
1022
|
+
return new _Fraction(
|
|
1023
|
+
this.numerator + other.numerator,
|
|
1024
|
+
this.denominator + other.denominator
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
var FRACTION_ZERO = new Fraction(0n, 1n);
|
|
1029
|
+
var FRACTION_ONE = new Fraction(1n, 1n);
|
|
1030
|
+
var FRACTION_NEG_ONE = new Fraction(-1n, 1n);
|
|
1031
|
+
var FRACTION_HALF = new Fraction(1n, 2n);
|
|
1032
|
+
var FRACTION_THIRD = new Fraction(1n, 3n);
|
|
1033
|
+
var FRACTION_QUARTER = new Fraction(1n, 4n);
|
|
1034
|
+
|
|
1035
|
+
// src/types/bignumber.ts
|
|
1036
|
+
function isBigNumber(value) {
|
|
1037
|
+
return value instanceof BigNumber;
|
|
1038
|
+
}
|
|
1039
|
+
var defaultConfig = {
|
|
1040
|
+
precision: 64,
|
|
1041
|
+
rounding: "halfUp",
|
|
1042
|
+
minExponent: -1e9,
|
|
1043
|
+
maxExponent: 1e9
|
|
1044
|
+
};
|
|
1045
|
+
var globalConfig = { ...defaultConfig };
|
|
1046
|
+
var BigNumber = class _BigNumber {
|
|
1047
|
+
type = "BigNumber";
|
|
1048
|
+
// Internal representation: sign * coefficient * 10^exponent
|
|
1049
|
+
_sign;
|
|
1050
|
+
_coefficient;
|
|
1051
|
+
// Absolute value, normalized
|
|
1052
|
+
_exponent;
|
|
1053
|
+
// Power of 10
|
|
1054
|
+
// Special values
|
|
1055
|
+
_isNaN = false;
|
|
1056
|
+
_isInfinite = false;
|
|
1057
|
+
constructor(sign, coefficient, exponent, isNaN2 = false, isInfinite = false) {
|
|
1058
|
+
this._sign = sign;
|
|
1059
|
+
this._coefficient = coefficient;
|
|
1060
|
+
this._exponent = exponent;
|
|
1061
|
+
this._isNaN = isNaN2;
|
|
1062
|
+
this._isInfinite = isInfinite;
|
|
1063
|
+
}
|
|
1064
|
+
// ============================================================
|
|
1065
|
+
// Static Factory Methods
|
|
1066
|
+
// ============================================================
|
|
1067
|
+
/**
|
|
1068
|
+
* Create a BigNumber from a number
|
|
1069
|
+
*/
|
|
1070
|
+
static fromNumber(n) {
|
|
1071
|
+
if (Number.isNaN(n)) {
|
|
1072
|
+
return new _BigNumber(0, 0n, 0, true, false);
|
|
1073
|
+
}
|
|
1074
|
+
if (!Number.isFinite(n)) {
|
|
1075
|
+
return new _BigNumber(n > 0 ? 1 : -1, 0n, 0, false, true);
|
|
1076
|
+
}
|
|
1077
|
+
if (n === 0) {
|
|
1078
|
+
return new _BigNumber(0, 0n, 0);
|
|
1079
|
+
}
|
|
1080
|
+
return _BigNumber.parse(n.toString());
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Create a BigNumber from a string
|
|
1084
|
+
*/
|
|
1085
|
+
static parse(str) {
|
|
1086
|
+
str = str.trim().toLowerCase();
|
|
1087
|
+
if (str === "nan") {
|
|
1088
|
+
return new _BigNumber(0, 0n, 0, true, false);
|
|
1089
|
+
}
|
|
1090
|
+
if (str === "infinity" || str === "+infinity") {
|
|
1091
|
+
return new _BigNumber(1, 0n, 0, false, true);
|
|
1092
|
+
}
|
|
1093
|
+
if (str === "-infinity") {
|
|
1094
|
+
return new _BigNumber(-1, 0n, 0, false, true);
|
|
1095
|
+
}
|
|
1096
|
+
let sign = 1;
|
|
1097
|
+
if (str.startsWith("-")) {
|
|
1098
|
+
sign = -1;
|
|
1099
|
+
str = str.slice(1);
|
|
1100
|
+
} else if (str.startsWith("+")) {
|
|
1101
|
+
str = str.slice(1);
|
|
1102
|
+
}
|
|
1103
|
+
let exponentPart = 0;
|
|
1104
|
+
const eIndex = str.indexOf("e");
|
|
1105
|
+
if (eIndex !== -1) {
|
|
1106
|
+
exponentPart = parseInt(str.slice(eIndex + 1), 10);
|
|
1107
|
+
str = str.slice(0, eIndex);
|
|
1108
|
+
}
|
|
1109
|
+
const dotIndex = str.indexOf(".");
|
|
1110
|
+
let coefficient;
|
|
1111
|
+
let decimalPlaces = 0;
|
|
1112
|
+
if (dotIndex !== -1) {
|
|
1113
|
+
coefficient = str.slice(0, dotIndex) + str.slice(dotIndex + 1);
|
|
1114
|
+
decimalPlaces = str.length - dotIndex - 1;
|
|
1115
|
+
} else {
|
|
1116
|
+
coefficient = str;
|
|
1117
|
+
}
|
|
1118
|
+
coefficient = coefficient.replace(/^0+/, "") || "0";
|
|
1119
|
+
if (coefficient === "0") {
|
|
1120
|
+
return new _BigNumber(0, 0n, 0);
|
|
1121
|
+
}
|
|
1122
|
+
let trailingZeros = 0;
|
|
1123
|
+
for (let i = coefficient.length - 1; i >= 0; i--) {
|
|
1124
|
+
if (coefficient[i] === "0") {
|
|
1125
|
+
trailingZeros++;
|
|
1126
|
+
} else {
|
|
1127
|
+
break;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
if (trailingZeros > 0) {
|
|
1131
|
+
coefficient = coefficient.slice(0, -trailingZeros);
|
|
1132
|
+
}
|
|
1133
|
+
const finalExponent = exponentPart - decimalPlaces + trailingZeros;
|
|
1134
|
+
return new _BigNumber(sign, BigInt(coefficient), finalExponent);
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Create from bigint
|
|
1138
|
+
*/
|
|
1139
|
+
static fromBigInt(n) {
|
|
1140
|
+
if (n === 0n) {
|
|
1141
|
+
return new _BigNumber(0, 0n, 0);
|
|
1142
|
+
}
|
|
1143
|
+
const sign = n < 0n ? -1 : 1;
|
|
1144
|
+
let str = (n < 0n ? -n : n).toString();
|
|
1145
|
+
let trailingZeros = 0;
|
|
1146
|
+
for (let i = str.length - 1; i >= 0; i--) {
|
|
1147
|
+
if (str[i] === "0") {
|
|
1148
|
+
trailingZeros++;
|
|
1149
|
+
} else {
|
|
1150
|
+
break;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (trailingZeros > 0) {
|
|
1154
|
+
str = str.slice(0, -trailingZeros);
|
|
1155
|
+
}
|
|
1156
|
+
return new _BigNumber(sign, BigInt(str), trailingZeros);
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Create a BigNumber from a JSON object
|
|
1160
|
+
*/
|
|
1161
|
+
static fromJSON(json) {
|
|
1162
|
+
return _BigNumber.parse(json.value);
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Get/set global configuration
|
|
1166
|
+
*/
|
|
1167
|
+
static config(newConfig) {
|
|
1168
|
+
if (newConfig) {
|
|
1169
|
+
globalConfig = { ...globalConfig, ...newConfig };
|
|
1170
|
+
}
|
|
1171
|
+
return { ...globalConfig };
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Reset configuration to defaults
|
|
1175
|
+
*/
|
|
1176
|
+
static resetConfig() {
|
|
1177
|
+
globalConfig = { ...defaultConfig };
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Compare two BigNumbers
|
|
1181
|
+
* @returns -1, 0, or 1
|
|
1182
|
+
*/
|
|
1183
|
+
static compare(a, b) {
|
|
1184
|
+
if (a._isNaN || b._isNaN) return NaN;
|
|
1185
|
+
if (a._isInfinite && b._isInfinite) {
|
|
1186
|
+
if (a._sign === b._sign) return 0;
|
|
1187
|
+
return a._sign > b._sign ? 1 : -1;
|
|
1188
|
+
}
|
|
1189
|
+
if (a._isInfinite) return a._sign;
|
|
1190
|
+
if (b._isInfinite) return -b._sign;
|
|
1191
|
+
if (a._sign === 0 && b._sign === 0) return 0;
|
|
1192
|
+
if (a._sign === 0) return -b._sign;
|
|
1193
|
+
if (b._sign === 0) return a._sign;
|
|
1194
|
+
if (a._sign !== b._sign) return a._sign > b._sign ? 1 : -1;
|
|
1195
|
+
const result = _BigNumber.compareMagnitude(a, b);
|
|
1196
|
+
return a._sign === 1 ? result : -result;
|
|
1197
|
+
}
|
|
1198
|
+
static compareMagnitude(a, b) {
|
|
1199
|
+
const aDigits = a._coefficient.toString();
|
|
1200
|
+
const bDigits = b._coefficient.toString();
|
|
1201
|
+
const aOrder = aDigits.length + a._exponent;
|
|
1202
|
+
const bOrder = bDigits.length + b._exponent;
|
|
1203
|
+
if (aOrder !== bOrder) {
|
|
1204
|
+
return aOrder > bOrder ? 1 : -1;
|
|
1205
|
+
}
|
|
1206
|
+
const aFull = aDigits + "0".repeat(Math.max(0, a._exponent));
|
|
1207
|
+
const bFull = bDigits + "0".repeat(Math.max(0, b._exponent));
|
|
1208
|
+
if (aFull === bFull) return 0;
|
|
1209
|
+
return aFull > bFull ? 1 : -1;
|
|
1210
|
+
}
|
|
1211
|
+
// ============================================================
|
|
1212
|
+
// Conversion Methods
|
|
1213
|
+
// ============================================================
|
|
1214
|
+
valueOf() {
|
|
1215
|
+
if (this._isNaN) return NaN;
|
|
1216
|
+
if (this._isInfinite) return this._sign === 1 ? Infinity : -Infinity;
|
|
1217
|
+
if (this._sign === 0) return 0;
|
|
1218
|
+
const str = this.toString();
|
|
1219
|
+
return parseFloat(str);
|
|
1220
|
+
}
|
|
1221
|
+
toString() {
|
|
1222
|
+
if (this._isNaN) return "NaN";
|
|
1223
|
+
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1224
|
+
if (this._sign === 0) return "0";
|
|
1225
|
+
const sign = this._sign === -1 ? "-" : "";
|
|
1226
|
+
const digits = this._coefficient.toString();
|
|
1227
|
+
if (this._exponent >= 0) {
|
|
1228
|
+
return sign + digits + "0".repeat(this._exponent);
|
|
1229
|
+
} else if (-this._exponent < digits.length) {
|
|
1230
|
+
const insertPos = digits.length + this._exponent;
|
|
1231
|
+
return sign + digits.slice(0, insertPos) + "." + digits.slice(insertPos);
|
|
1232
|
+
} else {
|
|
1233
|
+
return sign + "0." + "0".repeat(-this._exponent - digits.length) + digits;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
toJSON() {
|
|
1237
|
+
return {
|
|
1238
|
+
mathjs: "BigNumber",
|
|
1239
|
+
value: this.toString()
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Convert to fixed-point notation
|
|
1244
|
+
*/
|
|
1245
|
+
toFixed(decimalPlaces = 0) {
|
|
1246
|
+
return this.round(decimalPlaces).toFixedInternal(decimalPlaces);
|
|
1247
|
+
}
|
|
1248
|
+
toFixedInternal(decimalPlaces) {
|
|
1249
|
+
if (this._isNaN) return "NaN";
|
|
1250
|
+
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1251
|
+
if (this._sign === 0) return decimalPlaces > 0 ? "0." + "0".repeat(decimalPlaces) : "0";
|
|
1252
|
+
const sign = this._sign === -1 ? "-" : "";
|
|
1253
|
+
const digits = this._coefficient.toString();
|
|
1254
|
+
if (this._exponent >= 0) {
|
|
1255
|
+
const intPart = digits + "0".repeat(this._exponent);
|
|
1256
|
+
return sign + intPart + (decimalPlaces > 0 ? "." + "0".repeat(decimalPlaces) : "");
|
|
1257
|
+
} else if (-this._exponent <= digits.length) {
|
|
1258
|
+
const insertPos = digits.length + this._exponent;
|
|
1259
|
+
const intPart = digits.slice(0, insertPos) || "0";
|
|
1260
|
+
let decPart = digits.slice(insertPos);
|
|
1261
|
+
if (decPart.length < decimalPlaces) {
|
|
1262
|
+
decPart += "0".repeat(decimalPlaces - decPart.length);
|
|
1263
|
+
}
|
|
1264
|
+
return sign + intPart + (decimalPlaces > 0 ? "." + decPart.slice(0, decimalPlaces) : "");
|
|
1265
|
+
} else {
|
|
1266
|
+
const leadingZeros = -this._exponent - digits.length;
|
|
1267
|
+
let decPart = "0".repeat(leadingZeros) + digits;
|
|
1268
|
+
if (decPart.length < decimalPlaces) {
|
|
1269
|
+
decPart += "0".repeat(decimalPlaces - decPart.length);
|
|
1270
|
+
}
|
|
1271
|
+
return sign + "0" + (decimalPlaces > 0 ? "." + decPart.slice(0, decimalPlaces) : "");
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Convert to exponential notation
|
|
1276
|
+
*/
|
|
1277
|
+
toExponential(decimalPlaces) {
|
|
1278
|
+
if (this._isNaN) return "NaN";
|
|
1279
|
+
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1280
|
+
if (this._sign === 0) {
|
|
1281
|
+
const dp = decimalPlaces ?? 0;
|
|
1282
|
+
return dp > 0 ? "0." + "0".repeat(dp) + "e+0" : "0e+0";
|
|
1283
|
+
}
|
|
1284
|
+
const sign = this._sign === -1 ? "-" : "";
|
|
1285
|
+
const digits = this._coefficient.toString();
|
|
1286
|
+
const exp = digits.length - 1 + this._exponent;
|
|
1287
|
+
const expSign = exp >= 0 ? "+" : "";
|
|
1288
|
+
if (decimalPlaces === void 0) {
|
|
1289
|
+
if (digits.length === 1) {
|
|
1290
|
+
return `${sign}${digits}e${expSign}${exp}`;
|
|
1291
|
+
}
|
|
1292
|
+
return `${sign}${digits[0]}.${digits.slice(1)}e${expSign}${exp}`;
|
|
1293
|
+
}
|
|
1294
|
+
if (decimalPlaces === 0) {
|
|
1295
|
+
return `${sign}${digits[0]}e${expSign}${exp}`;
|
|
1296
|
+
}
|
|
1297
|
+
let decPart = digits.slice(1);
|
|
1298
|
+
if (decPart.length < decimalPlaces) {
|
|
1299
|
+
decPart += "0".repeat(decimalPlaces - decPart.length);
|
|
1300
|
+
} else {
|
|
1301
|
+
decPart = decPart.slice(0, decimalPlaces);
|
|
1302
|
+
}
|
|
1303
|
+
return `${sign}${digits[0]}.${decPart}e${expSign}${exp}`;
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Convert to precision
|
|
1307
|
+
*/
|
|
1308
|
+
toPrecision(significantDigits) {
|
|
1309
|
+
if (significantDigits === void 0) {
|
|
1310
|
+
return this.toString();
|
|
1311
|
+
}
|
|
1312
|
+
if (this._isNaN) return "NaN";
|
|
1313
|
+
if (this._isInfinite) return this._sign === 1 ? "Infinity" : "-Infinity";
|
|
1314
|
+
if (this._sign === 0) {
|
|
1315
|
+
return significantDigits > 1 ? "0." + "0".repeat(significantDigits - 1) : "0";
|
|
1316
|
+
}
|
|
1317
|
+
const digits = this._coefficient.toString();
|
|
1318
|
+
const order = digits.length + this._exponent;
|
|
1319
|
+
if (order > significantDigits || order < -6) {
|
|
1320
|
+
return this.toExponential(significantDigits - 1);
|
|
1321
|
+
}
|
|
1322
|
+
return this.toFixed(significantDigits - order);
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Convert to bigint (truncated)
|
|
1326
|
+
*/
|
|
1327
|
+
toBigInt() {
|
|
1328
|
+
if (this._isNaN || this._isInfinite) {
|
|
1329
|
+
throw new Error("Cannot convert NaN or Infinity to bigint");
|
|
1330
|
+
}
|
|
1331
|
+
if (this._sign === 0) return 0n;
|
|
1332
|
+
const digits = this._coefficient.toString();
|
|
1333
|
+
if (this._exponent >= 0) {
|
|
1334
|
+
return BigInt(this._sign) * BigInt(digits + "0".repeat(this._exponent));
|
|
1335
|
+
} else if (-this._exponent < digits.length) {
|
|
1336
|
+
return BigInt(this._sign) * BigInt(digits.slice(0, digits.length + this._exponent));
|
|
1337
|
+
}
|
|
1338
|
+
return 0n;
|
|
1339
|
+
}
|
|
1340
|
+
// ============================================================
|
|
1341
|
+
// Arithmetic Operations
|
|
1342
|
+
// ============================================================
|
|
1343
|
+
/**
|
|
1344
|
+
* Addition
|
|
1345
|
+
*/
|
|
1346
|
+
add(other) {
|
|
1347
|
+
const b = this.ensureBigNumber(other);
|
|
1348
|
+
if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1349
|
+
if (this._isInfinite && b._isInfinite) {
|
|
1350
|
+
if (this._sign === b._sign) return this;
|
|
1351
|
+
return new _BigNumber(0, 0n, 0, true);
|
|
1352
|
+
}
|
|
1353
|
+
if (this._isInfinite) return this;
|
|
1354
|
+
if (b._isInfinite) return b;
|
|
1355
|
+
if (this._sign === 0) return b;
|
|
1356
|
+
if (b._sign === 0) return this;
|
|
1357
|
+
const [aCoef, bCoef, exp] = this.alignExponents(this, b);
|
|
1358
|
+
if (this._sign === b._sign) {
|
|
1359
|
+
return this.normalize(this._sign, aCoef + bCoef, exp);
|
|
1360
|
+
} else {
|
|
1361
|
+
if (aCoef >= bCoef) {
|
|
1362
|
+
const diff = aCoef - bCoef;
|
|
1363
|
+
return this.normalize(diff === 0n ? 0 : this._sign, diff, exp);
|
|
1364
|
+
} else {
|
|
1365
|
+
return this.normalize(b._sign, bCoef - aCoef, exp);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
/**
|
|
1370
|
+
* Subtraction
|
|
1371
|
+
*/
|
|
1372
|
+
subtract(other) {
|
|
1373
|
+
const b = this.ensureBigNumber(other);
|
|
1374
|
+
return this.add(b.negate());
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Multiplication
|
|
1378
|
+
*/
|
|
1379
|
+
multiply(other) {
|
|
1380
|
+
const b = this.ensureBigNumber(other);
|
|
1381
|
+
if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1382
|
+
if (this._isInfinite || b._isInfinite) {
|
|
1383
|
+
if (this._sign === 0 || b._sign === 0) return new _BigNumber(0, 0n, 0, true);
|
|
1384
|
+
const sign2 = this._sign * b._sign;
|
|
1385
|
+
return new _BigNumber(sign2, 0n, 0, false, true);
|
|
1386
|
+
}
|
|
1387
|
+
if (this._sign === 0 || b._sign === 0) return new _BigNumber(0, 0n, 0);
|
|
1388
|
+
const sign = this._sign * b._sign;
|
|
1389
|
+
const coefficient = this._coefficient * b._coefficient;
|
|
1390
|
+
const exponent = this._exponent + b._exponent;
|
|
1391
|
+
return this.normalize(sign, coefficient, exponent);
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Division
|
|
1395
|
+
*/
|
|
1396
|
+
divide(other) {
|
|
1397
|
+
const b = this.ensureBigNumber(other);
|
|
1398
|
+
if (this._isNaN || b._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1399
|
+
if (this._isInfinite && b._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1400
|
+
if (b._sign === 0) {
|
|
1401
|
+
if (this._sign === 0) return new _BigNumber(0, 0n, 0, true);
|
|
1402
|
+
return new _BigNumber(this._sign, 0n, 0, false, true);
|
|
1403
|
+
}
|
|
1404
|
+
if (this._isInfinite) {
|
|
1405
|
+
const sign2 = this._sign * b._sign;
|
|
1406
|
+
return new _BigNumber(sign2, 0n, 0, false, true);
|
|
1407
|
+
}
|
|
1408
|
+
if (b._isInfinite) return new _BigNumber(0, 0n, 0);
|
|
1409
|
+
if (this._sign === 0) return new _BigNumber(0, 0n, 0);
|
|
1410
|
+
const sign = this._sign * b._sign;
|
|
1411
|
+
const precision = globalConfig.precision;
|
|
1412
|
+
const scale = BigInt(10) ** BigInt(precision + 10);
|
|
1413
|
+
const scaledDividend = this._coefficient * scale;
|
|
1414
|
+
const quotient = scaledDividend / b._coefficient;
|
|
1415
|
+
const exponent = this._exponent - b._exponent - precision - 10;
|
|
1416
|
+
return this.normalize(sign, quotient, exponent).roundToPrecision(precision);
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Negation
|
|
1420
|
+
*/
|
|
1421
|
+
negate() {
|
|
1422
|
+
if (this._isNaN) return this;
|
|
1423
|
+
if (this._sign === 0) return this;
|
|
1424
|
+
const newSign = this._sign === 1 ? -1 : 1;
|
|
1425
|
+
return new _BigNumber(newSign, this._coefficient, this._exponent, false, this._isInfinite);
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Absolute value
|
|
1429
|
+
*/
|
|
1430
|
+
abs() {
|
|
1431
|
+
if (this._isNaN) return this;
|
|
1432
|
+
if (this._sign === 0) return this;
|
|
1433
|
+
return new _BigNumber(1, this._coefficient, this._exponent, false, this._isInfinite);
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* Power (integer exponent)
|
|
1437
|
+
*/
|
|
1438
|
+
pow(n) {
|
|
1439
|
+
const exp = typeof n === "bigint" ? Number(n) : n;
|
|
1440
|
+
if (this._isNaN) return this;
|
|
1441
|
+
if (exp === 0) return _BigNumber.fromNumber(1);
|
|
1442
|
+
if (this._sign === 0) {
|
|
1443
|
+
if (exp < 0) return new _BigNumber(1, 0n, 0, false, true);
|
|
1444
|
+
return this;
|
|
1445
|
+
}
|
|
1446
|
+
if (exp < 0) {
|
|
1447
|
+
return _BigNumber.fromNumber(1).divide(this.pow(-exp));
|
|
1448
|
+
}
|
|
1449
|
+
let result = _BigNumber.fromNumber(1);
|
|
1450
|
+
let base = this;
|
|
1451
|
+
let e = exp;
|
|
1452
|
+
while (e > 0) {
|
|
1453
|
+
if (e % 2 === 1) {
|
|
1454
|
+
result = result.multiply(base);
|
|
1455
|
+
}
|
|
1456
|
+
base = base.multiply(base);
|
|
1457
|
+
e = Math.floor(e / 2);
|
|
1458
|
+
}
|
|
1459
|
+
return result.roundToPrecision(globalConfig.precision);
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Square root
|
|
1463
|
+
*/
|
|
1464
|
+
sqrt() {
|
|
1465
|
+
if (this._isNaN) return this;
|
|
1466
|
+
if (this._sign === -1) return new _BigNumber(0, 0n, 0, true);
|
|
1467
|
+
if (this._sign === 0) return this;
|
|
1468
|
+
if (this._isInfinite) return this;
|
|
1469
|
+
const precision = globalConfig.precision;
|
|
1470
|
+
let guess = _BigNumber.fromNumber(Math.sqrt(this.valueOf()));
|
|
1471
|
+
for (let i = 0; i < 100; i++) {
|
|
1472
|
+
const newGuess = guess.add(this.divide(guess)).divide(_BigNumber.fromNumber(2));
|
|
1473
|
+
if (guess.subtract(newGuess).abs().compareTo(guess.multiply(_BigNumber.parse("1e-" + (precision + 5)))) <= 0) {
|
|
1474
|
+
return newGuess.roundToPrecision(precision);
|
|
1475
|
+
}
|
|
1476
|
+
guess = newGuess;
|
|
1477
|
+
}
|
|
1478
|
+
return guess.roundToPrecision(precision);
|
|
1479
|
+
}
|
|
1480
|
+
// ============================================================
|
|
1481
|
+
// Comparison Methods
|
|
1482
|
+
// ============================================================
|
|
1483
|
+
equals(other) {
|
|
1484
|
+
return _BigNumber.compare(this, other) === 0;
|
|
1485
|
+
}
|
|
1486
|
+
lessThan(other) {
|
|
1487
|
+
return _BigNumber.compare(this, other) < 0;
|
|
1488
|
+
}
|
|
1489
|
+
lessThanOrEqual(other) {
|
|
1490
|
+
return _BigNumber.compare(this, other) <= 0;
|
|
1491
|
+
}
|
|
1492
|
+
greaterThan(other) {
|
|
1493
|
+
return _BigNumber.compare(this, other) > 0;
|
|
1494
|
+
}
|
|
1495
|
+
greaterThanOrEqual(other) {
|
|
1496
|
+
return _BigNumber.compare(this, other) >= 0;
|
|
1497
|
+
}
|
|
1498
|
+
compareTo(other) {
|
|
1499
|
+
return _BigNumber.compare(this, other);
|
|
1500
|
+
}
|
|
1501
|
+
compare(other) {
|
|
1502
|
+
return this.compareTo(other);
|
|
1503
|
+
}
|
|
1504
|
+
// ============================================================
|
|
1505
|
+
// Rounding Methods
|
|
1506
|
+
// ============================================================
|
|
1507
|
+
/**
|
|
1508
|
+
* Round to specified decimal places
|
|
1509
|
+
*/
|
|
1510
|
+
round(decimalPlaces = 0, mode = globalConfig.rounding) {
|
|
1511
|
+
if (this._isNaN || this._isInfinite || this._sign === 0) return this;
|
|
1512
|
+
const targetExp = -decimalPlaces;
|
|
1513
|
+
if (this._exponent >= targetExp) return this;
|
|
1514
|
+
const shift = targetExp - this._exponent;
|
|
1515
|
+
const divisor = BigInt(10) ** BigInt(shift);
|
|
1516
|
+
const quotient = this._coefficient / divisor;
|
|
1517
|
+
const remainder = this._coefficient % divisor;
|
|
1518
|
+
let rounded = quotient;
|
|
1519
|
+
const halfDivisor = divisor / 2n;
|
|
1520
|
+
const shouldRoundUp = this.shouldRound(remainder, halfDivisor, divisor, quotient, mode);
|
|
1521
|
+
if (shouldRoundUp) {
|
|
1522
|
+
rounded += 1n;
|
|
1523
|
+
}
|
|
1524
|
+
return this.normalize(rounded === 0n ? 0 : this._sign, rounded, targetExp);
|
|
1525
|
+
}
|
|
1526
|
+
shouldRound(remainder, halfDivisor, divisor, quotient, mode) {
|
|
1527
|
+
const isPositive = this._sign === 1;
|
|
1528
|
+
const isExactlyHalf = remainder === halfDivisor && divisor % 2n === 0n;
|
|
1529
|
+
const isMoreThanHalf = remainder > halfDivisor;
|
|
1530
|
+
switch (mode) {
|
|
1531
|
+
case "up":
|
|
1532
|
+
return remainder > 0n;
|
|
1533
|
+
case "down":
|
|
1534
|
+
return false;
|
|
1535
|
+
case "ceil":
|
|
1536
|
+
return isPositive && remainder > 0n;
|
|
1537
|
+
case "floor":
|
|
1538
|
+
return !isPositive && remainder > 0n;
|
|
1539
|
+
case "halfUp":
|
|
1540
|
+
return isMoreThanHalf || isExactlyHalf;
|
|
1541
|
+
case "halfDown":
|
|
1542
|
+
return isMoreThanHalf;
|
|
1543
|
+
case "halfEven":
|
|
1544
|
+
return isMoreThanHalf || isExactlyHalf && quotient % 2n !== 0n;
|
|
1545
|
+
case "halfCeil":
|
|
1546
|
+
return isMoreThanHalf || isExactlyHalf && isPositive;
|
|
1547
|
+
case "halfFloor":
|
|
1548
|
+
return isMoreThanHalf || isExactlyHalf && !isPositive;
|
|
1549
|
+
default:
|
|
1550
|
+
return isMoreThanHalf || isExactlyHalf;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Round to specified precision (significant digits)
|
|
1555
|
+
*/
|
|
1556
|
+
roundToPrecision(precision, mode = globalConfig.rounding) {
|
|
1557
|
+
if (this._isNaN || this._isInfinite || this._sign === 0) return this;
|
|
1558
|
+
const digits = this._coefficient.toString();
|
|
1559
|
+
if (digits.length <= precision) return this;
|
|
1560
|
+
const digitsToRemove = digits.length - precision;
|
|
1561
|
+
const divisor = BigInt(10) ** BigInt(digitsToRemove);
|
|
1562
|
+
const quotient = this._coefficient / divisor;
|
|
1563
|
+
const remainder = this._coefficient % divisor;
|
|
1564
|
+
const halfDivisor = divisor / 2n;
|
|
1565
|
+
let rounded = quotient;
|
|
1566
|
+
const shouldRoundUp = this.shouldRound(remainder, halfDivisor, divisor, quotient, mode);
|
|
1567
|
+
if (shouldRoundUp) {
|
|
1568
|
+
rounded += 1n;
|
|
1569
|
+
}
|
|
1570
|
+
const newExponent = this._exponent + digitsToRemove;
|
|
1571
|
+
return this.normalize(rounded === 0n ? 0 : this._sign, rounded, newExponent);
|
|
1572
|
+
}
|
|
1573
|
+
floor() {
|
|
1574
|
+
return this.round(0, "floor");
|
|
1575
|
+
}
|
|
1576
|
+
ceil() {
|
|
1577
|
+
return this.round(0, "ceil");
|
|
1578
|
+
}
|
|
1579
|
+
trunc() {
|
|
1580
|
+
return this.round(0, "down");
|
|
1581
|
+
}
|
|
1582
|
+
// ============================================================
|
|
1583
|
+
// Modular Arithmetic
|
|
1584
|
+
// ============================================================
|
|
1585
|
+
/**
|
|
1586
|
+
* Modulo (remainder after division)
|
|
1587
|
+
* Result has the same sign as the dividend (this).
|
|
1588
|
+
*/
|
|
1589
|
+
mod(other) {
|
|
1590
|
+
const b = this.ensureBigNumber(other);
|
|
1591
|
+
if (this._isNaN || b._isNaN || b._sign === 0) return new _BigNumber(0, 0n, 0, true);
|
|
1592
|
+
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1593
|
+
if (b._isInfinite) return this;
|
|
1594
|
+
if (this._sign === 0) return this;
|
|
1595
|
+
const quotient = this.divide(b).trunc();
|
|
1596
|
+
return this.subtract(b.multiply(quotient));
|
|
1597
|
+
}
|
|
1598
|
+
// ============================================================
|
|
1599
|
+
// Trigonometric Functions
|
|
1600
|
+
// ============================================================
|
|
1601
|
+
/**
|
|
1602
|
+
* Sine of this BigNumber (in radians)
|
|
1603
|
+
* Uses Taylor series: sin(x) = x - x^3/3! + x^5/5! - ...
|
|
1604
|
+
*/
|
|
1605
|
+
sin() {
|
|
1606
|
+
if (this._isNaN) return this;
|
|
1607
|
+
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1608
|
+
if (this._sign === 0) return this;
|
|
1609
|
+
const x = this._reduceAngle();
|
|
1610
|
+
return x._sinTaylor();
|
|
1611
|
+
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Cosine of this BigNumber (in radians)
|
|
1614
|
+
* Uses Taylor series: cos(x) = 1 - x^2/2! + x^4/4! - ...
|
|
1615
|
+
*/
|
|
1616
|
+
cos() {
|
|
1617
|
+
if (this._isNaN) return this;
|
|
1618
|
+
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1619
|
+
if (this._sign === 0) return _BigNumber.fromNumber(1);
|
|
1620
|
+
const x = this._reduceAngle();
|
|
1621
|
+
return x._cosTaylor();
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Tangent of this BigNumber (in radians)
|
|
1625
|
+
* tan(x) = sin(x) / cos(x)
|
|
1626
|
+
*/
|
|
1627
|
+
tan() {
|
|
1628
|
+
if (this._isNaN) return this;
|
|
1629
|
+
if (this._isInfinite) return new _BigNumber(0, 0n, 0, true);
|
|
1630
|
+
if (this._sign === 0) return this;
|
|
1631
|
+
const x = this._reduceAngle();
|
|
1632
|
+
return x._sinTaylor().divide(x._cosTaylor());
|
|
1633
|
+
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Arcsine of this BigNumber
|
|
1636
|
+
* Returns value in [-PI/2, PI/2]
|
|
1637
|
+
*/
|
|
1638
|
+
asin() {
|
|
1639
|
+
if (this._isNaN) return this;
|
|
1640
|
+
const one = _BigNumber.fromNumber(1);
|
|
1641
|
+
if (this.abs().compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
|
|
1642
|
+
if (this._sign === 0) return this;
|
|
1643
|
+
const xSquared = this.multiply(this);
|
|
1644
|
+
const denominator = one.subtract(xSquared).sqrt();
|
|
1645
|
+
if (denominator.isZero()) {
|
|
1646
|
+
return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
|
|
1647
|
+
}
|
|
1648
|
+
return this.divide(denominator).atan();
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Arccosine of this BigNumber
|
|
1652
|
+
* Returns value in [0, PI]
|
|
1653
|
+
*/
|
|
1654
|
+
acos() {
|
|
1655
|
+
if (this._isNaN) return this;
|
|
1656
|
+
const one = _BigNumber.fromNumber(1);
|
|
1657
|
+
if (this.abs().compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
|
|
1658
|
+
return BIGNUMBER_PI.divide(2).subtract(this.asin());
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Arctangent of this BigNumber
|
|
1662
|
+
* Returns value in (-PI/2, PI/2)
|
|
1663
|
+
* Uses Taylor series with argument reduction for convergence.
|
|
1664
|
+
*/
|
|
1665
|
+
atan() {
|
|
1666
|
+
if (this._isNaN) return this;
|
|
1667
|
+
if (this._sign === 0) return this;
|
|
1668
|
+
if (this._isInfinite) {
|
|
1669
|
+
return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
|
|
1670
|
+
}
|
|
1671
|
+
const one = _BigNumber.fromNumber(1);
|
|
1672
|
+
if (this.abs().compareTo(one) > 0) {
|
|
1673
|
+
const reciprocal = one.divide(this);
|
|
1674
|
+
const piHalf = BIGNUMBER_PI.divide(2);
|
|
1675
|
+
return this._sign === 1 ? piHalf.subtract(reciprocal.atan()) : piHalf.negate().subtract(reciprocal.atan());
|
|
1676
|
+
}
|
|
1677
|
+
const half = _BigNumber.fromNumber(0.5);
|
|
1678
|
+
if (this.abs().compareTo(half) > 0) {
|
|
1679
|
+
const xSq = this.multiply(this);
|
|
1680
|
+
const reduced = this.divide(one.add(one.add(xSq).sqrt()));
|
|
1681
|
+
return reduced.atan().multiply(_BigNumber.fromNumber(2));
|
|
1682
|
+
}
|
|
1683
|
+
return this._atanTaylor();
|
|
1684
|
+
}
|
|
1685
|
+
/**
|
|
1686
|
+
* Two-argument arctangent: atan2(y, x)
|
|
1687
|
+
* this = y, argument = x
|
|
1688
|
+
* Returns angle in (-PI, PI]
|
|
1689
|
+
*/
|
|
1690
|
+
atan2(x) {
|
|
1691
|
+
if (this._isNaN || x._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1692
|
+
if (this._sign === 0 && x._sign === 0) return _BigNumber.fromNumber(0);
|
|
1693
|
+
if (x._sign === 0) {
|
|
1694
|
+
return this._sign === 1 ? BIGNUMBER_PI.divide(2) : BIGNUMBER_PI.divide(-2);
|
|
1695
|
+
}
|
|
1696
|
+
const angle = this.divide(x).atan();
|
|
1697
|
+
if (x.isPositive()) {
|
|
1698
|
+
return angle;
|
|
1699
|
+
} else if (this.isNegative()) {
|
|
1700
|
+
return angle.subtract(BIGNUMBER_PI);
|
|
1701
|
+
} else {
|
|
1702
|
+
return angle.add(BIGNUMBER_PI);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
// ============================================================
|
|
1706
|
+
// Hyperbolic Functions
|
|
1707
|
+
// ============================================================
|
|
1708
|
+
/**
|
|
1709
|
+
* Hyperbolic sine: sinh(x) = (e^x - e^(-x)) / 2
|
|
1710
|
+
*/
|
|
1711
|
+
sinh() {
|
|
1712
|
+
if (this._isNaN) return this;
|
|
1713
|
+
if (this._isInfinite) return this;
|
|
1714
|
+
if (this._sign === 0) return this;
|
|
1715
|
+
const ex = this.exp();
|
|
1716
|
+
const enx = this.negate().exp();
|
|
1717
|
+
return ex.subtract(enx).divide(_BigNumber.fromNumber(2));
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Hyperbolic cosine: cosh(x) = (e^x + e^(-x)) / 2
|
|
1721
|
+
*/
|
|
1722
|
+
cosh() {
|
|
1723
|
+
if (this._isNaN) return this;
|
|
1724
|
+
if (this._isInfinite) return new _BigNumber(1, 0n, 0, false, true);
|
|
1725
|
+
if (this._sign === 0) return _BigNumber.fromNumber(1);
|
|
1726
|
+
const ex = this.exp();
|
|
1727
|
+
const enx = this.negate().exp();
|
|
1728
|
+
return ex.add(enx).divide(_BigNumber.fromNumber(2));
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Hyperbolic tangent: tanh(x) = sinh(x) / cosh(x)
|
|
1732
|
+
*/
|
|
1733
|
+
tanh() {
|
|
1734
|
+
if (this._isNaN) return this;
|
|
1735
|
+
if (this._sign === 0) return this;
|
|
1736
|
+
if (this._isInfinite) return _BigNumber.fromNumber(this._sign);
|
|
1737
|
+
const ex = this.exp();
|
|
1738
|
+
const enx = this.negate().exp();
|
|
1739
|
+
return ex.subtract(enx).divide(ex.add(enx));
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Inverse hyperbolic sine: asinh(x) = ln(x + sqrt(x^2 + 1))
|
|
1743
|
+
*/
|
|
1744
|
+
asinh() {
|
|
1745
|
+
if (this._isNaN) return this;
|
|
1746
|
+
if (this._isInfinite) return this;
|
|
1747
|
+
if (this._sign === 0) return this;
|
|
1748
|
+
const one = _BigNumber.fromNumber(1);
|
|
1749
|
+
return this.add(this.multiply(this).add(one).sqrt()).ln();
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* Inverse hyperbolic cosine: acosh(x) = ln(x + sqrt(x^2 - 1))
|
|
1753
|
+
* Domain: x >= 1
|
|
1754
|
+
*/
|
|
1755
|
+
acosh() {
|
|
1756
|
+
if (this._isNaN) return this;
|
|
1757
|
+
const one = _BigNumber.fromNumber(1);
|
|
1758
|
+
if (this.compareTo(one) < 0) return new _BigNumber(0, 0n, 0, true);
|
|
1759
|
+
if (this._isInfinite) return this;
|
|
1760
|
+
return this.add(this.multiply(this).subtract(one).sqrt()).ln();
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Inverse hyperbolic tangent: atanh(x) = 0.5 * ln((1+x)/(1-x))
|
|
1764
|
+
* Domain: -1 < x < 1
|
|
1765
|
+
*/
|
|
1766
|
+
atanh() {
|
|
1767
|
+
if (this._isNaN) return this;
|
|
1768
|
+
const one = _BigNumber.fromNumber(1);
|
|
1769
|
+
const absVal = this.abs();
|
|
1770
|
+
if (absVal.compareTo(one) > 0) return new _BigNumber(0, 0n, 0, true);
|
|
1771
|
+
if (absVal.equals(one)) {
|
|
1772
|
+
return this._sign === 1 ? new _BigNumber(1, 0n, 0, false, true) : new _BigNumber(-1, 0n, 0, false, true);
|
|
1773
|
+
}
|
|
1774
|
+
if (this._sign === 0) return this;
|
|
1775
|
+
const half = _BigNumber.fromNumber(0.5);
|
|
1776
|
+
return one.add(this).divide(one.subtract(this)).ln().multiply(half);
|
|
1777
|
+
}
|
|
1778
|
+
// ============================================================
|
|
1779
|
+
// Transcendental Functions
|
|
1780
|
+
// ============================================================
|
|
1781
|
+
/**
|
|
1782
|
+
* Exponential function: e^x
|
|
1783
|
+
* Uses Taylor series: e^x = 1 + x + x^2/2! + x^3/3! + ...
|
|
1784
|
+
* With argument reduction: e^x = (e^(x/2^k))^(2^k) for faster convergence.
|
|
1785
|
+
*/
|
|
1786
|
+
exp() {
|
|
1787
|
+
if (this._isNaN) return this;
|
|
1788
|
+
if (this._sign === 0) return _BigNumber.fromNumber(1);
|
|
1789
|
+
if (this._isInfinite) {
|
|
1790
|
+
return this._sign === 1 ? this : _BigNumber.fromNumber(0);
|
|
1791
|
+
}
|
|
1792
|
+
const precision = globalConfig.precision;
|
|
1793
|
+
const val = Math.abs(this.valueOf());
|
|
1794
|
+
let k = 0;
|
|
1795
|
+
if (val > 0.5) {
|
|
1796
|
+
k = Math.ceil(Math.log2(val * 2));
|
|
1797
|
+
}
|
|
1798
|
+
const divisor = _BigNumber.fromNumber(2 ** k);
|
|
1799
|
+
const reduced = this.divide(divisor);
|
|
1800
|
+
let sum = _BigNumber.fromNumber(1);
|
|
1801
|
+
let term = _BigNumber.fromNumber(1);
|
|
1802
|
+
const maxIter = precision + 20;
|
|
1803
|
+
for (let n = 1; n <= maxIter; n++) {
|
|
1804
|
+
term = term.multiply(reduced).divide(_BigNumber.fromNumber(n));
|
|
1805
|
+
const newSum = sum.add(term);
|
|
1806
|
+
if (sum.equals(newSum)) break;
|
|
1807
|
+
sum = newSum;
|
|
1808
|
+
}
|
|
1809
|
+
for (let i = 0; i < k; i++) {
|
|
1810
|
+
sum = sum.multiply(sum);
|
|
1811
|
+
}
|
|
1812
|
+
return sum.roundToPrecision(precision);
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Natural logarithm: ln(x)
|
|
1816
|
+
* Uses the AGM (arithmetic-geometric mean) method for fast convergence.
|
|
1817
|
+
* Fallback: series ln((1+y)/(1-y)) = 2*(y + y^3/3 + y^5/5 + ...) where y = (x-1)/(x+1)
|
|
1818
|
+
*/
|
|
1819
|
+
ln() {
|
|
1820
|
+
if (this._isNaN) return this;
|
|
1821
|
+
if (this._sign === -1) return new _BigNumber(0, 0n, 0, true);
|
|
1822
|
+
if (this._sign === 0) return new _BigNumber(-1, 0n, 0, false, true);
|
|
1823
|
+
if (this._isInfinite) return this;
|
|
1824
|
+
const one = _BigNumber.fromNumber(1);
|
|
1825
|
+
if (this.equals(one)) return _BigNumber.fromNumber(0);
|
|
1826
|
+
const precision = globalConfig.precision;
|
|
1827
|
+
let x = this.clone();
|
|
1828
|
+
let k = 0;
|
|
1829
|
+
const two = _BigNumber.fromNumber(2);
|
|
1830
|
+
const half = _BigNumber.fromNumber(0.5);
|
|
1831
|
+
while (x.compareTo(two) > 0) {
|
|
1832
|
+
x = x.divide(two);
|
|
1833
|
+
k++;
|
|
1834
|
+
}
|
|
1835
|
+
while (x.compareTo(half) < 0) {
|
|
1836
|
+
x = x.multiply(two);
|
|
1837
|
+
k--;
|
|
1838
|
+
}
|
|
1839
|
+
const y = x.subtract(one).divide(x.add(one));
|
|
1840
|
+
const ySq = y.multiply(y);
|
|
1841
|
+
let term = y;
|
|
1842
|
+
let sum = y;
|
|
1843
|
+
const maxIter = precision + 20;
|
|
1844
|
+
for (let n = 1; n <= maxIter; n++) {
|
|
1845
|
+
term = term.multiply(ySq);
|
|
1846
|
+
const contribution = term.divide(_BigNumber.fromNumber(2 * n + 1));
|
|
1847
|
+
const newSum = sum.add(contribution);
|
|
1848
|
+
if (sum.equals(newSum)) break;
|
|
1849
|
+
sum = newSum;
|
|
1850
|
+
}
|
|
1851
|
+
sum = sum.multiply(two);
|
|
1852
|
+
if (k !== 0) {
|
|
1853
|
+
sum = sum.add(BIGNUMBER_LN2.multiply(_BigNumber.fromNumber(k)));
|
|
1854
|
+
}
|
|
1855
|
+
return sum.roundToPrecision(precision);
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Base-10 logarithm: log10(x) = ln(x) / ln(10)
|
|
1859
|
+
*/
|
|
1860
|
+
log10() {
|
|
1861
|
+
return this.ln().divide(BIGNUMBER_LN10);
|
|
1862
|
+
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Base-2 logarithm: log2(x) = ln(x) / ln(2)
|
|
1865
|
+
*/
|
|
1866
|
+
log2() {
|
|
1867
|
+
return this.ln().divide(BIGNUMBER_LN2);
|
|
1868
|
+
}
|
|
1869
|
+
/**
|
|
1870
|
+
* Cube root
|
|
1871
|
+
* Uses Newton-Raphson iteration.
|
|
1872
|
+
*/
|
|
1873
|
+
cbrt() {
|
|
1874
|
+
if (this._isNaN) return this;
|
|
1875
|
+
if (this._sign === 0) return this;
|
|
1876
|
+
if (this._isInfinite) return this;
|
|
1877
|
+
if (this._sign === -1) {
|
|
1878
|
+
return this.negate().cbrt().negate();
|
|
1879
|
+
}
|
|
1880
|
+
const precision = globalConfig.precision;
|
|
1881
|
+
const three = _BigNumber.fromNumber(3);
|
|
1882
|
+
let guess = _BigNumber.fromNumber(Math.cbrt(this.valueOf()));
|
|
1883
|
+
for (let i = 0; i < 100; i++) {
|
|
1884
|
+
const guessSquared = guess.multiply(guess);
|
|
1885
|
+
const newGuess = guess.multiply(_BigNumber.fromNumber(2)).add(this.divide(guessSquared)).divide(three);
|
|
1886
|
+
if (guess.subtract(newGuess).abs().compareTo(
|
|
1887
|
+
guess.abs().multiply(_BigNumber.parse("1e-" + (precision + 5)))
|
|
1888
|
+
) <= 0) {
|
|
1889
|
+
return newGuess.roundToPrecision(precision);
|
|
1890
|
+
}
|
|
1891
|
+
guess = newGuess;
|
|
1892
|
+
}
|
|
1893
|
+
return guess.roundToPrecision(precision);
|
|
1894
|
+
}
|
|
1895
|
+
/**
|
|
1896
|
+
* e^x - 1 (more precise than exp(x) - 1 for small x)
|
|
1897
|
+
* Uses Taylor series directly: expm1(x) = x + x^2/2! + x^3/3! + ...
|
|
1898
|
+
*/
|
|
1899
|
+
expm1() {
|
|
1900
|
+
if (this._isNaN) return this;
|
|
1901
|
+
if (this._sign === 0) return this;
|
|
1902
|
+
if (this._isInfinite) {
|
|
1903
|
+
return this._sign === 1 ? this : _BigNumber.fromNumber(-1);
|
|
1904
|
+
}
|
|
1905
|
+
if (Math.abs(this.valueOf()) > 0.5) {
|
|
1906
|
+
return this.exp().subtract(_BigNumber.fromNumber(1));
|
|
1907
|
+
}
|
|
1908
|
+
const precision = globalConfig.precision;
|
|
1909
|
+
let term = this.clone();
|
|
1910
|
+
let sum = this.clone();
|
|
1911
|
+
const maxIter = precision + 20;
|
|
1912
|
+
for (let n = 2; n <= maxIter; n++) {
|
|
1913
|
+
term = term.multiply(this).divide(_BigNumber.fromNumber(n));
|
|
1914
|
+
const newSum = sum.add(term);
|
|
1915
|
+
if (sum.equals(newSum)) break;
|
|
1916
|
+
sum = newSum;
|
|
1917
|
+
}
|
|
1918
|
+
return sum.roundToPrecision(precision);
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* ln(1 + x) (more precise than ln(1 + x) for small x)
|
|
1922
|
+
*/
|
|
1923
|
+
log1p() {
|
|
1924
|
+
if (this._isNaN) return this;
|
|
1925
|
+
const one = _BigNumber.fromNumber(1);
|
|
1926
|
+
const negOne = _BigNumber.fromNumber(-1);
|
|
1927
|
+
if (this.compareTo(negOne) < 0) return new _BigNumber(0, 0n, 0, true);
|
|
1928
|
+
if (this.equals(negOne)) return new _BigNumber(-1, 0n, 0, false, true);
|
|
1929
|
+
if (this._sign === 0) return this;
|
|
1930
|
+
return one.add(this).ln();
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Hypotenuse: sqrt(this^2 + other^2)
|
|
1934
|
+
*/
|
|
1935
|
+
hypot(other) {
|
|
1936
|
+
if (this._isNaN || other._isNaN) return new _BigNumber(0, 0n, 0, true);
|
|
1937
|
+
if (this._isInfinite || other._isInfinite) return new _BigNumber(1, 0n, 0, false, true);
|
|
1938
|
+
return this.multiply(this).add(other.multiply(other)).sqrt();
|
|
1939
|
+
}
|
|
1940
|
+
// ============================================================
|
|
1941
|
+
// Private Taylor Series Helpers
|
|
1942
|
+
// ============================================================
|
|
1943
|
+
/** Reduce angle to [-PI, PI] range */
|
|
1944
|
+
_reduceAngle() {
|
|
1945
|
+
const twoPi = BIGNUMBER_PI.multiply(_BigNumber.fromNumber(2));
|
|
1946
|
+
if (this.abs().compareTo(BIGNUMBER_PI) <= 0) {
|
|
1947
|
+
return this;
|
|
1948
|
+
}
|
|
1949
|
+
const quotient = this.divide(twoPi).round(0, "halfUp");
|
|
1950
|
+
let reduced = this.subtract(twoPi.multiply(quotient));
|
|
1951
|
+
if (reduced.compareTo(BIGNUMBER_PI) > 0) {
|
|
1952
|
+
reduced = reduced.subtract(twoPi);
|
|
1953
|
+
} else if (reduced.compareTo(BIGNUMBER_PI.negate()) < 0) {
|
|
1954
|
+
reduced = reduced.add(twoPi);
|
|
1955
|
+
}
|
|
1956
|
+
return reduced;
|
|
1957
|
+
}
|
|
1958
|
+
/** Taylor series for sin(x), assumes x is in [-PI, PI] */
|
|
1959
|
+
_sinTaylor() {
|
|
1960
|
+
const precision = globalConfig.precision;
|
|
1961
|
+
let term = this.clone();
|
|
1962
|
+
let sum = this.clone();
|
|
1963
|
+
const xSquared = this.multiply(this);
|
|
1964
|
+
const maxIter = precision + 20;
|
|
1965
|
+
for (let n = 1; n <= maxIter; n++) {
|
|
1966
|
+
term = term.multiply(xSquared).divide(
|
|
1967
|
+
_BigNumber.fromNumber(2 * n * (2 * n + 1))
|
|
1968
|
+
).negate();
|
|
1969
|
+
const newSum = sum.add(term);
|
|
1970
|
+
if (sum.equals(newSum)) break;
|
|
1971
|
+
sum = newSum;
|
|
1972
|
+
}
|
|
1973
|
+
return sum.roundToPrecision(precision);
|
|
1974
|
+
}
|
|
1975
|
+
/** Taylor series for cos(x), assumes x is in [-PI, PI] */
|
|
1976
|
+
_cosTaylor() {
|
|
1977
|
+
const precision = globalConfig.precision;
|
|
1978
|
+
let term = _BigNumber.fromNumber(1);
|
|
1979
|
+
let sum = _BigNumber.fromNumber(1);
|
|
1980
|
+
const xSquared = this.multiply(this);
|
|
1981
|
+
const maxIter = precision + 20;
|
|
1982
|
+
for (let n = 1; n <= maxIter; n++) {
|
|
1983
|
+
term = term.multiply(xSquared).divide(
|
|
1984
|
+
_BigNumber.fromNumber((2 * n - 1) * (2 * n))
|
|
1985
|
+
).negate();
|
|
1986
|
+
const newSum = sum.add(term);
|
|
1987
|
+
if (sum.equals(newSum)) break;
|
|
1988
|
+
sum = newSum;
|
|
1989
|
+
}
|
|
1990
|
+
return sum.roundToPrecision(precision);
|
|
1991
|
+
}
|
|
1992
|
+
/** Taylor series for atan(x), assumes |x| <= 0.5 */
|
|
1993
|
+
_atanTaylor() {
|
|
1994
|
+
const precision = globalConfig.precision;
|
|
1995
|
+
const xSquared = this.multiply(this);
|
|
1996
|
+
let term = this.clone();
|
|
1997
|
+
let sum = this.clone();
|
|
1998
|
+
const maxIter = precision + 20;
|
|
1999
|
+
for (let n = 1; n <= maxIter; n++) {
|
|
2000
|
+
term = term.multiply(xSquared).negate();
|
|
2001
|
+
const contribution = term.divide(_BigNumber.fromNumber(2 * n + 1));
|
|
2002
|
+
const newSum = sum.add(contribution);
|
|
2003
|
+
if (sum.equals(newSum)) break;
|
|
2004
|
+
sum = newSum;
|
|
2005
|
+
}
|
|
2006
|
+
return sum.roundToPrecision(precision);
|
|
2007
|
+
}
|
|
2008
|
+
// ============================================================
|
|
2009
|
+
// Utility Methods
|
|
2010
|
+
// ============================================================
|
|
2011
|
+
isNaN() {
|
|
2012
|
+
return this._isNaN;
|
|
2013
|
+
}
|
|
2014
|
+
isFinite() {
|
|
2015
|
+
return !this._isNaN && !this._isInfinite;
|
|
2016
|
+
}
|
|
2017
|
+
isInfinite() {
|
|
2018
|
+
return this._isInfinite;
|
|
2019
|
+
}
|
|
2020
|
+
isZero() {
|
|
2021
|
+
return this._sign === 0 && !this._isNaN;
|
|
2022
|
+
}
|
|
2023
|
+
isPositive() {
|
|
2024
|
+
return this._sign === 1;
|
|
2025
|
+
}
|
|
2026
|
+
isNegative() {
|
|
2027
|
+
return this._sign === -1;
|
|
2028
|
+
}
|
|
2029
|
+
isInteger() {
|
|
2030
|
+
if (this._isNaN || this._isInfinite || this._sign === 0) return this._sign === 0;
|
|
2031
|
+
return this._exponent >= 0;
|
|
2032
|
+
}
|
|
2033
|
+
sign() {
|
|
2034
|
+
return this._sign;
|
|
2035
|
+
}
|
|
2036
|
+
clone() {
|
|
2037
|
+
return new _BigNumber(this._sign, this._coefficient, this._exponent, this._isNaN, this._isInfinite);
|
|
2038
|
+
}
|
|
2039
|
+
// ============================================================
|
|
2040
|
+
// Private Helper Methods
|
|
2041
|
+
// ============================================================
|
|
2042
|
+
ensureBigNumber(value) {
|
|
2043
|
+
if (value instanceof _BigNumber) return value;
|
|
2044
|
+
if (typeof value === "number") return _BigNumber.fromNumber(value);
|
|
2045
|
+
if (typeof value === "string") return _BigNumber.parse(value);
|
|
2046
|
+
return _BigNumber.fromNumber(Number(value.valueOf()));
|
|
2047
|
+
}
|
|
2048
|
+
alignExponents(a, b) {
|
|
2049
|
+
const minExp = Math.min(a._exponent, b._exponent);
|
|
2050
|
+
const aShift = a._exponent - minExp;
|
|
2051
|
+
const bShift = b._exponent - minExp;
|
|
2052
|
+
const aCoef = aShift > 0 ? a._coefficient * BigInt(10) ** BigInt(aShift) : a._coefficient;
|
|
2053
|
+
const bCoef = bShift > 0 ? b._coefficient * BigInt(10) ** BigInt(bShift) : b._coefficient;
|
|
2054
|
+
return [aCoef, bCoef, minExp];
|
|
2055
|
+
}
|
|
2056
|
+
normalize(sign, coefficient, exponent) {
|
|
2057
|
+
if (coefficient === 0n) {
|
|
2058
|
+
return new _BigNumber(0, 0n, 0);
|
|
2059
|
+
}
|
|
2060
|
+
let coef = coefficient;
|
|
2061
|
+
let exp = exponent;
|
|
2062
|
+
while (coef % 10n === 0n && coef !== 0n) {
|
|
2063
|
+
coef = coef / 10n;
|
|
2064
|
+
exp++;
|
|
2065
|
+
}
|
|
2066
|
+
return new _BigNumber(sign, coef, exp);
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2069
|
+
var BIGNUMBER_ZERO = BigNumber.fromNumber(0);
|
|
2070
|
+
var BIGNUMBER_ONE = BigNumber.fromNumber(1);
|
|
2071
|
+
var BIGNUMBER_NEG_ONE = BigNumber.fromNumber(-1);
|
|
2072
|
+
var BIGNUMBER_TEN = BigNumber.fromNumber(10);
|
|
2073
|
+
var BIGNUMBER_PI = BigNumber.parse("3.14159265358979323846264338327950288419716939937510");
|
|
2074
|
+
var BIGNUMBER_E = BigNumber.parse("2.71828182845904523536028747135266249775724709369995");
|
|
2075
|
+
var BIGNUMBER_LN2 = BigNumber.parse("0.69314718055994530941723212145817656807550013436026");
|
|
2076
|
+
var BIGNUMBER_LN10 = BigNumber.parse("2.30258509299404568401799145468436420760110148862877");
|
|
2077
|
+
|
|
2078
|
+
// src/typed/mathts-typed.ts
|
|
2079
|
+
import typed, { create } from "typed-function";
|
|
2080
|
+
var wasmInitialized = false;
|
|
2081
|
+
var wasmAvailable = false;
|
|
2082
|
+
async function initTypedWasm(options = {}) {
|
|
2083
|
+
if (wasmInitialized) return wasmAvailable;
|
|
2084
|
+
try {
|
|
2085
|
+
if (typeof typed.init === "function") {
|
|
2086
|
+
await typed.init({ preferWasm: options.preferWasm ?? true });
|
|
2087
|
+
wasmAvailable = typed.isWasmEnabled?.() ?? false;
|
|
2088
|
+
}
|
|
2089
|
+
} catch {
|
|
2090
|
+
wasmAvailable = false;
|
|
2091
|
+
}
|
|
2092
|
+
wasmInitialized = true;
|
|
2093
|
+
return wasmAvailable;
|
|
2094
|
+
}
|
|
2095
|
+
function isTypedWasmAvailable() {
|
|
2096
|
+
return typed.isWasmEnabled?.() ?? wasmAvailable;
|
|
2097
|
+
}
|
|
2098
|
+
var isNumber = (x) => typeof x === "number";
|
|
2099
|
+
var isBoolean = (x) => typeof x === "boolean";
|
|
2100
|
+
var isString = (x) => typeof x === "string";
|
|
2101
|
+
var isBigInt = (x) => typeof x === "bigint";
|
|
2102
|
+
var isArray = (x) => Array.isArray(x);
|
|
2103
|
+
var isFunction = (x) => typeof x === "function";
|
|
2104
|
+
var isObject = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
|
|
2105
|
+
var isNull = (x) => x === null;
|
|
2106
|
+
var isUndefined = (x) => x === void 0;
|
|
2107
|
+
var isFloat64Array = (x) => x instanceof Float64Array;
|
|
2108
|
+
var isFloat32Array = (x) => x instanceof Float32Array;
|
|
2109
|
+
var isInt32Array = (x) => x instanceof Int32Array;
|
|
2110
|
+
var isUint32Array = (x) => x instanceof Uint32Array;
|
|
2111
|
+
var isUint8Array = (x) => x instanceof Uint8Array;
|
|
2112
|
+
var isComplex2 = (x) => isComplex(x);
|
|
2113
|
+
var isFraction2 = (x) => isFraction(x);
|
|
2114
|
+
var isBigNumber2 = (x) => isBigNumber(x);
|
|
2115
|
+
var isMatrix = (x) => isObject(x) && "rows" in x && "cols" in x && "get" in x && typeof x.type === "string";
|
|
2116
|
+
var isDenseMatrix = (x) => isMatrix(x) && x.type === "DenseMatrix";
|
|
2117
|
+
var isSparseMatrix = (x) => isMatrix(x) && x.type === "SparseMatrix";
|
|
2118
|
+
var isUnit = (x) => isObject(x) && "value" in x && "unit" in x && typeof x.type === "string";
|
|
2119
|
+
var MATHTS_TYPES = [
|
|
2120
|
+
// bigint is not built into typed-function
|
|
2121
|
+
{ name: "bigint", test: isBigInt },
|
|
2122
|
+
// MathTS numeric types (ordered by specificity for conversion priority)
|
|
2123
|
+
// WASM masks use typed.masks.OBJECT | typed.masks.custom(N) pattern
|
|
2124
|
+
{ name: "Complex", test: isComplex2 },
|
|
2125
|
+
{ name: "Fraction", test: isFraction2 },
|
|
2126
|
+
{ name: "BigNumber", test: isBigNumber2 },
|
|
2127
|
+
// TypedArrays (for parallel-first WASM operations)
|
|
2128
|
+
{ name: "Float64Array", test: isFloat64Array },
|
|
2129
|
+
{ name: "Float32Array", test: isFloat32Array },
|
|
2130
|
+
{ name: "Int32Array", test: isInt32Array },
|
|
2131
|
+
{ name: "Uint32Array", test: isUint32Array },
|
|
2132
|
+
{ name: "Uint8Array", test: isUint8Array },
|
|
2133
|
+
// Matrix types
|
|
2134
|
+
{ name: "DenseMatrix", test: isDenseMatrix },
|
|
2135
|
+
{ name: "SparseMatrix", test: isSparseMatrix },
|
|
2136
|
+
{ name: "Matrix", test: isMatrix },
|
|
2137
|
+
// Other types
|
|
2138
|
+
{ name: "Unit", test: isUnit }
|
|
2139
|
+
];
|
|
2140
|
+
var MATHTS_CONVERSIONS = [
|
|
2141
|
+
// -------------------------------------------------------------------------
|
|
2142
|
+
// To Complex conversions
|
|
2143
|
+
// -------------------------------------------------------------------------
|
|
2144
|
+
{
|
|
2145
|
+
from: "number",
|
|
2146
|
+
to: "Complex",
|
|
2147
|
+
convert: (n) => Complex.fromNumber(n)
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
from: "Fraction",
|
|
2151
|
+
to: "Complex",
|
|
2152
|
+
convert: (f) => Complex.fromNumber(f.toNumber())
|
|
2153
|
+
},
|
|
2154
|
+
{
|
|
2155
|
+
from: "BigNumber",
|
|
2156
|
+
to: "Complex",
|
|
2157
|
+
convert: (bn) => Complex.fromNumber(bn.valueOf())
|
|
2158
|
+
},
|
|
2159
|
+
{
|
|
2160
|
+
from: "string",
|
|
2161
|
+
to: "Complex",
|
|
2162
|
+
convert: (s) => Complex.parse(s)
|
|
2163
|
+
},
|
|
2164
|
+
// -------------------------------------------------------------------------
|
|
2165
|
+
// To Fraction conversions
|
|
2166
|
+
// -------------------------------------------------------------------------
|
|
2167
|
+
{
|
|
2168
|
+
from: "number",
|
|
2169
|
+
to: "Fraction",
|
|
2170
|
+
convert: (n) => Fraction.fromNumber(n)
|
|
2171
|
+
},
|
|
2172
|
+
{
|
|
2173
|
+
from: "bigint",
|
|
2174
|
+
to: "Fraction",
|
|
2175
|
+
convert: (n) => new Fraction(n, 1n)
|
|
2176
|
+
},
|
|
2177
|
+
{
|
|
2178
|
+
from: "string",
|
|
2179
|
+
to: "Fraction",
|
|
2180
|
+
convert: (s) => Fraction.parse(s)
|
|
2181
|
+
},
|
|
2182
|
+
// -------------------------------------------------------------------------
|
|
2183
|
+
// To BigNumber conversions
|
|
2184
|
+
// -------------------------------------------------------------------------
|
|
2185
|
+
{
|
|
2186
|
+
from: "number",
|
|
2187
|
+
to: "BigNumber",
|
|
2188
|
+
convert: (n) => BigNumber.fromNumber(n)
|
|
2189
|
+
},
|
|
2190
|
+
{
|
|
2191
|
+
from: "bigint",
|
|
2192
|
+
to: "BigNumber",
|
|
2193
|
+
convert: (n) => BigNumber.fromBigInt(n)
|
|
2194
|
+
},
|
|
2195
|
+
{
|
|
2196
|
+
from: "Fraction",
|
|
2197
|
+
to: "BigNumber",
|
|
2198
|
+
convert: (f) => BigNumber.fromNumber(f.toNumber())
|
|
2199
|
+
},
|
|
2200
|
+
{
|
|
2201
|
+
from: "string",
|
|
2202
|
+
to: "BigNumber",
|
|
2203
|
+
convert: (s) => BigNumber.parse(s)
|
|
2204
|
+
},
|
|
2205
|
+
// -------------------------------------------------------------------------
|
|
2206
|
+
// To number conversions
|
|
2207
|
+
// -------------------------------------------------------------------------
|
|
2208
|
+
{
|
|
2209
|
+
from: "boolean",
|
|
2210
|
+
to: "number",
|
|
2211
|
+
convert: (b) => b ? 1 : 0
|
|
2212
|
+
},
|
|
2213
|
+
{
|
|
2214
|
+
from: "string",
|
|
2215
|
+
to: "number",
|
|
2216
|
+
convert: (s) => {
|
|
2217
|
+
const n = parseFloat(s);
|
|
2218
|
+
if (isNaN(n)) throw new Error(`Cannot convert "${s}" to number`);
|
|
2219
|
+
return n;
|
|
2220
|
+
}
|
|
2221
|
+
},
|
|
2222
|
+
{
|
|
2223
|
+
from: "bigint",
|
|
2224
|
+
to: "number",
|
|
2225
|
+
convert: (n) => Number(n)
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
from: "Fraction",
|
|
2229
|
+
to: "number",
|
|
2230
|
+
convert: (f) => f.toNumber()
|
|
2231
|
+
},
|
|
2232
|
+
{
|
|
2233
|
+
from: "BigNumber",
|
|
2234
|
+
to: "number",
|
|
2235
|
+
convert: (bn) => bn.valueOf()
|
|
2236
|
+
},
|
|
2237
|
+
// -------------------------------------------------------------------------
|
|
2238
|
+
// To bigint conversions
|
|
2239
|
+
// -------------------------------------------------------------------------
|
|
2240
|
+
{
|
|
2241
|
+
from: "number",
|
|
2242
|
+
to: "bigint",
|
|
2243
|
+
convert: (n) => BigInt(Math.trunc(n))
|
|
2244
|
+
},
|
|
2245
|
+
{
|
|
2246
|
+
from: "Fraction",
|
|
2247
|
+
to: "bigint",
|
|
2248
|
+
convert: (f) => f.trunc().numerator
|
|
2249
|
+
},
|
|
2250
|
+
{
|
|
2251
|
+
from: "BigNumber",
|
|
2252
|
+
to: "bigint",
|
|
2253
|
+
convert: (bn) => bn.toBigInt()
|
|
2254
|
+
},
|
|
2255
|
+
{
|
|
2256
|
+
from: "string",
|
|
2257
|
+
to: "bigint",
|
|
2258
|
+
convert: (s) => BigInt(s)
|
|
2259
|
+
},
|
|
2260
|
+
// -------------------------------------------------------------------------
|
|
2261
|
+
// Matrix conversions (placeholder until Matrix is implemented)
|
|
2262
|
+
// -------------------------------------------------------------------------
|
|
2263
|
+
{
|
|
2264
|
+
from: "Array",
|
|
2265
|
+
to: "Matrix",
|
|
2266
|
+
convert: (a) => {
|
|
2267
|
+
const arr = a;
|
|
2268
|
+
return {
|
|
2269
|
+
rows: arr.length,
|
|
2270
|
+
cols: arr[0]?.length ?? 0,
|
|
2271
|
+
data: arr.flat(),
|
|
2272
|
+
type: "DenseMatrix",
|
|
2273
|
+
get: (r, c) => arr[r]?.[c]
|
|
2274
|
+
};
|
|
2275
|
+
}
|
|
2276
|
+
},
|
|
2277
|
+
{
|
|
2278
|
+
from: "Matrix",
|
|
2279
|
+
to: "Array",
|
|
2280
|
+
convert: (m) => {
|
|
2281
|
+
const matrix = m;
|
|
2282
|
+
const result = [];
|
|
2283
|
+
for (let i = 0; i < matrix.rows; i++) {
|
|
2284
|
+
result[i] = [];
|
|
2285
|
+
for (let j = 0; j < matrix.cols; j++) {
|
|
2286
|
+
result[i][j] = matrix.get(i, j);
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
return result;
|
|
2290
|
+
}
|
|
2291
|
+
},
|
|
2292
|
+
{
|
|
2293
|
+
from: "DenseMatrix",
|
|
2294
|
+
to: "SparseMatrix",
|
|
2295
|
+
convert: (m) => {
|
|
2296
|
+
return { ...m, type: "SparseMatrix" };
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
];
|
|
2300
|
+
function createMathTSTyped() {
|
|
2301
|
+
const instance = create();
|
|
2302
|
+
if (typeof instance.addType === "function") {
|
|
2303
|
+
for (const typeDef of MATHTS_TYPES) {
|
|
2304
|
+
instance.addType(typeDef);
|
|
2305
|
+
}
|
|
2306
|
+
} else {
|
|
2307
|
+
instance.addTypes(MATHTS_TYPES, "any");
|
|
2308
|
+
}
|
|
2309
|
+
instance.addConversions(MATHTS_CONVERSIONS);
|
|
2310
|
+
return instance;
|
|
2311
|
+
}
|
|
2312
|
+
var mathTyped = createMathTSTyped();
|
|
2313
|
+
var TypeRegistry = class {
|
|
2314
|
+
types = /* @__PURE__ */ new Map();
|
|
2315
|
+
conversions = /* @__PURE__ */ new Map();
|
|
2316
|
+
instance = null;
|
|
2317
|
+
/**
|
|
2318
|
+
* Register a new type
|
|
2319
|
+
*/
|
|
2320
|
+
registerType(name, test) {
|
|
2321
|
+
this.types.set(name, { name, test });
|
|
2322
|
+
this.instance = null;
|
|
2323
|
+
return this;
|
|
2324
|
+
}
|
|
2325
|
+
/**
|
|
2326
|
+
* Register a type conversion
|
|
2327
|
+
*/
|
|
2328
|
+
registerConversion(from, to, convert) {
|
|
2329
|
+
const key = `${from}->${to}`;
|
|
2330
|
+
this.conversions.set(key, {
|
|
2331
|
+
from,
|
|
2332
|
+
to,
|
|
2333
|
+
convert
|
|
2334
|
+
});
|
|
2335
|
+
this.instance = null;
|
|
2336
|
+
return this;
|
|
2337
|
+
}
|
|
2338
|
+
/**
|
|
2339
|
+
* Check if a type is registered
|
|
2340
|
+
*/
|
|
2341
|
+
hasType(name) {
|
|
2342
|
+
return this.types.has(name);
|
|
2343
|
+
}
|
|
2344
|
+
/**
|
|
2345
|
+
* Check if a conversion is registered
|
|
2346
|
+
*/
|
|
2347
|
+
hasConversion(from, to) {
|
|
2348
|
+
return this.conversions.has(`${from}->${to}`);
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* Get all registered type names
|
|
2352
|
+
*/
|
|
2353
|
+
getTypeNames() {
|
|
2354
|
+
return Array.from(this.types.keys());
|
|
2355
|
+
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Build a typed-function instance from the registry
|
|
2358
|
+
*/
|
|
2359
|
+
build() {
|
|
2360
|
+
if (!this.instance) {
|
|
2361
|
+
const inst = create();
|
|
2362
|
+
inst.addTypes(Array.from(this.types.values()), "any");
|
|
2363
|
+
inst.addConversions(Array.from(this.conversions.values()));
|
|
2364
|
+
this.instance = inst;
|
|
2365
|
+
}
|
|
2366
|
+
return this.instance;
|
|
2367
|
+
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Clear all registered types and conversions
|
|
2370
|
+
*/
|
|
2371
|
+
clear() {
|
|
2372
|
+
this.types.clear();
|
|
2373
|
+
this.conversions.clear();
|
|
2374
|
+
this.instance = null;
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
function createTypedFunction(name, signatures, typedInstance = mathTyped) {
|
|
2378
|
+
return typedInstance(name, signatures);
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
// src/typed/type-bridge.ts
|
|
2382
|
+
var registered = false;
|
|
2383
|
+
function registerNativeTypes() {
|
|
2384
|
+
if (registered) return;
|
|
2385
|
+
registered = true;
|
|
2386
|
+
if (!("isComplex" in Complex.prototype)) {
|
|
2387
|
+
Object.defineProperty(Complex.prototype, "isComplex", {
|
|
2388
|
+
value: true,
|
|
2389
|
+
writable: false,
|
|
2390
|
+
enumerable: false,
|
|
2391
|
+
configurable: false
|
|
2392
|
+
});
|
|
2393
|
+
}
|
|
2394
|
+
if (!("type" in Complex.prototype)) {
|
|
2395
|
+
Object.defineProperty(Complex.prototype, "type", {
|
|
2396
|
+
value: "Complex",
|
|
2397
|
+
writable: false,
|
|
2398
|
+
enumerable: false,
|
|
2399
|
+
configurable: false
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
if (!("isFraction" in Fraction.prototype)) {
|
|
2403
|
+
Object.defineProperty(Fraction.prototype, "isFraction", {
|
|
2404
|
+
value: true,
|
|
2405
|
+
writable: false,
|
|
2406
|
+
enumerable: false,
|
|
2407
|
+
configurable: false
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
if (!("type" in Fraction.prototype)) {
|
|
2411
|
+
Object.defineProperty(Fraction.prototype, "type", {
|
|
2412
|
+
value: "Fraction",
|
|
2413
|
+
writable: false,
|
|
2414
|
+
enumerable: false,
|
|
2415
|
+
configurable: false
|
|
2416
|
+
});
|
|
2417
|
+
}
|
|
2418
|
+
if (!("isBigNumber" in BigNumber.prototype)) {
|
|
2419
|
+
Object.defineProperty(BigNumber.prototype, "isBigNumber", {
|
|
2420
|
+
value: true,
|
|
2421
|
+
writable: false,
|
|
2422
|
+
enumerable: false,
|
|
2423
|
+
configurable: false
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
if (!("type" in BigNumber.prototype)) {
|
|
2427
|
+
Object.defineProperty(BigNumber.prototype, "type", {
|
|
2428
|
+
value: "BigNumber",
|
|
2429
|
+
writable: false,
|
|
2430
|
+
enumerable: false,
|
|
2431
|
+
configurable: false
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
// src/factory/factory.ts
|
|
2437
|
+
var DEFAULT_CONFIG = {
|
|
2438
|
+
precision: 64,
|
|
2439
|
+
matrix: "Matrix",
|
|
2440
|
+
number: "number",
|
|
2441
|
+
randomSeed: null,
|
|
2442
|
+
epsilon: 1e-12,
|
|
2443
|
+
preferredBackend: "auto",
|
|
2444
|
+
wasmThreshold: 1e3,
|
|
2445
|
+
gpuThreshold: 1e5,
|
|
2446
|
+
parallelEnabled: true,
|
|
2447
|
+
parallelThreshold: 5e4
|
|
2448
|
+
};
|
|
2449
|
+
var FunctionRegistry = class {
|
|
2450
|
+
factories = /* @__PURE__ */ new Map();
|
|
2451
|
+
instances = /* @__PURE__ */ new Map();
|
|
2452
|
+
dependencies;
|
|
2453
|
+
creating = /* @__PURE__ */ new Set();
|
|
2454
|
+
constructor(config = {}, typed2 = mathTyped) {
|
|
2455
|
+
this.dependencies = {
|
|
2456
|
+
config: { ...DEFAULT_CONFIG, ...config },
|
|
2457
|
+
typed: typed2
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Register a factory function
|
|
2462
|
+
*/
|
|
2463
|
+
register(factory) {
|
|
2464
|
+
this.factories.set(factory.name, factory);
|
|
2465
|
+
}
|
|
2466
|
+
/**
|
|
2467
|
+
* Register multiple factory functions
|
|
2468
|
+
*/
|
|
2469
|
+
registerAll(factories) {
|
|
2470
|
+
for (const factory of factories) {
|
|
2471
|
+
this.register(factory);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
/**
|
|
2475
|
+
* Get or create a function by name
|
|
2476
|
+
*/
|
|
2477
|
+
get(name) {
|
|
2478
|
+
const existing = this.instances.get(name);
|
|
2479
|
+
if (existing) return existing;
|
|
2480
|
+
if (this.creating.has(name)) {
|
|
2481
|
+
throw new Error(`Circular dependency detected: ${name}`);
|
|
2482
|
+
}
|
|
2483
|
+
const factory = this.factories.get(name);
|
|
2484
|
+
if (!factory) {
|
|
2485
|
+
throw new Error(`Unknown function: ${name}`);
|
|
2486
|
+
}
|
|
2487
|
+
this.creating.add(name);
|
|
2488
|
+
try {
|
|
2489
|
+
const deps = { ...this.dependencies };
|
|
2490
|
+
for (const depName of factory.dependencies) {
|
|
2491
|
+
if (depName === "config" || depName === "typed") continue;
|
|
2492
|
+
deps[depName] = this.get(depName);
|
|
2493
|
+
}
|
|
2494
|
+
const fn = factory.factory(deps);
|
|
2495
|
+
this.instances.set(name, fn);
|
|
2496
|
+
this.dependencies[name] = fn;
|
|
2497
|
+
return fn;
|
|
2498
|
+
} finally {
|
|
2499
|
+
this.creating.delete(name);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
/**
|
|
2503
|
+
* Check if a function is registered
|
|
2504
|
+
*/
|
|
2505
|
+
has(name) {
|
|
2506
|
+
return this.factories.has(name);
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Get all registered function names
|
|
2510
|
+
*/
|
|
2511
|
+
names() {
|
|
2512
|
+
return Array.from(this.factories.keys());
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Update configuration
|
|
2516
|
+
*/
|
|
2517
|
+
updateConfig(config) {
|
|
2518
|
+
this.dependencies.config = { ...this.dependencies.config, ...config };
|
|
2519
|
+
this.instances.clear();
|
|
2520
|
+
}
|
|
2521
|
+
/**
|
|
2522
|
+
* Get current configuration
|
|
2523
|
+
*/
|
|
2524
|
+
getConfig() {
|
|
2525
|
+
return { ...this.dependencies.config };
|
|
2526
|
+
}
|
|
2527
|
+
};
|
|
2528
|
+
function createFactory(name, dependencies, factory) {
|
|
2529
|
+
return { name, dependencies, factory };
|
|
2530
|
+
}
|
|
2531
|
+
var registry = new FunctionRegistry();
|
|
2532
|
+
var math = {
|
|
2533
|
+
/**
|
|
2534
|
+
* Get a registered function
|
|
2535
|
+
*/
|
|
2536
|
+
get: (name) => registry.get(name),
|
|
2537
|
+
/**
|
|
2538
|
+
* Register a factory function
|
|
2539
|
+
*/
|
|
2540
|
+
register: (factory) => registry.register(factory),
|
|
2541
|
+
/**
|
|
2542
|
+
* Get configuration
|
|
2543
|
+
*/
|
|
2544
|
+
config: () => registry.getConfig(),
|
|
2545
|
+
/**
|
|
2546
|
+
* Update configuration
|
|
2547
|
+
*/
|
|
2548
|
+
configure: (config) => registry.updateConfig(config)
|
|
2549
|
+
};
|
|
2550
|
+
|
|
2551
|
+
// src/index.ts
|
|
2552
|
+
var VERSION = "0.1.0";
|
|
2553
|
+
export {
|
|
2554
|
+
BIGNUMBER_E,
|
|
2555
|
+
BIGNUMBER_LN10,
|
|
2556
|
+
BIGNUMBER_LN2,
|
|
2557
|
+
BIGNUMBER_NEG_ONE,
|
|
2558
|
+
BIGNUMBER_ONE,
|
|
2559
|
+
BIGNUMBER_PI,
|
|
2560
|
+
BIGNUMBER_TEN,
|
|
2561
|
+
BIGNUMBER_ZERO,
|
|
2562
|
+
BigNumber,
|
|
2563
|
+
COMPLEX_NEG_ONE,
|
|
2564
|
+
COMPLEX_ONE,
|
|
2565
|
+
COMPLEX_ZERO,
|
|
2566
|
+
Complex,
|
|
2567
|
+
DEFAULT_CONFIG,
|
|
2568
|
+
FRACTION_HALF,
|
|
2569
|
+
FRACTION_NEG_ONE,
|
|
2570
|
+
FRACTION_ONE,
|
|
2571
|
+
FRACTION_QUARTER,
|
|
2572
|
+
FRACTION_THIRD,
|
|
2573
|
+
FRACTION_ZERO,
|
|
2574
|
+
Fraction,
|
|
2575
|
+
FunctionRegistry,
|
|
2576
|
+
I,
|
|
2577
|
+
MATHTS_CONVERSIONS,
|
|
2578
|
+
MATHTS_TYPES,
|
|
2579
|
+
TypeRegistry,
|
|
2580
|
+
VERSION,
|
|
2581
|
+
create,
|
|
2582
|
+
createFactory,
|
|
2583
|
+
createMathTSTyped,
|
|
2584
|
+
createTypedFunction,
|
|
2585
|
+
initTypedWasm,
|
|
2586
|
+
isArray,
|
|
2587
|
+
isBigInt,
|
|
2588
|
+
isBigNumber,
|
|
2589
|
+
isBoolean,
|
|
2590
|
+
isComplex,
|
|
2591
|
+
isDenseMatrix,
|
|
2592
|
+
isFraction,
|
|
2593
|
+
isFunction,
|
|
2594
|
+
isMatrix,
|
|
2595
|
+
isNull,
|
|
2596
|
+
isNumber,
|
|
2597
|
+
isObject,
|
|
2598
|
+
isSparseMatrix,
|
|
2599
|
+
isString,
|
|
2600
|
+
isTypedWasmAvailable,
|
|
2601
|
+
isUndefined,
|
|
2602
|
+
isUnit,
|
|
2603
|
+
math,
|
|
2604
|
+
mathTyped,
|
|
2605
|
+
registerNativeTypes,
|
|
2606
|
+
registry,
|
|
2607
|
+
typed
|
|
2608
|
+
};
|