picocalc 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +355 -282
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -44,15 +44,9 @@ var InterpreterRangeError = class extends InterpreterError {
|
|
|
44
44
|
super(message);
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
|
-
var MismatchedParenthesisError = class extends InterpreterError {
|
|
48
|
-
constructor(pos, message = "Mismatched parenthesis") {
|
|
49
|
-
super(message, pos);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
// src/lib/options.ts
|
|
53
47
|
const ROUNDING_MODE = "round";
|
|
54
|
-
function
|
|
55
|
-
return
|
|
48
|
+
function getBitPrecision(maxDecimals = 30) {
|
|
49
|
+
return BigInt(maxDecimals * 4 + 32);
|
|
56
50
|
}
|
|
57
51
|
/**
|
|
58
52
|
* Maximum allowed precision
|
|
@@ -77,7 +71,7 @@ function splitSeries(a, b) {
|
|
|
77
71
|
function computeE(maxDecimals) {
|
|
78
72
|
let b = 1n;
|
|
79
73
|
let m = 1n;
|
|
80
|
-
const t =
|
|
74
|
+
const t = 1n << getBitPrecision(maxDecimals);
|
|
81
75
|
while (m < t) {
|
|
82
76
|
b++;
|
|
83
77
|
m *= b;
|
|
@@ -106,7 +100,7 @@ function gcd(a, b) {
|
|
|
106
100
|
return a;
|
|
107
101
|
}
|
|
108
102
|
// src/lib/utils/multiply.ts
|
|
109
|
-
function multiply(a, b, maxDecimals
|
|
103
|
+
function multiply(a, b, maxDecimals) {
|
|
110
104
|
const aN = a.n;
|
|
111
105
|
const bN = b.n;
|
|
112
106
|
if (aN === 0n || bN === 0n) return ZERO;
|
|
@@ -163,43 +157,41 @@ function iNthRoot(value, n) {
|
|
|
163
157
|
/**
|
|
164
158
|
* Calculates the n-th root of a fraction.
|
|
165
159
|
*/
|
|
166
|
-
function nthRoot(v, n,
|
|
160
|
+
function nthRoot(v, n, maxDecimals) {
|
|
167
161
|
if (n === 0n) throw new DivisionByZeroError();
|
|
168
162
|
if (n === 1n) return v;
|
|
169
163
|
if (v.n < 0) {
|
|
170
164
|
if (n % 2n === 0n) throw new NotImplementedError(`Even (${n}th) root of negative numbers is not implemented yet.`);
|
|
171
|
-
const
|
|
165
|
+
const r = nthRoot({
|
|
172
166
|
n: -v.n,
|
|
173
167
|
d: v.d
|
|
174
|
-
}, n,
|
|
168
|
+
}, n, maxDecimals);
|
|
175
169
|
return {
|
|
176
|
-
n: -
|
|
177
|
-
d:
|
|
170
|
+
n: -r.n,
|
|
171
|
+
d: r.d
|
|
178
172
|
};
|
|
179
173
|
}
|
|
180
174
|
if (v.n === 0n) return ZERO;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
});
|
|
195
|
-
}
|
|
175
|
+
const rootN = iNthRoot(v.n, n);
|
|
176
|
+
const rootD = iNthRoot(v.d, n);
|
|
177
|
+
if (rootN ** n === v.n && rootD ** n === v.d) {
|
|
178
|
+
const e = simplify({
|
|
179
|
+
n: v.e?.n ?? 1n,
|
|
180
|
+
d: (v.e?.d ?? 1n) * n
|
|
181
|
+
});
|
|
182
|
+
return simplify({
|
|
183
|
+
n: rootN,
|
|
184
|
+
d: rootD,
|
|
185
|
+
c: v.c,
|
|
186
|
+
e
|
|
187
|
+
});
|
|
196
188
|
}
|
|
197
|
-
const
|
|
198
|
-
const scaleFactor =
|
|
189
|
+
const precisionBits = getBitPrecision(maxDecimals);
|
|
190
|
+
const scaleFactor = 1n << precisionBits * n;
|
|
199
191
|
const s = toSimpleFraction(v);
|
|
200
192
|
return simplify({
|
|
201
193
|
n: iNthRoot(s.n * scaleFactor / s.d, n),
|
|
202
|
-
d:
|
|
194
|
+
d: 1n << precisionBits
|
|
203
195
|
});
|
|
204
196
|
}
|
|
205
197
|
// src/lib/utils/simplify.ts
|
|
@@ -234,12 +226,12 @@ function simplify(v) {
|
|
|
234
226
|
/**
|
|
235
227
|
* Resolves any constants and exponents to return a simple fraction.
|
|
236
228
|
*/
|
|
237
|
-
function toSimpleFraction(val, maxDecimals
|
|
229
|
+
function toSimpleFraction(val, maxDecimals) {
|
|
238
230
|
if (!val.c) return {
|
|
239
231
|
d: val.d,
|
|
240
232
|
n: val.n
|
|
241
233
|
};
|
|
242
|
-
const c = getConst(val.c,
|
|
234
|
+
const c = getConst(val.c, maxDecimals);
|
|
243
235
|
const expN = val.e?.n ?? 1n;
|
|
244
236
|
const expD = val.e?.d ?? 1n;
|
|
245
237
|
const absExpN = expN < 0 ? -expN : expN;
|
|
@@ -247,27 +239,20 @@ function toSimpleFraction(val, maxDecimals = 30) {
|
|
|
247
239
|
n: expN < 0 ? c.d ** absExpN : c.n ** absExpN,
|
|
248
240
|
d: expN < 0 ? c.n ** absExpN : c.d ** absExpN
|
|
249
241
|
};
|
|
250
|
-
if (expD !== 1n) poweredConstant = nthRoot(poweredConstant, expD
|
|
242
|
+
if (expD !== 1n) poweredConstant = nthRoot(poweredConstant, expD);
|
|
251
243
|
return multiply(poweredConstant, {
|
|
252
244
|
n: val.n,
|
|
253
245
|
d: val.d
|
|
254
246
|
}, maxDecimals);
|
|
255
247
|
}
|
|
256
248
|
// src/lib/utils/arctan.ts
|
|
257
|
-
function rawArctanSeries(
|
|
258
|
-
const
|
|
259
|
-
const SCALE = 10n ** BigInt(precisionDigits);
|
|
260
|
-
const xScaled = absN * SCALE / absD;
|
|
261
|
-
if (xScaled === 0n) return {
|
|
262
|
-
n: 0n,
|
|
263
|
-
d: SCALE
|
|
264
|
-
};
|
|
265
|
-
const xSqScaled = xScaled * xScaled / SCALE;
|
|
249
|
+
function rawArctanSeries(xScaled, bitPrecision) {
|
|
250
|
+
const xSqScaled = xScaled * xScaled >> bitPrecision;
|
|
266
251
|
let currentTerm = xScaled;
|
|
267
252
|
let totalSum = xScaled;
|
|
268
253
|
let k = 1n;
|
|
269
254
|
while (true) {
|
|
270
|
-
currentTerm = currentTerm * xSqScaled
|
|
255
|
+
currentTerm = currentTerm * xSqScaled >> bitPrecision;
|
|
271
256
|
const denominatorFactor = 2n * k + 1n;
|
|
272
257
|
const termValue = currentTerm / denominatorFactor;
|
|
273
258
|
if (termValue === 0n) break;
|
|
@@ -275,32 +260,26 @@ function rawArctanSeries(absN, absD, precision) {
|
|
|
275
260
|
else totalSum += termValue;
|
|
276
261
|
k++;
|
|
277
262
|
}
|
|
278
|
-
return
|
|
279
|
-
n: totalSum,
|
|
280
|
-
d: SCALE
|
|
281
|
-
};
|
|
263
|
+
return totalSum;
|
|
282
264
|
}
|
|
283
|
-
function arctan(v,
|
|
265
|
+
function arctan(v, maxDecimals) {
|
|
284
266
|
const { n, d } = v;
|
|
285
267
|
if (n === 0n) return ZERO;
|
|
268
|
+
const bitPrecision = getBitPrecision(maxDecimals);
|
|
286
269
|
const isNegative = n < 0n !== d < 0n;
|
|
287
270
|
const absN = n < 0n ? -n : n;
|
|
288
271
|
const absD = d < 0n ? -d : d;
|
|
289
|
-
if (absN === absD) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
n,
|
|
295
|
-
d: pi.d * 4n
|
|
296
|
-
});
|
|
297
|
-
}
|
|
272
|
+
if (absN === absD) return {
|
|
273
|
+
c: "pi",
|
|
274
|
+
n: isNegative ? -1n : 1n,
|
|
275
|
+
d: 4n
|
|
276
|
+
};
|
|
298
277
|
if (absN > absD) {
|
|
299
|
-
const pi = computePi(
|
|
278
|
+
const pi = computePi(maxDecimals);
|
|
300
279
|
const subArctan = arctan({
|
|
301
280
|
n: absD,
|
|
302
281
|
d: absN
|
|
303
|
-
},
|
|
282
|
+
}, maxDecimals);
|
|
304
283
|
const resultNum = pi.n * subArctan.d - 2n * subArctan.n * pi.d;
|
|
305
284
|
const resultDen = 2n * pi.d * subArctan.d;
|
|
306
285
|
return simplify({
|
|
@@ -312,11 +291,11 @@ function arctan(v, precision) {
|
|
|
312
291
|
const halfArctan = arctan({
|
|
313
292
|
n: 1n,
|
|
314
293
|
d: 2n
|
|
315
|
-
},
|
|
294
|
+
}, maxDecimals);
|
|
316
295
|
const remainderArctan = arctan({
|
|
317
296
|
n: 2n * absN - absD,
|
|
318
297
|
d: 2n * absD + absN
|
|
319
|
-
},
|
|
298
|
+
}, maxDecimals);
|
|
320
299
|
const resultNum = halfArctan.n * remainderArctan.d + remainderArctan.n * halfArctan.d;
|
|
321
300
|
const resultDen = halfArctan.d * remainderArctan.d;
|
|
322
301
|
return simplify({
|
|
@@ -324,22 +303,22 @@ function arctan(v, precision) {
|
|
|
324
303
|
d: resultDen
|
|
325
304
|
});
|
|
326
305
|
}
|
|
327
|
-
const r = rawArctanSeries(absN
|
|
306
|
+
const r = rawArctanSeries((absN << bitPrecision) / absD, bitPrecision);
|
|
328
307
|
return simplify({
|
|
329
|
-
n: isNegative ? -r
|
|
330
|
-
d:
|
|
308
|
+
n: isNegative ? -r : r,
|
|
309
|
+
d: 1n << bitPrecision
|
|
331
310
|
});
|
|
332
311
|
}
|
|
333
312
|
// src/lib/utils/pi.ts
|
|
334
|
-
function computePi(
|
|
313
|
+
function computePi(maxDecimals) {
|
|
335
314
|
const p5 = arctan({
|
|
336
315
|
n: 1n,
|
|
337
316
|
d: 5n
|
|
338
|
-
},
|
|
317
|
+
}, maxDecimals);
|
|
339
318
|
const p239 = arctan({
|
|
340
319
|
n: 1n,
|
|
341
320
|
d: 239n
|
|
342
|
-
},
|
|
321
|
+
}, maxDecimals);
|
|
343
322
|
return simplify({
|
|
344
323
|
n: 16n * p5.n * p239.d - 4n * p239.n * p5.d,
|
|
345
324
|
d: p5.d * p239.d
|
|
@@ -354,37 +333,29 @@ const ONE = {
|
|
|
354
333
|
n: 1n,
|
|
355
334
|
d: 1n
|
|
356
335
|
};
|
|
357
|
-
function getConst(id,
|
|
358
|
-
if (
|
|
359
|
-
|
|
360
|
-
d: 1n,
|
|
361
|
-
c: id
|
|
362
|
-
};
|
|
363
|
-
if (id === "pi") return computePi(options);
|
|
364
|
-
return computeE(options.maxDecimals);
|
|
336
|
+
function getConst(id, maxDecimals) {
|
|
337
|
+
if (id === "pi") return computePi(maxDecimals);
|
|
338
|
+
return computeE(maxDecimals);
|
|
365
339
|
}
|
|
366
340
|
// src/lib/utils/add.ts
|
|
367
|
-
function
|
|
341
|
+
function negate(v) {
|
|
342
|
+
if (v.n === "OVERFLOW") return v;
|
|
343
|
+
const { n, d } = v;
|
|
344
|
+
return {
|
|
345
|
+
...v,
|
|
346
|
+
n: d < 0 ? n : -n,
|
|
347
|
+
d: d < 0 ? -d : d
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function add(left, right, maxDecimals, subtract = false) {
|
|
368
351
|
const lN = left.n;
|
|
369
352
|
const rN = right.n;
|
|
370
|
-
if (lN === "OVERFLOW") return left;
|
|
371
|
-
if (rN === "OVERFLOW") return right;
|
|
353
|
+
if (lN === "OVERFLOW" || rN === 0n) return left;
|
|
354
|
+
if (rN === "OVERFLOW" || lN === 0n) return subtract ? negate(right) : right;
|
|
372
355
|
const { d: lD, c, e } = left;
|
|
373
356
|
const { d: rD, c: rC, e: rE } = right;
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
d: rD,
|
|
377
|
-
c: rC,
|
|
378
|
-
e: rE
|
|
379
|
-
};
|
|
380
|
-
if (rN === 0n) return {
|
|
381
|
-
n: lN,
|
|
382
|
-
d: lD,
|
|
383
|
-
c,
|
|
384
|
-
e
|
|
385
|
-
};
|
|
386
|
-
let n;
|
|
387
|
-
let d;
|
|
357
|
+
if (c !== rC || e?.n !== rE?.n) return add(toSimpleFraction(left, maxDecimals), toSimpleFraction(right, maxDecimals), maxDecimals, subtract);
|
|
358
|
+
let n, d;
|
|
388
359
|
if (lD === rD) {
|
|
389
360
|
n = subtract ? lN - rN : lN + rN;
|
|
390
361
|
d = lD;
|
|
@@ -396,7 +367,10 @@ function add(left, right, maxDecimals = 30, subtract = false) {
|
|
|
396
367
|
d = lD * mLeft;
|
|
397
368
|
}
|
|
398
369
|
if (n === 0n) return ZERO;
|
|
399
|
-
if (
|
|
370
|
+
if (n < 0n && d < 0n) {
|
|
371
|
+
n = -n;
|
|
372
|
+
d = -d;
|
|
373
|
+
}
|
|
400
374
|
return {
|
|
401
375
|
n,
|
|
402
376
|
d,
|
|
@@ -404,102 +378,34 @@ function add(left, right, maxDecimals = 30, subtract = false) {
|
|
|
404
378
|
e
|
|
405
379
|
};
|
|
406
380
|
}
|
|
407
|
-
// src/lib/utils/sqrt.ts
|
|
408
|
-
/**
|
|
409
|
-
* Calculates the integer square root of a BigInt.
|
|
410
|
-
*/
|
|
411
|
-
function isqrt(value) {
|
|
412
|
-
if (value < 0) throw new NotImplementedError("Square root of negative numbers is not implemented yet.");
|
|
413
|
-
if (value < 2n) return value;
|
|
414
|
-
let res = 0n;
|
|
415
|
-
let bit = 1n << (BigInt.bitLength(value) & -2n);
|
|
416
|
-
while (bit !== 0n) {
|
|
417
|
-
if (value >= res + bit) {
|
|
418
|
-
value -= res + bit;
|
|
419
|
-
res = (res >> 1n) + bit;
|
|
420
|
-
} else res >>= 1n;
|
|
421
|
-
bit >>= 2n;
|
|
422
|
-
}
|
|
423
|
-
return res;
|
|
424
|
-
}
|
|
425
|
-
function isPerfectSquare(val) {
|
|
426
|
-
if (val < 0) return [false, 0n];
|
|
427
|
-
const root = isqrt(val);
|
|
428
|
-
return [root * root === val, root];
|
|
429
|
-
}
|
|
430
|
-
function sqrt(v, precision) {
|
|
431
|
-
if (v.n === "OVERFLOW") return v;
|
|
432
|
-
if (v.n < 0) throw new NotImplementedError("Square root of negative numbers is not implemented yet.");
|
|
433
|
-
if (v.n === 0n) return ZERO;
|
|
434
|
-
if (precision.format === "precise") {
|
|
435
|
-
const [nIsSquare, n] = isPerfectSquare(v.n);
|
|
436
|
-
const [dIsSquare, d] = isPerfectSquare(v.d);
|
|
437
|
-
if (nIsSquare && dIsSquare) {
|
|
438
|
-
const e = simplify({
|
|
439
|
-
n: v.e?.n ?? 1n,
|
|
440
|
-
d: (v.e?.d ?? 1n) * 2n
|
|
441
|
-
});
|
|
442
|
-
return simplify({
|
|
443
|
-
n,
|
|
444
|
-
d,
|
|
445
|
-
c: v.c,
|
|
446
|
-
e
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
const precisionDigits = getPrecisionDigits(precision.maxDecimals);
|
|
451
|
-
const scaleFactor = 10n ** BigInt(precisionDigits * 2);
|
|
452
|
-
const s = toSimpleFraction(v);
|
|
453
|
-
return simplify({
|
|
454
|
-
n: isqrt(s.n * scaleFactor / s.d),
|
|
455
|
-
d: 10n ** BigInt(precisionDigits)
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
381
|
// src/lib/utils/arctanh.ts
|
|
459
|
-
function rawArctanhSeries(xScaled,
|
|
382
|
+
function rawArctanhSeries(xScaled, bitPrecision) {
|
|
460
383
|
let currentTerm = xScaled;
|
|
461
384
|
let totalSum = xScaled;
|
|
462
|
-
const xSqScaled = xScaled * xScaled
|
|
385
|
+
const xSqScaled = xScaled * xScaled >> bitPrecision;
|
|
463
386
|
let k = 1n;
|
|
464
387
|
while (true) {
|
|
465
|
-
currentTerm = currentTerm * xSqScaled
|
|
388
|
+
currentTerm = currentTerm * xSqScaled >> bitPrecision;
|
|
466
389
|
const denominatorFactor = 2n * k + 1n;
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
totalSum += termValue;
|
|
390
|
+
if (currentTerm < denominatorFactor) break;
|
|
391
|
+
totalSum += currentTerm / denominatorFactor;
|
|
470
392
|
k++;
|
|
471
393
|
}
|
|
472
394
|
return totalSum;
|
|
473
395
|
}
|
|
474
|
-
function arctanh(v,
|
|
396
|
+
function arctanh(v, maxDecimals) {
|
|
475
397
|
const { n, d } = v;
|
|
476
398
|
if (n === 0n) return ZERO;
|
|
477
|
-
const
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const isNegative = currentN < 0n !== currentD < 0n;
|
|
482
|
-
currentN = currentN < 0n ? -currentN : currentN;
|
|
483
|
-
currentD = currentD < 0n ? -currentD : currentD;
|
|
399
|
+
const bitPrecision = getBitPrecision(maxDecimals);
|
|
400
|
+
const isNegative = n < 0n !== d < 0n;
|
|
401
|
+
const currentN = n < 0n ? -n : n;
|
|
402
|
+
const currentD = d < 0n ? -d : d;
|
|
484
403
|
if (currentN >= currentD) throw new InterpreterRangeError("arctanh argument must be strictly between -1 and 1");
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
let xScaled = currentN * SCALE / currentD;
|
|
488
|
-
while (xScaled > threshold) {
|
|
489
|
-
const sqrtVal = sqrt({
|
|
490
|
-
n: SCALE - xScaled * xScaled / SCALE,
|
|
491
|
-
d: SCALE
|
|
492
|
-
}, precision);
|
|
493
|
-
const denom = SCALE + sqrtVal.n * SCALE / sqrtVal.d;
|
|
494
|
-
xScaled = xScaled * SCALE / denom;
|
|
495
|
-
reductions++;
|
|
496
|
-
}
|
|
497
|
-
let sumScaled = rawArctanhSeries(xScaled, SCALE);
|
|
498
|
-
sumScaled <<= reductions;
|
|
499
|
-
return simplify({
|
|
404
|
+
const sumScaled = rawArctanhSeries((currentN << bitPrecision) / currentD, bitPrecision);
|
|
405
|
+
return {
|
|
500
406
|
n: isNegative ? -sumScaled : sumScaled,
|
|
501
|
-
d:
|
|
502
|
-
}
|
|
407
|
+
d: 1n << bitPrecision
|
|
408
|
+
};
|
|
503
409
|
}
|
|
504
410
|
// src/lib/utils/ceil.ts
|
|
505
411
|
/**
|
|
@@ -514,7 +420,7 @@ function ceil(v) {
|
|
|
514
420
|
return isPositive && hasRemainder ? result + 1n : result;
|
|
515
421
|
}
|
|
516
422
|
// src/lib/utils/divide.ts
|
|
517
|
-
function divide(left, right, maxDecimals
|
|
423
|
+
function divide(left, right, maxDecimals) {
|
|
518
424
|
const lN = left.n;
|
|
519
425
|
const rN = right.n;
|
|
520
426
|
if (rN === 0n) throw new DivisionByZeroError();
|
|
@@ -522,6 +428,7 @@ function divide(left, right, maxDecimals = 30) {
|
|
|
522
428
|
if (lN === "OVERFLOW" || rN === "OVERFLOW") return OverflowValue;
|
|
523
429
|
const { d: lD, c: lC, e: lE } = left;
|
|
524
430
|
const { d: rD, c: rC, e: rE } = right;
|
|
431
|
+
if (lC !== void 0 && rC !== void 0 && lC !== rC) return divide(toSimpleFraction(left, maxDecimals), toSimpleFraction(right, maxDecimals), maxDecimals);
|
|
525
432
|
const g1 = gcd(lN, rN);
|
|
526
433
|
const g2 = gcd(rD, lD);
|
|
527
434
|
const n = lN / g1 * (rD / g2);
|
|
@@ -543,10 +450,7 @@ function divide(left, right, maxDecimals = 30) {
|
|
|
543
450
|
if (lC !== void 0) e = lE ? {
|
|
544
451
|
n: lE.n,
|
|
545
452
|
d: lE.d ?? 1n
|
|
546
|
-
} :
|
|
547
|
-
n: 1n,
|
|
548
|
-
d: 1n
|
|
549
|
-
};
|
|
453
|
+
} : ONE;
|
|
550
454
|
else if (rC !== void 0) e = {
|
|
551
455
|
n: -(rE?.n ?? 1n),
|
|
552
456
|
d: rE?.d ?? 1n
|
|
@@ -558,37 +462,80 @@ function divide(left, right, maxDecimals = 30) {
|
|
|
558
462
|
e
|
|
559
463
|
};
|
|
560
464
|
}
|
|
465
|
+
// src/lib/utils/sqrt.ts
|
|
466
|
+
/**
|
|
467
|
+
* Calculates the integer square root of a BigInt.
|
|
468
|
+
*/
|
|
469
|
+
function isqrt(value) {
|
|
470
|
+
if (value < 0) throw new NotImplementedError("Square root of negative numbers is not implemented yet.");
|
|
471
|
+
if (value < 2n) return value;
|
|
472
|
+
let res = 0n;
|
|
473
|
+
let bit = 1n << (BigInt.bitLength(value) & -2n);
|
|
474
|
+
while (bit !== 0n) {
|
|
475
|
+
if (value >= res + bit) {
|
|
476
|
+
value -= res + bit;
|
|
477
|
+
res = (res >> 1n) + bit;
|
|
478
|
+
} else res >>= 1n;
|
|
479
|
+
bit >>= 2n;
|
|
480
|
+
}
|
|
481
|
+
return res;
|
|
482
|
+
}
|
|
483
|
+
function isPerfectSquare(val) {
|
|
484
|
+
if (val < 0) return [false, 0n];
|
|
485
|
+
const root = isqrt(val);
|
|
486
|
+
return [root * root === val, root];
|
|
487
|
+
}
|
|
488
|
+
function sqrt(v, maxDecimals) {
|
|
489
|
+
if (v.n === "OVERFLOW") return v;
|
|
490
|
+
if (v.n < 0) throw new NotImplementedError("Square root of negative numbers is not implemented yet.");
|
|
491
|
+
if (v.n === 0n) return ZERO;
|
|
492
|
+
const [nIsSquare, n] = isPerfectSquare(v.n);
|
|
493
|
+
const [dIsSquare, d] = isPerfectSquare(v.d);
|
|
494
|
+
if (nIsSquare && dIsSquare) {
|
|
495
|
+
const e = simplify({
|
|
496
|
+
n: v.e?.n ?? 1n,
|
|
497
|
+
d: (v.e?.d ?? 1n) * 2n
|
|
498
|
+
});
|
|
499
|
+
return simplify({
|
|
500
|
+
n,
|
|
501
|
+
d,
|
|
502
|
+
c: v.c,
|
|
503
|
+
e
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
const precisionBits = getBitPrecision(maxDecimals);
|
|
507
|
+
const scaleFactor = 1n << precisionBits * 2n;
|
|
508
|
+
const s = toSimpleFraction(v);
|
|
509
|
+
return {
|
|
510
|
+
n: isqrt(s.n * scaleFactor / s.d),
|
|
511
|
+
d: 1n << precisionBits
|
|
512
|
+
};
|
|
513
|
+
}
|
|
561
514
|
// src/lib/utils/ln.ts
|
|
562
|
-
function ln(v,
|
|
515
|
+
function ln(v, maxDecimals) {
|
|
563
516
|
const { n, d, c, e } = v;
|
|
564
517
|
if (n <= 0n || d <= 0n) throw new InterpreterRangeError("Logarithm of non-positive number");
|
|
565
|
-
if (c === "e") return e ? {
|
|
518
|
+
if (c === "e" && n === d) return e ? {
|
|
566
519
|
n: e.n,
|
|
567
520
|
d: e.d ?? 1n
|
|
568
521
|
} : ONE;
|
|
569
|
-
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
let currentD = d;
|
|
522
|
+
let { n: sN, d: sD } = toSimpleFraction(v);
|
|
523
|
+
const isReciprocal = sN < sD;
|
|
524
|
+
if (isReciprocal) [sN, sD] = [sD, sN];
|
|
573
525
|
let m = 0;
|
|
574
|
-
|
|
575
|
-
if (currentN * SCALE < currentD * SCALE) {
|
|
576
|
-
currentN = d;
|
|
577
|
-
currentD = n;
|
|
578
|
-
}
|
|
579
|
-
while (currentN * SCALE >= 2n * currentD * SCALE) {
|
|
526
|
+
while (sN >= 2n * sD) {
|
|
580
527
|
const val = sqrt({
|
|
581
|
-
n:
|
|
582
|
-
d:
|
|
583
|
-
},
|
|
584
|
-
|
|
585
|
-
|
|
528
|
+
n: sN,
|
|
529
|
+
d: sD
|
|
530
|
+
}, maxDecimals);
|
|
531
|
+
sN = val.n;
|
|
532
|
+
sD = val.d;
|
|
586
533
|
m++;
|
|
587
534
|
}
|
|
588
535
|
const at = arctanh({
|
|
589
|
-
n:
|
|
590
|
-
d:
|
|
591
|
-
},
|
|
536
|
+
n: sN - sD,
|
|
537
|
+
d: sN + sD
|
|
538
|
+
}, maxDecimals);
|
|
592
539
|
let rN = at.n * 2n;
|
|
593
540
|
if (m > 0) rN <<= BigInt(m);
|
|
594
541
|
if (isReciprocal) rN = -rN;
|
|
@@ -598,29 +545,28 @@ function ln(v, precision) {
|
|
|
598
545
|
});
|
|
599
546
|
}
|
|
600
547
|
// src/lib/utils/exp.ts
|
|
601
|
-
function rawExp(v,
|
|
548
|
+
function rawExp(v, maxDecimals) {
|
|
602
549
|
const { n, d } = v;
|
|
603
550
|
if (n === 0n) return ONE;
|
|
604
|
-
const
|
|
605
|
-
const
|
|
606
|
-
const xScaled = n * SCALE / d;
|
|
551
|
+
const scale = 1n << getBitPrecision(maxDecimals);
|
|
552
|
+
const xScaled = n * scale / d;
|
|
607
553
|
const ln2Val = ln({
|
|
608
554
|
n: 2n,
|
|
609
555
|
d: 1n
|
|
610
|
-
},
|
|
611
|
-
const ln2Scaled = ln2Val.n *
|
|
556
|
+
}, maxDecimals);
|
|
557
|
+
const ln2Scaled = ln2Val.n * scale / ln2Val.d;
|
|
612
558
|
let k;
|
|
613
559
|
if (xScaled >= 0n) k = (xScaled + ln2Scaled / 2n) / ln2Scaled;
|
|
614
560
|
else k = (xScaled - ln2Scaled / 2n) / ln2Scaled;
|
|
615
561
|
const rScaled = xScaled - k * ln2Scaled;
|
|
616
562
|
const isNegativeR = rScaled < 0n;
|
|
617
563
|
const absRScaled = isNegativeR ? -rScaled : rScaled;
|
|
618
|
-
let sum =
|
|
619
|
-
let currentTerm =
|
|
564
|
+
let sum = scale;
|
|
565
|
+
let currentTerm = scale;
|
|
620
566
|
let factorial = 1n;
|
|
621
567
|
let i = 1n;
|
|
622
568
|
while (true) {
|
|
623
|
-
currentTerm = currentTerm * absRScaled /
|
|
569
|
+
currentTerm = currentTerm * absRScaled / scale;
|
|
624
570
|
if (currentTerm === 0n) break;
|
|
625
571
|
factorial *= i;
|
|
626
572
|
const termVal = currentTerm / factorial;
|
|
@@ -630,7 +576,7 @@ function rawExp(v, precision) {
|
|
|
630
576
|
i += 1n;
|
|
631
577
|
}
|
|
632
578
|
let finalNum = sum;
|
|
633
|
-
let finalDen =
|
|
579
|
+
let finalDen = scale;
|
|
634
580
|
if (k > 0n) finalNum <<= k;
|
|
635
581
|
else if (k < 0n) finalDen <<= -k;
|
|
636
582
|
return {
|
|
@@ -638,7 +584,7 @@ function rawExp(v, precision) {
|
|
|
638
584
|
d: finalDen
|
|
639
585
|
};
|
|
640
586
|
}
|
|
641
|
-
function exp(v,
|
|
587
|
+
function exp(v, maxDecimals) {
|
|
642
588
|
const { n, d, c } = v;
|
|
643
589
|
if (n === 0n) return ONE;
|
|
644
590
|
if (!c) return simplify({
|
|
@@ -650,14 +596,9 @@ function exp(v, precision) {
|
|
|
650
596
|
d
|
|
651
597
|
}
|
|
652
598
|
});
|
|
653
|
-
return rawExp(toSimpleFraction(v,
|
|
599
|
+
return rawExp(toSimpleFraction(v, maxDecimals), maxDecimals);
|
|
654
600
|
}
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* Maximum digits allowed for the result of exponentiation
|
|
658
|
-
*/
|
|
659
|
-
const MAX_EXPONENT_RESULT_DIGITS = 10000000n;
|
|
660
|
-
function exponentiate(left, right, precision) {
|
|
601
|
+
function exponentiate(left, right, maxDecimals) {
|
|
661
602
|
const rN = right.n;
|
|
662
603
|
if (rN === 0n) return ONE;
|
|
663
604
|
const lN = left.n;
|
|
@@ -673,27 +614,29 @@ function exponentiate(left, right, precision) {
|
|
|
673
614
|
};
|
|
674
615
|
return ONE;
|
|
675
616
|
}
|
|
676
|
-
const normalizedExp = toSimpleFraction(rS,
|
|
617
|
+
const normalizedExp = toSimpleFraction(rS, maxDecimals);
|
|
677
618
|
const dExp = normalizedExp.d;
|
|
678
619
|
let exponent = normalizedExp.n;
|
|
679
620
|
if (lN === 0n) {
|
|
680
621
|
if (exponent < 0) throw new DivisionByZeroError();
|
|
681
622
|
return ZERO;
|
|
682
623
|
}
|
|
683
|
-
if (dExp >= 100) {
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
}
|
|
624
|
+
if ((dExp >= 100 || lD > 1e3) && (lN !== 1n || rS.c)) {
|
|
625
|
+
const isNegativeBase = lN < 0;
|
|
626
|
+
if (isNegativeBase && dExp % 2n === 0n) throw new NotImplementedError(`Even (${dExp}th) root of negative numbers is not implemented yet.`);
|
|
627
|
+
const l = toSimpleFraction(isNegativeBase ? negate(left) : left, maxDecimals);
|
|
628
|
+
const r = toSimpleFraction(rS, maxDecimals);
|
|
629
|
+
const lnBase = ln(l, maxDecimals);
|
|
630
|
+
const scale = 1n << getBitPrecision(maxDecimals);
|
|
631
|
+
const p = lnBase.n * scale / lnBase.d * (r.n * scale / r.d) / scale;
|
|
632
|
+
const pAbs = p < 0 ? -p : p;
|
|
633
|
+
if (scale > pAbs * 10000000n || pAbs > scale * 10000000n) return OverflowValue;
|
|
634
|
+
const result = rawExp({
|
|
635
|
+
n: p,
|
|
636
|
+
d: scale
|
|
637
|
+
}, maxDecimals);
|
|
638
|
+
if (isNegativeBase && normalizedExp.n % 2n !== 0n) return negate(result);
|
|
639
|
+
return result;
|
|
697
640
|
}
|
|
698
641
|
const eN = (left.e?.n ?? 1n) * exponent;
|
|
699
642
|
let baseN = lN;
|
|
@@ -704,7 +647,7 @@ function exponentiate(left, right, precision) {
|
|
|
704
647
|
}
|
|
705
648
|
const baseNDigits = BigInt.bitLength(baseN);
|
|
706
649
|
const baseDDigits = BigInt.bitLength(baseD);
|
|
707
|
-
if (baseNDigits * exponent >
|
|
650
|
+
if (baseNDigits * exponent > 10000000n || baseDDigits * exponent > 10000000n || (baseNDigits > 5e3 || baseDDigits > 5e3) && exponent > 10) return OverflowValue;
|
|
708
651
|
const e = c ? simplify({
|
|
709
652
|
n: eN,
|
|
710
653
|
d: left.e?.d ?? 1n
|
|
@@ -722,8 +665,8 @@ function exponentiate(left, right, precision) {
|
|
|
722
665
|
e
|
|
723
666
|
};
|
|
724
667
|
if (dExp === 1n) return v;
|
|
725
|
-
if (dExp === 2n) return sqrt(v,
|
|
726
|
-
return nthRoot(v, dExp,
|
|
668
|
+
if (dExp === 2n) return sqrt(v, maxDecimals);
|
|
669
|
+
return nthRoot(v, dExp, maxDecimals);
|
|
727
670
|
}
|
|
728
671
|
// src/lib/utils/factorial.ts
|
|
729
672
|
function binaryProduct(arr, low, high) {
|
|
@@ -791,6 +734,143 @@ function mod(a, b) {
|
|
|
791
734
|
d
|
|
792
735
|
};
|
|
793
736
|
}
|
|
737
|
+
// src/lib/utils/trig.ts
|
|
738
|
+
function roundDiv(numerator, denominator) {
|
|
739
|
+
const twice = numerator * 2n;
|
|
740
|
+
const absTwice = twice < 0n ? -twice : twice;
|
|
741
|
+
const absDenom = denominator < 0n ? -denominator : denominator;
|
|
742
|
+
const quotient = (absTwice + absDenom) / (2n * absDenom);
|
|
743
|
+
return twice < 0n !== denominator < 0n ? -quotient : quotient;
|
|
744
|
+
}
|
|
745
|
+
function rawSinSeries(rScaled, bitPrecision) {
|
|
746
|
+
const rSqScaled = rScaled * rScaled >> bitPrecision;
|
|
747
|
+
let termValue = rScaled;
|
|
748
|
+
let totalSum = rScaled;
|
|
749
|
+
let k = 1n;
|
|
750
|
+
while (true) {
|
|
751
|
+
termValue = (termValue * rSqScaled >> bitPrecision) / (2n * k * (2n * k + 1n));
|
|
752
|
+
if (termValue === 0n) break;
|
|
753
|
+
if (k % 2n === 1n) totalSum -= termValue;
|
|
754
|
+
else totalSum += termValue;
|
|
755
|
+
k++;
|
|
756
|
+
}
|
|
757
|
+
return totalSum;
|
|
758
|
+
}
|
|
759
|
+
function rawCosSeries(rScaled, bitPrecision) {
|
|
760
|
+
const rSqScaled = rScaled * rScaled >> bitPrecision;
|
|
761
|
+
const scale = 1n << bitPrecision;
|
|
762
|
+
let termValue = scale;
|
|
763
|
+
let totalSum = scale;
|
|
764
|
+
let k = 1n;
|
|
765
|
+
while (true) {
|
|
766
|
+
termValue = (termValue * rSqScaled >> bitPrecision) / ((2n * k - 1n) * (2n * k));
|
|
767
|
+
if (termValue === 0n) break;
|
|
768
|
+
if (k % 2n === 1n) totalSum -= termValue;
|
|
769
|
+
else totalSum += termValue;
|
|
770
|
+
k++;
|
|
771
|
+
}
|
|
772
|
+
return totalSum;
|
|
773
|
+
}
|
|
774
|
+
function getHalfPi(maxDecimals) {
|
|
775
|
+
const { d, n, c } = computePi(maxDecimals);
|
|
776
|
+
return {
|
|
777
|
+
c,
|
|
778
|
+
n,
|
|
779
|
+
d: d * 2n
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
function sin(v, maxDecimals) {
|
|
783
|
+
const { n, d, c, e } = v;
|
|
784
|
+
if (n === 0n) return ZERO;
|
|
785
|
+
const bitPrecision = getBitPrecision(maxDecimals);
|
|
786
|
+
const scale = 1n << bitPrecision;
|
|
787
|
+
const isPiLinear = c === "pi" && (e === void 0 || e.n === 1n);
|
|
788
|
+
let rScaled;
|
|
789
|
+
let k;
|
|
790
|
+
if (isPiLinear) {
|
|
791
|
+
k = roundDiv(2n * n, d);
|
|
792
|
+
const rN = 2n * n - k * d;
|
|
793
|
+
if (rN === 0n) {
|
|
794
|
+
const quadrant = (k % 4n + 4n) % 4n;
|
|
795
|
+
if (quadrant === 0n || quadrant === 2n) return ZERO;
|
|
796
|
+
if (quadrant === 1n) return ONE;
|
|
797
|
+
return {
|
|
798
|
+
n: -1n,
|
|
799
|
+
d: 1n
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
const piVal = computePi(maxDecimals);
|
|
803
|
+
rScaled = rN * piVal.n * scale / (2n * d * piVal.d);
|
|
804
|
+
} else {
|
|
805
|
+
const simple = toSimpleFraction(v);
|
|
806
|
+
const halfPi = getHalfPi(maxDecimals);
|
|
807
|
+
k = roundDiv(simple.n * halfPi.d, simple.d * halfPi.n);
|
|
808
|
+
const rN = simple.n * halfPi.d - k * halfPi.n * simple.d;
|
|
809
|
+
const rD = simple.d * halfPi.d;
|
|
810
|
+
rScaled = rN * scale / rD;
|
|
811
|
+
}
|
|
812
|
+
const quadrant = (k % 4n + 4n) % 4n;
|
|
813
|
+
let resultScaled;
|
|
814
|
+
let negate = false;
|
|
815
|
+
if (quadrant === 0n) resultScaled = rawSinSeries(rScaled, bitPrecision);
|
|
816
|
+
else if (quadrant === 1n) resultScaled = rawCosSeries(rScaled, bitPrecision);
|
|
817
|
+
else if (quadrant === 2n) {
|
|
818
|
+
resultScaled = rawSinSeries(rScaled, bitPrecision);
|
|
819
|
+
negate = true;
|
|
820
|
+
} else {
|
|
821
|
+
resultScaled = rawCosSeries(rScaled, bitPrecision);
|
|
822
|
+
negate = true;
|
|
823
|
+
}
|
|
824
|
+
return {
|
|
825
|
+
n: negate ? -resultScaled : resultScaled,
|
|
826
|
+
d: scale
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
function cos(v, maxDecimals) {
|
|
830
|
+
const { n, d, c, e } = v;
|
|
831
|
+
if (n === 0n) return ONE;
|
|
832
|
+
const bitPrecision = getBitPrecision(maxDecimals);
|
|
833
|
+
const scale = 1n << bitPrecision;
|
|
834
|
+
const isPiLinear = c === "pi" && (e === void 0 || e.n === 1n);
|
|
835
|
+
let rScaled;
|
|
836
|
+
let k;
|
|
837
|
+
if (isPiLinear) {
|
|
838
|
+
k = roundDiv(2n * n, d);
|
|
839
|
+
const rN = 2n * n - k * d;
|
|
840
|
+
if (rN === 0n) {
|
|
841
|
+
const quadrant = (k % 4n + 4n) % 4n;
|
|
842
|
+
if (quadrant === 0n || quadrant === 2n) return quadrant === 0n ? ONE : {
|
|
843
|
+
n: -1n,
|
|
844
|
+
d: 1n
|
|
845
|
+
};
|
|
846
|
+
return ZERO;
|
|
847
|
+
}
|
|
848
|
+
const piVal = computePi(maxDecimals);
|
|
849
|
+
rScaled = rN * piVal.n * scale / (2n * d * piVal.d);
|
|
850
|
+
} else {
|
|
851
|
+
const simple = toSimpleFraction(v);
|
|
852
|
+
const halfPi = getHalfPi(maxDecimals);
|
|
853
|
+
k = roundDiv(simple.n * halfPi.d, simple.d * halfPi.n);
|
|
854
|
+
const rN = simple.n * halfPi.d - k * halfPi.n * simple.d;
|
|
855
|
+
const rD = simple.d * halfPi.d;
|
|
856
|
+
rScaled = rN * scale / rD;
|
|
857
|
+
}
|
|
858
|
+
const quadrant = (k % 4n + 4n) % 4n;
|
|
859
|
+
let resultScaled;
|
|
860
|
+
let negate = false;
|
|
861
|
+
if (quadrant === 0n) resultScaled = rawCosSeries(rScaled, bitPrecision);
|
|
862
|
+
else if (quadrant === 1n) {
|
|
863
|
+
resultScaled = rawSinSeries(rScaled, bitPrecision);
|
|
864
|
+
negate = true;
|
|
865
|
+
} else if (quadrant === 2n) {
|
|
866
|
+
resultScaled = rawCosSeries(rScaled, bitPrecision);
|
|
867
|
+
negate = true;
|
|
868
|
+
} else resultScaled = rawSinSeries(rScaled, bitPrecision);
|
|
869
|
+
return {
|
|
870
|
+
n: negate ? -resultScaled : resultScaled,
|
|
871
|
+
d: scale
|
|
872
|
+
};
|
|
873
|
+
}
|
|
794
874
|
// src/lib/interpreter.ts
|
|
795
875
|
const precedence = {
|
|
796
876
|
LPAREN: 0,
|
|
@@ -800,12 +880,12 @@ const precedence = {
|
|
|
800
880
|
MULTIPLY: 2,
|
|
801
881
|
DIVIDE: 2,
|
|
802
882
|
MOD: 2,
|
|
803
|
-
UNARY_PLUS:
|
|
804
|
-
UNARY_MINUS:
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
FACTORIAL:
|
|
883
|
+
UNARY_PLUS: 3,
|
|
884
|
+
UNARY_MINUS: 3,
|
|
885
|
+
FN_CALL: 4,
|
|
886
|
+
EXP: 5,
|
|
887
|
+
IMPLICIT_MUL: 5,
|
|
888
|
+
FACTORIAL: 6
|
|
809
889
|
};
|
|
810
890
|
function isFunctionOp(op) {
|
|
811
891
|
return typeof op === "object";
|
|
@@ -814,7 +894,7 @@ function isUnaryOperation(op) {
|
|
|
814
894
|
return op === "UNARY_PLUS" || op === "UNARY_MINUS" || isFunctionOp(op);
|
|
815
895
|
}
|
|
816
896
|
function getOpPrecedence(op) {
|
|
817
|
-
if (
|
|
897
|
+
if (isFunctionOp(op)) return precedence.FN_CALL;
|
|
818
898
|
return precedence[op];
|
|
819
899
|
}
|
|
820
900
|
function evaluate(tokens, options = {}) {
|
|
@@ -827,37 +907,27 @@ function evaluate(tokens, options = {}) {
|
|
|
827
907
|
if (!op || op === "LPAREN" || op === "ABS_OPEN" || op === "UNARY_PLUS") return;
|
|
828
908
|
const right = values.pop();
|
|
829
909
|
if (isUnaryOperation(op)) {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
if (rN === "OVERFLOW") {
|
|
834
|
-
values.push(OverflowValue);
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
values.push({
|
|
838
|
-
...right,
|
|
839
|
-
n: -rN
|
|
840
|
-
});
|
|
841
|
-
return;
|
|
910
|
+
if (op === "UNARY_MINUS") {
|
|
911
|
+
values.push(negate(right));
|
|
912
|
+
return;
|
|
842
913
|
}
|
|
843
914
|
const { id } = op;
|
|
844
915
|
if (id === "sqrt") {
|
|
845
|
-
values.push(sqrt(right,
|
|
916
|
+
values.push(sqrt(right, maxDecimals));
|
|
846
917
|
return;
|
|
847
918
|
}
|
|
848
|
-
|
|
919
|
+
const n = right.n;
|
|
920
|
+
if (n === "OVERFLOW") {
|
|
849
921
|
values.push(OverflowValue);
|
|
850
922
|
return;
|
|
851
923
|
}
|
|
852
924
|
switch (id) {
|
|
853
|
-
case "abs":
|
|
854
|
-
const n = rN < 0 ? -rN : rN;
|
|
925
|
+
case "abs":
|
|
855
926
|
values.push({
|
|
856
927
|
...right,
|
|
857
|
-
n
|
|
928
|
+
n: n < 0 ? -n : n
|
|
858
929
|
});
|
|
859
930
|
return;
|
|
860
|
-
}
|
|
861
931
|
case "ceil":
|
|
862
932
|
values.push({
|
|
863
933
|
n: ceil(toSimpleFraction(right, maxDecimals)),
|
|
@@ -871,16 +941,22 @@ function evaluate(tokens, options = {}) {
|
|
|
871
941
|
});
|
|
872
942
|
return;
|
|
873
943
|
case "arctan":
|
|
874
|
-
values.push(arctan(toSimpleFraction(right, maxDecimals),
|
|
944
|
+
values.push(arctan(toSimpleFraction(right, maxDecimals), maxDecimals));
|
|
875
945
|
return;
|
|
876
946
|
case "arctanh":
|
|
877
|
-
values.push(arctanh(toSimpleFraction(right, maxDecimals),
|
|
947
|
+
values.push(arctanh(toSimpleFraction(right, maxDecimals), maxDecimals));
|
|
878
948
|
return;
|
|
879
949
|
case "ln":
|
|
880
|
-
values.push(ln(right,
|
|
950
|
+
values.push(ln(right, maxDecimals));
|
|
881
951
|
return;
|
|
882
952
|
case "exp":
|
|
883
|
-
values.push(exp(right,
|
|
953
|
+
values.push(exp(right, maxDecimals));
|
|
954
|
+
return;
|
|
955
|
+
case "sin":
|
|
956
|
+
values.push(sin(right, maxDecimals));
|
|
957
|
+
return;
|
|
958
|
+
case "cos":
|
|
959
|
+
values.push(cos(right, maxDecimals));
|
|
884
960
|
return;
|
|
885
961
|
}
|
|
886
962
|
}
|
|
@@ -922,7 +998,7 @@ function evaluate(tokens, options = {}) {
|
|
|
922
998
|
values.push(mod(toSimpleFraction(left), toSimpleFraction(right)));
|
|
923
999
|
return;
|
|
924
1000
|
case "EXP":
|
|
925
|
-
values.push(exponentiate(left, right,
|
|
1001
|
+
values.push(exponentiate(left, right, maxDecimals));
|
|
926
1002
|
return;
|
|
927
1003
|
}
|
|
928
1004
|
};
|
|
@@ -971,15 +1047,10 @@ function evaluate(tokens, options = {}) {
|
|
|
971
1047
|
ops.push(token.type);
|
|
972
1048
|
break;
|
|
973
1049
|
case "RPAREN": {
|
|
974
|
-
let foundMatch = false;
|
|
975
1050
|
while (ops.length > 0) {
|
|
976
|
-
if (ops.at(-1) === "LPAREN")
|
|
977
|
-
foundMatch = true;
|
|
978
|
-
break;
|
|
979
|
-
}
|
|
1051
|
+
if (ops.at(-1) === "LPAREN") break;
|
|
980
1052
|
applyOp(token.pos);
|
|
981
1053
|
}
|
|
982
|
-
if (!foundMatch) throw new MismatchedParenthesisError(token.pos);
|
|
983
1054
|
ops.pop();
|
|
984
1055
|
const nextOp = ops.at(-1);
|
|
985
1056
|
if (!nextOp) break;
|
|
@@ -1178,9 +1249,11 @@ const KNOWN_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
|
1178
1249
|
"arctan",
|
|
1179
1250
|
"arctanh",
|
|
1180
1251
|
"ceil",
|
|
1252
|
+
"cos",
|
|
1181
1253
|
"exp",
|
|
1182
1254
|
"floor",
|
|
1183
1255
|
"ln",
|
|
1256
|
+
"sin",
|
|
1184
1257
|
"sqrt"
|
|
1185
1258
|
]);
|
|
1186
1259
|
function isKnownFunctionName(name) {
|
|
@@ -1236,9 +1309,9 @@ function parse(tokens) {
|
|
|
1236
1309
|
let token = tokens[i];
|
|
1237
1310
|
const prev = tokens[i - 1];
|
|
1238
1311
|
if (token.type === "IDENTIFIER") token = resolveIdentifier(token);
|
|
1239
|
-
const pos = token
|
|
1312
|
+
const { pos, type } = token;
|
|
1240
1313
|
const isPrevOperand = isOperand(result.at(-1));
|
|
1241
|
-
if (
|
|
1314
|
+
if (type === "PIPE") {
|
|
1242
1315
|
if (absStack > 0 && isPrevOperand) {
|
|
1243
1316
|
result.push({
|
|
1244
1317
|
type: "ABS_CLOSE",
|
|
@@ -1258,19 +1331,19 @@ function parse(tokens) {
|
|
|
1258
1331
|
absStack++;
|
|
1259
1332
|
continue;
|
|
1260
1333
|
}
|
|
1261
|
-
if ((
|
|
1334
|
+
if ((type === "LPAREN" || type === "FUNC" || type === "NUMBER" || type === "CONST") && isPrevOperand) result.push({
|
|
1262
1335
|
type: "IMPLICIT_MUL",
|
|
1263
1336
|
pos
|
|
1264
1337
|
});
|
|
1265
1338
|
const prevParsed = result.at(-1);
|
|
1266
1339
|
if (isBinaryOperator(token) && isUnaryContext(prevParsed)) throw new UnexpectedOperatorError(`Unexpected operator '${getSym(token)}'`, token.pos);
|
|
1267
|
-
if ((
|
|
1340
|
+
if ((type === "FACTORIAL" || type === "RPAREN") && isUnaryContext(prevParsed)) {
|
|
1268
1341
|
if (!prevParsed) throw new UnexpectedOperatorError(`Unexpected '${getSym(token)}' at the beginning of expression`, token.pos);
|
|
1269
1342
|
throw new UnexpectedOperatorError(`Unexpected '${getSym(token)}' after '${getSym(prevParsed)}'`, token.pos);
|
|
1270
1343
|
}
|
|
1271
|
-
if (prev && (prev.type === "NUMBER" || prev.type === "IDENTIFIER" && resolveIdentifier(prev).type === "CONST") &&
|
|
1272
|
-
if ((
|
|
1273
|
-
type:
|
|
1344
|
+
if (prev && (prev.type === "NUMBER" || prev.type === "IDENTIFIER" && resolveIdentifier(prev).type === "CONST") && type === "NUMBER") throw new ParserError("Missing operator between numbers", token.pos);
|
|
1345
|
+
if ((type === "PLUS" || type === "MINUS") && isUnaryContext(prevParsed)) result.push({
|
|
1346
|
+
type: type === "PLUS" ? "UNARY_PLUS" : "UNARY_MINUS",
|
|
1274
1347
|
pos
|
|
1275
1348
|
});
|
|
1276
1349
|
else result.push(token);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "picocalc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@gameroman/config": "0.3.0",
|
|
34
34
|
"@types/bun": "1.4.4",
|
|
35
|
-
"oxfmt": "0.
|
|
36
|
-
"oxlint": "1.
|
|
37
|
-
"oxlint-tsgolint": "7.0.
|
|
38
|
-
"tsdown": "0.23.
|
|
35
|
+
"oxfmt": "0.77.0",
|
|
36
|
+
"oxlint": "1.92.0",
|
|
37
|
+
"oxlint-tsgolint": "7.0.2006",
|
|
38
|
+
"tsdown": "0.23.5",
|
|
39
39
|
"typescript": "7.0.2"
|
|
40
40
|
}
|
|
41
41
|
}
|