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.
Files changed (2) hide show
  1. package/dist/index.mjs +355 -282
  2. 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 getPrecisionDigits(maxDecimals) {
55
- return Math.max(10, (maxDecimals ?? 30) + 10);
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 = 10n ** BigInt(getPrecisionDigits(maxDecimals));
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 = 30) {
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, precision) {
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 positiveResult = nthRoot({
165
+ const r = nthRoot({
172
166
  n: -v.n,
173
167
  d: v.d
174
- }, n, precision);
168
+ }, n, maxDecimals);
175
169
  return {
176
- n: -positiveResult.n,
177
- d: positiveResult.d
170
+ n: -r.n,
171
+ d: r.d
178
172
  };
179
173
  }
180
174
  if (v.n === 0n) return ZERO;
181
- if (precision.format === "precise") {
182
- const rootN = iNthRoot(v.n, n);
183
- const rootD = iNthRoot(v.d, n);
184
- if (rootN ** n === v.n && rootD ** n === v.d) {
185
- const e = simplify({
186
- n: v.e?.n ?? 1n,
187
- d: (v.e?.d ?? 1n) * n
188
- });
189
- return simplify({
190
- n: rootN,
191
- d: rootD,
192
- c: v.c,
193
- e
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 precisionDigits = getPrecisionDigits(precision.maxDecimals);
198
- const scaleFactor = 10n ** (BigInt(precisionDigits) * n);
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: 10n ** BigInt(precisionDigits)
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 = 30) {
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, { maxDecimals });
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, { format: "precise" });
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(absN, absD, precision) {
258
- const precisionDigits = getPrecisionDigits(precision.maxDecimals);
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 / SCALE;
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, precision) {
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
- const pi = getConst("pi", precision);
291
- const n = isNegative ? -pi.n : pi.n;
292
- return simplify({
293
- c: pi.c,
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(precision);
278
+ const pi = computePi(maxDecimals);
300
279
  const subArctan = arctan({
301
280
  n: absD,
302
281
  d: absN
303
- }, precision);
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
- }, precision);
294
+ }, maxDecimals);
316
295
  const remainderArctan = arctan({
317
296
  n: 2n * absN - absD,
318
297
  d: 2n * absD + absN
319
- }, precision);
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, absD, precision);
306
+ const r = rawArctanSeries((absN << bitPrecision) / absD, bitPrecision);
328
307
  return simplify({
329
- n: isNegative ? -r.n : r.n,
330
- d: r.d
308
+ n: isNegative ? -r : r,
309
+ d: 1n << bitPrecision
331
310
  });
332
311
  }
333
312
  // src/lib/utils/pi.ts
334
- function computePi(precision) {
313
+ function computePi(maxDecimals) {
335
314
  const p5 = arctan({
336
315
  n: 1n,
337
316
  d: 5n
338
- }, precision);
317
+ }, maxDecimals);
339
318
  const p239 = arctan({
340
319
  n: 1n,
341
320
  d: 239n
342
- }, precision);
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, options) {
358
- if (options.format === "precise") return {
359
- n: 1n,
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 add(left, right, maxDecimals = 30, subtract = false) {
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 (lN === 0n) return {
375
- n: subtract ? -rN : rN,
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 (c !== rC || e?.n !== rE?.n) return add(toSimpleFraction(left, maxDecimals), toSimpleFraction(right, maxDecimals), maxDecimals, subtract);
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, SCALE) {
382
+ function rawArctanhSeries(xScaled, bitPrecision) {
460
383
  let currentTerm = xScaled;
461
384
  let totalSum = xScaled;
462
- const xSqScaled = xScaled * xScaled / SCALE;
385
+ const xSqScaled = xScaled * xScaled >> bitPrecision;
463
386
  let k = 1n;
464
387
  while (true) {
465
- currentTerm = currentTerm * xSqScaled / SCALE;
388
+ currentTerm = currentTerm * xSqScaled >> bitPrecision;
466
389
  const denominatorFactor = 2n * k + 1n;
467
- const termValue = currentTerm / denominatorFactor;
468
- if (termValue === 0n) break;
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, precision) {
396
+ function arctanh(v, maxDecimals) {
475
397
  const { n, d } = v;
476
398
  if (n === 0n) return ZERO;
477
- const precisionDigits = getPrecisionDigits(precision.maxDecimals);
478
- const SCALE = 10n ** BigInt(precisionDigits);
479
- let currentN = n;
480
- let currentD = d;
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
- let reductions = 0n;
486
- const threshold = SCALE / 2n;
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: SCALE
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 = 30) {
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, precision) {
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
- const precisionDigits = getPrecisionDigits(precision.maxDecimals);
570
- const SCALE = 10n ** BigInt(precisionDigits);
571
- let currentN = n;
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
- const isReciprocal = currentN * SCALE < currentD * SCALE;
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: currentN,
582
- d: currentD
583
- }, precision);
584
- currentN = val.n;
585
- currentD = val.d;
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: currentN - currentD,
590
- d: currentN + currentD
591
- }, precision);
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, precision) {
548
+ function rawExp(v, maxDecimals) {
602
549
  const { n, d } = v;
603
550
  if (n === 0n) return ONE;
604
- const precisionDigits = getPrecisionDigits(precision.maxDecimals);
605
- const SCALE = 10n ** BigInt(precisionDigits);
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
- }, precision);
611
- const ln2Scaled = ln2Val.n * SCALE / ln2Val.d;
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 = SCALE;
619
- let currentTerm = SCALE;
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 / SCALE;
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 = SCALE;
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, precision) {
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, getPrecisionDigits(precision.maxDecimals)), precision);
599
+ return rawExp(toSimpleFraction(v, maxDecimals), maxDecimals);
654
600
  }
