]> Lady’s Gitweb - Pisces/blob - numeric.js
Make base32 handling less forgiving
[Pisces] / numeric.js
1 // ♓🌟 Piscēs ∷ numeric.js
2 // ====================================================================
3 //
4 // Copyright © 2022 Lady [@ Lady’s Computer].
5 //
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
9
10 import { call } from "./function.js";
11 import {
12 stringCatenate,
13 stringPadEnd,
14 stringRepeat,
15 substring,
16 toString,
17 } from "./string.js";
18 import { sameValue, toPrimitive } from "./value.js";
19
20 export const {
21 /**
22 * ln(10).
23 *
24 * ※ This is an alias for Math.LN10.
25 */
26 LN10,
27
28 /**
29 * ln(2).
30 *
31 * ※ This is an alias for Math.LN2.
32 */
33 LN2,
34
35 /**
36 * log10(ℇ).
37 *
38 * ※ This is an alias for Math.LOG10E.
39 */
40 LOG10E: LOG10ℇ,
41
42 /**
43 * log2(ℇ).
44 *
45 * ※ This is an alias for Math.LOG2E.
46 */
47 LOG2E: LOG2ℇ,
48
49 /**
50 * sqrt(.5).
51 *
52 * ※ This is an alias for Math.SQRT1_2.
53 */
54 SQRT1_2: RECIPROCAL_SQRT2,
55
56 /**
57 * sqrt(2).
58 *
59 * ※ This is an alias for Math.SQRT2.
60 */
61 SQRT2,
62
63 /**
64 * Returns the arccos of the provided value.
65 *
66 * ※ This is an alias for Math.acos.
67 *
68 * ☡ This function does not allow big·int arguments.
69 */
70 acos: arccos,
71
72 /**
73 * Returns the arccosh of the provided value.
74 *
75 * ※ This is an alias for Math.acosh.
76 *
77 * ☡ This function does not allow big·int arguments.
78 */
79 acosh: arccosh,
80
81 /**
82 * Returns the arcsin of the provided value.
83 *
84 * ※ This is an alias for Math.asin.
85 *
86 * ☡ This function does not allow big·int arguments.
87 */
88 asin: arcsin,
89
90 /**
91 * Returns the arcsinh of the provided value.
92 *
93 * ※ This is an alias for Math.asinh.
94 *
95 * ☡ This function does not allow big·int arguments.
96 */
97 asinh: arcsinh,
98
99 /**
100 * Returns the arctan of the provided value.
101 *
102 * ※ This is an alias for Math.atan.
103 *
104 * ☡ This function does not allow big·int arguments.
105 */
106 atan: arctan,
107
108 /**
109 * Returns the arctanh of the provided value.
110 *
111 * ※ This is an alias for Math.atanh.
112 *
113 * ☡ This function does not allow big·int arguments.
114 */
115 atanh: arctanh,
116
117 /**
118 * Returns the cube root of the provided value.
119 *
120 * ※ This is an alias for Math.cbrt.
121 *
122 * ☡ This function does not allow big·int arguments.
123 */
124 cbrt,
125
126 /**
127 * Returns the ceiling of the provided value.
128 *
129 * ※ This is an alias for Math.ceil.
130 *
131 * ☡ This function does not allow big·int arguments.
132 */
133 ceil,
134
135 /**
136 * Returns the cos of the provided value.
137 *
138 * ※ This is an alias for Math.cos.
139 *
140 * ☡ This function does not allow big·int arguments.
141 */
142 cos,
143
144 /**
145 * Returns the cosh of the provided value.
146 *
147 * ※ This is an alias for Math.cosh.
148 *
149 * ☡ This function does not allow big·int arguments.
150 */
151 cosh,
152
153 /**
154 * Returns the Euler number raised to the provided value.
155 *
156 * ※ This is an alias for Math.exp.
157 *
158 * ☡ This function does not allow big·int arguments.
159 */
160 exp,
161
162 /**
163 * Returns the Euler number raised to the provided value, minus one.
164 *
165 * ※ This is an alias for Math.expm1.
166 *
167 * ☡ This function does not allow big·int arguments.
168 */
169 expm1,
170
171 /**
172 * Returns the floor of the provided value.
173 *
174 * ※ This is an alias for Math.floor.
175 *
176 * ☡ This function does not allow big·int arguments.
177 */
178 floor,
179
180 /**
181 * Returns the square root of the sum of the squares of the provided
182 * arguments.
183 *
184 * ※ This is an alias for Math.hypot.
185 *
186 * ☡ This function does not allow big·int arguments.
187 */
188 hypot,
189
190 /**
191 * Returns the ln of the provided value.
192 *
193 * ※ This is an alias for Math.log.
194 *
195 * ☡ This function does not allow big·int arguments.
196 */
197 log: ln,
198
199 /**
200 * Returns the log10 of the provided value.
201 *
202 * ※ This is an alias for Math.log10.
203 *
204 * ☡ This function does not allow big·int arguments.
205 */
206 log10,
207
208 /**
209 * Returns the ln of one plus the provided value.
210 *
211 * ※ This is an alias for Math.log1p.
212 *
213 * ☡ This function does not allow big·int arguments.
214 */
215 log1p: ln1p,
216
217 /**
218 * Returns the log2 of the provided value.
219 *
220 * ※ This is an alias for Math.log2.
221 *
222 * ☡ This function does not allow big·int arguments.
223 */
224 log2,
225
226 /**
227 * Returns a pseudo·random value in the range [0, 1).
228 *
229 * ※ This is an alias for Math.random.
230 */
231 random: rand,
232
233 /**
234 * Returns the round of the provided value.
235 *
236 * ※ This is an alias for Math.round.
237 *
238 * ☡ This function does not allow big·int arguments.
239 */
240 round,
241
242 /**
243 * Returns the sinh of the provided value.
244 *
245 * ※ This is an alias for Math.sinh.
246 *
247 * ☡ This function does not allow big·int arguments.
248 */
249 sinh,
250
251 /**
252 * Returns the square root of the provided value.
253 *
254 * ※ This is an alias for Math.sqrt.
255 *
256 * ☡ This function does not allow big·int arguments.
257 */
258 sqrt,
259
260 /**
261 * Returns the tan of the provided value.
262 *
263 * ※ This is an alias for Math.tan.
264 *
265 * ☡ This function does not allow big·int arguments.
266 */
267 tan,
268
269 /**
270 * Returns the tanh of the provided value.
271 *
272 * ※ This is an alias for Math.tanh.
273 *
274 * ☡ This function does not allow big·int arguments.
275 */
276 tanh,
277
278 /**
279 * Returns the trunc of the provided value.
280 *
281 * ※ This is an alias for Math.trunc.
282 *
283 * ☡ This function does not allow big·int arguments.
284 */
285 trunc,
286
287 /**
288 * The mathematical constant π.
289 *
290 * ※ This is an alias for Math.PI.
291 */
292 PI: Π,
293
294 /**
295 * The Euler number.
296 *
297 * ※ This is an alias for Math.E.
298 */
299 E: ℇ,
300 } = Math;
301
302 export const {
303 /**
304 * The largest number value less than infinity.
305 *
306 * ※ This is an alias for Number.MAX_VALUE.
307 */
308 MAX_VALUE: MAXIMUM_NUMBER,
309
310 /**
311 * 2**53 - 1.
312 *
313 * ※ This is an alias for Number.MAX_SAFE_INTEGER.
314 */
315 MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER,
316
317 /**
318 * The smallest number value greater than negative infinity.
319 *
320 * ※ This is an alias for Number.MIN_VALUE.
321 */
322 MIN_VALUE: MINIMUM_NUMBER,
323
324 /**
325 * -(2**53 - 1).
326 *
327 * ※ This is an alias for Number.MIN_SAFE_INTEGER.
328 */
329 MIN_SAFE_INTEGER: MINIMUM_SAFE_INTEGRAL_NUMBER,
330
331 /**
332 * Negative infinity.
333 *
334 * ※ This is an alias for Number.NEGATIVE_INFINITY.
335 */
336 NEGATIVE_INFINITY,
337
338 /**
339 * Nan.
340 *
341 * ※ This is an alias for Number.NaN.
342 */
343 NaN: NAN,
344
345 /**
346 * Positive infinity.
347 *
348 * ※ This is an alias for Number.POSITIVE_INFINITY.
349 */
350 POSITIVE_INFINITY,
351
352 /**
353 * The difference between 1 and the smallest number greater than 1.
354 *
355 * ※ This is an alias for Number.EPSILON.
356 */
357 EPSILON: Ε,
358
359 /**
360 * Returns whether the provided value is a finite number.
361 *
362 * ※ This is an alias for Number.isFinite.
363 */
364 isFinite: isFiniteNumber,
365
366 /**
367 * Returns whether the provided value is an integral number.
368 *
369 * ※ This is an alias for Number.isInteger.
370 */
371 isInteger: isIntegralNumber,
372
373 /**
374 * Returns whether the provided value is nan.
375 *
376 * ※ This is an alias for Number.isNaN.
377 */
378 isNaN: isNan,
379
380 /**
381 * Returns whether the provided value is a safe integral number.
382 *
383 * ※ This is an alias for Number.isSafeInteger.
384 */
385 isSafeInteger: isSafeIntegralNumber,
386 } = Number;
387
388 /** Positive zero. */
389 export const POSITIVE_ZERO = 0;
390
391 /** Negative zero. */
392 export const NEGATIVE_ZERO = -0;
393
394 /**
395 * Returns the magnitude (absolute value) of the provided value.
396 *
397 * ※ Unlike Math.abs, this function can take big·int arguments.
398 */
399 export const abs = ($) => {
400 const n = toNumeric($);
401 return typeof n === "bigint"
402 ? n < 0n ? -n : n
403 : isNan(n)
404 ? NAN
405 : sameValue(n, -0)
406 ? 0
407 : sameValue(n, NEGATIVE_INFINITY)
408 ? POSITIVE_INFINITY
409 : n < 0
410 ? -n
411 : n;
412 };
413
414 export const {
415 /**
416 * Returns the arctangent of the dividend of the provided values.
417 *
418 * ※ Unlike Math.atan2, this function can take big·int arguments.
419 * However, the result will always be a number.
420 */
421 atan2,
422
423 /**
424 * Returns the number of leading zeroes in the 32‐bit representation of
425 * the provided value.
426 *
427 * ※ Unlike Math.clz32, this function accepts either number or big·int
428 * values.
429 */
430 clz32,
431
432 /**
433 * Returns the 32‐bit float which best approximate the provided
434 * value.
435 *
436 * ※ Unlike Math.fround, this function can take big·int arguments.
437 * However, the result will always be a number.
438 */
439 toFloat32,
440 } = (() => {
441 const { atan2, fround, clz32 } = Math;
442 return {
443 atan2: (y, x) => atan2(toNumber(y), toNumber(x)),
444 clz32: ($) => {
445 const n = toNumeric($);
446 return clz32(
447 typeof n === "bigint" ? toNumber(toUintN(32, n)) : n,
448 );
449 },
450 toFloat32: ($) => fround(toNumber($)),
451 };
452 })();
453
454 /**
455 * Returns the highest value of the provided arguments, or negative
456 * infinity if no argument is provided.
457 *
458 * ※ Unlike Math.max, this function accepts either number or big·int
459 * values. All values must be of the same type, or this function will
460 * throw an error.
461 *
462 * ☡ If no argument is supplied, the result will be a number, not a
463 * big·int.
464 */
465 export const max = (...$s) => {
466 let highest = undefined;
467 for (let i = 0; i < $s.length; ++i) {
468 // Iterate over all the numbers.
469 const number = toNumeric($s[i]);
470 if (highest === undefined) {
471 // The current number is the first one.
472 if (isNan(number)) {
473 // The current number is nan.
474 return NAN;
475 } else {
476 // The current number is not nan.
477 highest = number;
478 }
479 } else {
480 if (typeof highest !== typeof number) {
481 // The type of the current number and the lowest number don’t
482 // match.
483 throw new TypeError("Piscēs: Type mismatch.");
484 } else if (isNan(number)) {
485 // The current number is nan.
486 return NAN;
487 } else if (sameValue(number, 0) && sameValue(highest, -0)) {
488 // The current number is +0 and the highest number is -0.
489 highest = 0;
490 } else if (highest === undefined || number > highest) {
491 // The current number is greater than the highest number.
492 highest = number;
493 } else {
494 // The current number is less than or equal to the lowest
495 // number.
496 /* do nothing */
497 }
498 }
499 }
500 return highest ?? NEGATIVE_INFINITY;
501 };
502
503 /**
504 * Returns the lowest value of the provided arguments, or positive
505 * infinity if no argument is provided.
506 *
507 * ※ Unlike Math.min, this function accepts either number or big·int
508 * values. All values must be of the same type, or this function will
509 * throw an error.
510 *
511 * ☡ If no argument is supplied, the result will be a number, not a
512 * big·int.
513 */
514 export const min = (...$s) => {
515 let lowest = undefined;
516 for (let i = 0; i < $s.length; ++i) {
517 // Iterate over all the numbers.
518 const number = toNumeric($s[i]);
519 if (lowest === undefined) {
520 // The current number is the first one.
521 if (isNan(number)) {
522 // The current number is nan.
523 return NAN;
524 } else {
525 // The current number is not nan.
526 lowest = number;
527 }
528 } else {
529 // The current number is not the first one.
530 if (typeof lowest !== typeof number) {
531 // The type of the current number and the lowest number don’t
532 // match.
533 throw new TypeError("Piscēs: Type mismatch.");
534 } else if (isNan(number)) {
535 // The current number is nan.
536 return NAN;
537 } else if (sameValue(number, -0) && sameValue(lowest, 0)) {
538 // The current number is -0 and the lowest number is +0.
539 lowest = -0;
540 } else if (number < lowest) {
541 // The current number is less than the lowest number.
542 lowest = number;
543 } else {
544 // The current number is greater than or equal to the lowest
545 // number.
546 /* do nothing */
547 }
548 }
549 }
550 return lowest ?? POSITIVE_INFINITY;
551 };
552
553 /**
554 * Returns a unit value with the same sign as the provided value, or
555 * the provided value itself if it is not a number or (potentially
556 * signed) zero.
557 *
558 * For big·ints, the return value of this function is 0n if the
559 * provided value is 0n, -1n if the provided value is negative, and +1n
560 * otherwise.
561 *
562 * For numbers, the return value is nan, -0, or +0 if the provided
563 * value is nan, -0, or +0, respectively, and -1 if the provided value
564 * is negative and +1 if the provided value is positive otherwise. Note
565 * that positive and negative infinity will return +1 and -1
566 * respectively.
567 *
568 * ※ Unlike Math.sign, this function accepts either number or big·int
569 * values.
570 */
571 export const sgn = ($) => {
572 const n = toNumeric($);
573 return typeof n === "bigint"
574 ? n === 0n ? 0n : n < 0n ? -1n : 1n
575 : isNan(n) || n === 0
576 ? n
577 //deno-lint-ignore no-compare-neg-zero
578 : n < -0
579 ? -1
580 : 1;
581 };
582
583 /**
584 * Returns the result of converting the provided value to a big·int.
585 *
586 * ※ This method is safe to use with numbers.
587 *
588 * ※ This is effectively an alias for BigInt.
589 */
590 export const { toBigInt } = (() => {
591 const makeBigInt = BigInt;
592 return { toBigInt: ($) => makeBigInt($) };
593 })();
594
595 export const {
596 /**
597 * Returns the result of converting the provided value to an
598 * exponential notation string.
599 *
600 * If a second argument is provided, it gives the number of
601 * fractional digits to use in the mantissa. Otherwise, the smallest
602 * number which does not result in a reduction in precision is used.
603 *
604 * ※ This method is safe to use with big·ints.
605 */
606 toExponentialNotation,
607
608 /**
609 * Returns the result of converting the provided value to a fixed
610 * decimal notation string with the provided number of fractional
611 * digits.
612 *
613 * ※ This method is safe to use with big·ints.
614 */
615 toFixedDecimalNotation,
616 } = (() => {
617 const {
618 toExponential: numberToExponential,
619 toFixed: numberToFixed,
620 } = Number.prototype;
621 const { toString: bigintToString } = BigInt.prototype;
622 return {
623 toExponentialNotation: ($, fractionDigits) => {
624 const n = toNumeric($);
625 const f = toIntegralNumberOrInfinity(fractionDigits);
626 if (!isFiniteNumber(f) || f < 0 || f > 100) {
627 throw new RangeError(
628 `Piscēs: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`,
629 );
630 } else {
631 if (typeof n === "number") {
632 return call(
633 numberToExponential,
634 n,
635 [fractionDigits === undefined ? fractionDigits : f],
636 );
637 } else {
638 const digits = call(bigintToString, n, [10]);
639 const { length } = digits;
640 if (fractionDigits === undefined) {
641 return length === 1
642 ? `${digits[0]}e+0`
643 : `${digits[0]}.${substring(digits, 1)}e+${length - 1}`;
644 } else if (f === 0) {
645 return `${digits[0]}e+0`;
646 } else {
647 const fractionalPart = toString(
648 round(
649 +stringCatenate(
650 stringPadEnd(substring(digits, 1, f + 1), f, "0"),
651 ".",
652 digits[f + 1] || "0",
653 ),
654 ),
655 );
656 return `${digits[0]}.${fractionalPart}e+${length - 1}`;
657 }
658 }
659 }
660 },
661 toFixedDecimalNotation: ($, fractionDigits) => {
662 const f = toIntegralNumberOrInfinity(fractionDigits);
663 if (!isFiniteNumber(f) || f < 0 || f > 100) {
664 throw new RangeError(
665 `Piscēs: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`,
666 );
667 } else {
668 const n = toNumeric($);
669 if (typeof n === "number") {
670 return call(numberToFixed, n, [f]);
671 } else {
672 const digits = call(bigintToString, n, [10]);
673 return f === 0
674 ? digits
675 : `${digits}.${stringRepeat("0", f)}`;
676 }
677 }
678 },
679 };
680 })();
681
682 export const {
683 /**
684 * Returns the result of converting the provided value to fit within
685 * the provided number of bits as a signed integer.
686 *
687 * ※ Unlike BigInt.asIntN, this function accepts both big·int and
688 * number values.
689 *
690 * ☡ The first argument, the number of bits, must be a number.
691 */
692 toIntN,
693
694 /**
695 * Returns the result of converting the provided value to fit within
696 * the provided number of bits as an unsigned integer.
697 *
698 * ※ Unlike BigInt.asUintN, this function accepts both big·int and
699 * number values.
700 *
701 * ☡ The first argument, the number of bits, must be a number.
702 */
703 toUintN,
704 } = (() => {
705 const { asIntN, asUintN } = BigInt;
706 return {
707 toIntN: (n, $) => {
708 const prim = toPrimitive($);
709 if (typeof prim === "bigint") {
710 // The primitive value is a big·int.
711 return asIntN(n, prim);
712 } else {
713 // The primitive value is not a big·int.
714 const int = trunc(prim);
715 if (!isFiniteNumber(int) || int == 0) {
716 // The truncated value is zero or not finite.
717 return 0;
718 } else {
719 // The truncated value is finite.
720 return toNumber(asIntN(n, toBigInt(int)));
721 }
722 }
723 },
724 toUintN: (n, $) => {
725 const prim = toPrimitive($);
726 if (typeof prim === "bigint") {
727 // The primitive value is a big·int.
728 return asUintN(n, prim);
729 } else {
730 // The primitive value is not a big·int.
731 const int = trunc(prim);
732 if (!isFiniteNumber(int) || int == 0) {
733 // The truncated value is zero or not finite.
734 return 0;
735 } else {
736 // The truncated value is finite.
737 return toNumber(asUintN(n, toBigInt(int)));
738 }
739 }
740 },
741 };
742 })();
743
744 /**
745 * Returns the result of converting the provided number to an integral
746 * number.
747 *
748 * ※ This function will never return negative zero.
749 */
750 export const toIntegralNumber = ($) => {
751 const n = toIntegralNumberOrInfinity($);
752 return !isFiniteNumber(n) || n == 0 ? 0 : n;
753 };
754
755 /**
756 * Returns the result of converting the provided number to an integer
757 * or infinity.
758 *
759 * ※ Unlike the ToIntegerOrInfinity function defined in the Ecmascript
760 * specification, this function is safe to use with big·ints. However,
761 * the result will always be a number.
762 *
763 * ※ This function will never return negative zero.
764 */
765 export const toIntegralNumberOrInfinity = ($) => {
766 const integer = trunc(toNumber($));
767 if (isNan(integer) || integer == 0) {
768 // The provided value truncs to nan or (positive or negative) zero.
769 return 0;
770 } else if (integer == POSITIVE_INFINITY) {
771 // The provided value truncs to positive infinity.
772 return POSITIVE_INFINITY;
773 } else if (integer == NEGATIVE_INFINITY) {
774 // The provided value truncs to negative infinity.
775 return NEGATIVE_INFINITY;
776 } else {
777 // The provided value truncs to an integer.
778 return integer;
779 }
780 };
781
782 /**
783 * Returns the result of converting the provided value to a number.
784 *
785 * ※ This function is safe to use with big·ints.
786 *
787 * ※ This is effectively a nonconstructible version of the Number
788 * constructor.
789 */
790 export const { toNumber } = (() => {
791 const makeNumber = Number;
792 return { toNumber: ($) => makeNumber($) };
793 })();
794
795 /**
796 * Returns the result of converting the provided value to a number or
797 * big·int.
798 *
799 * ※ If the result of converting the provided value to a primitive is
800 * not a big·int, this function will return a number.
801 */
802 export const toNumeric = ($) => {
803 const primValue = toPrimitive($, "number");
804 return typeof primValue === "bigint" ? primValue : +primValue;
805 };
This page took 0.108471 seconds and 5 git commands to generate.