655
- // src/lib/utils/exponentiate.ts
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, precision.maxDecimals);
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 maxDecimals = getPrecisionDigits(precision.maxDecimals);
685
- const lS = toSimpleFraction(left, maxDecimals);
686
- const rS = toSimpleFraction(right, maxDecimals);
687
- try {
688
- const lnBase = ln(lS, { maxDecimals });
689
- const SCALE = 10n ** BigInt(maxDecimals);
690
- return rawExp({
691
- n: lnBase.n * SCALE / lnBase.d * (rS.n * SCALE / rS.d) / SCALE,
692
- d: SCALE
693
- }, precision);
694
- } catch {
695
- return OverflowValue;
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 > MAX_EXPONENT_RESULT_DIGITS || baseDDigits * exponent > MAX_EXPONENT_RESULT_DIGITS || (baseNDigits > 5e3 || baseDDigits > 5e3) && exponent > 10) return OverflowValue;
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, precision);
726
- return nthRoot(v, dExp, precision);
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: 4,
804
- UNARY_MINUS: 4,
805
- EXP: 6,
806
- IMPLICIT_MUL: 6,
807
- FN_CALL: 8,
808
- FACTORIAL: 10
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 (typeof op === "object") return precedence.FN_CALL;
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
- const rN = right.n;
831
- switch (op) {
832
- case "UNARY_MINUS":
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, options));
916
+ values.push(sqrt(right, maxDecimals));
846
917
  return;
847
918
  }
848
- if (rN === "OVERFLOW") {
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), options));
944
+ values.push(arctan(toSimpleFraction(right, maxDecimals), maxDecimals));
875
945
  return;
876
946
  case "arctanh":
877
- values.push(arctanh(toSimpleFraction(right, maxDecimals), options));
947
+ values.push(arctanh(toSimpleFraction(right, maxDecimals), maxDecimals));
878
948
  return;
879
949
  case "ln":
880
- values.push(ln(right, options));
950
+ values.push(ln(right, maxDecimals));
881
951
  return;
882
952
  case "exp":
883
- values.push(exp(right, options));
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, options));
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.pos;
1312
+ const { pos, type } = token;
1240
1313
  const isPrevOperand = isOperand(result.at(-1));
1241
- if (token.type === "PIPE") {
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 ((token.type === "LPAREN" || token.type === "FUNC" || token.type === "NUMBER" || token.type === "CONST") && isPrevOperand) result.push({
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 ((token.type === "FACTORIAL" || token.type === "RPAREN") && isUnaryContext(prevParsed)) {
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") && token.type === "NUMBER") throw new ParserError("Missing operator between numbers", token.pos);
1272
- if ((token.type === "PLUS" || token.type === "MINUS") && isUnaryContext(prevParsed)) result.push({
1273
- type: token.type === "PLUS" ? "UNARY_PLUS" : "UNARY_MINUS",
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.5",
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.75.0",
36
- "oxlint": "1.90.0",
37
- "oxlint-tsgolint": "7.0.2005",
38
- "tsdown": "0.23.4",
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
  }