1 // ♓🌟 Piscēs ∷ numeric.js
2 // ====================================================================
4 // Copyright © 2022–2023 Lady [@ Lady’s Computer].
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/>.
10 import { call
, createArrowFunction
} from "./function.js";
11 import { defineOwnDataProperty
} from "./object.js";
29 * Returns the magnitude (absolute value) of the provided value.
31 * ※ Unlike `Math.abs`, this function can take big·int arguments.
33 export const abs
= ($) => {
34 const n
= toNumeric($);
35 return typeof n
=== "bigint"
41 : sameValue(n
, NEGATIVE_INFINITY
)
49 * Returns the arccos of the provided value.
51 * ※ This function is effectively an alias for `Math.acos`.
53 * ☡ This function does not allow big·int arguments.
55 export const arccos
= createArrowFunction(
61 * Returns the arccosh of the provided value.
63 * ※ This function is effectively an alias for `Math.acosh`.
65 * ☡ This function does not allow big·int arguments.
67 export const arccosh
= createArrowFunction(
73 * Returns the arcsin of the provided value.
75 * ※ This function is effectively an alias for `Math.asin`.
77 * ☡ This function does not allow big·int arguments.
79 export const arcsin
= createArrowFunction(
85 * Returns the arcsinh of the provided value.
87 * ※ This function is effectively an alias for `Math.asinh`.
89 * ☡ This function does not allow big·int arguments.
91 export const arcsinh
= createArrowFunction(
97 * Returns the arctan of the provided value.
99 * ※ This function is effectively an alias for `Math.atan`.
101 * ☡ This function does not allow big·int arguments.
103 export const arctan
= createArrowFunction(
110 * Returns the arctangent of the dividend of the provided values.
112 * ※ Unlike `Math.atan2`, this function can take big·int arguments.
113 * However, the result will always be a number.
118 * Returns the number of leading zeroes in the 32‐bit representation
119 * of the provided value.
121 * ※ Unlike `Math.clz32`, this function accepts either number or
127 * Returns the 32‐bit float which best approximate the provided
130 * ※ Unlike `Math.fround`, this function can take big·int arguments.
131 * However, the result will always be a number.
135 const { atan2
, fround
, clz32
} = Math
;
137 arctan2
: (y
, x
) => atan2(toNumber(y
), toNumber(x
)),
139 const n
= toNumeric($);
141 typeof n
=== "bigint"
142 ? toNumber(toUnsignedIntegralNumeric(32, n
))
146 toFloat32
: ($) => fround(toNumber($)),
151 * Returns the arctanh of the provided value.
153 * ※ This function is effectively an alias for `Math.atanh`.
155 * ☡ This function does not allow big·int arguments.
157 export const arctanh
= createArrowFunction(
163 * Returns the cube root of the provided value.
165 * ※ This function is effectively an alias for `Math.cbrt`.
167 * ☡ This function does not allow big·int arguments.
169 export const cbrt
= createArrowFunction(Math
.cbrt
);
172 * Returns the ceiling of the provided value.
174 * ※ This function is effectively an alias for `Math.ceil`.
176 * ☡ This function does not allow big·int arguments.
178 export const ceil
= createArrowFunction(Math
.ceil
);
181 * Returns the cos of the provided value.
183 * ※ This function is effectively an alias for `Math.cos`.
185 * ☡ This function does not allow big·int arguments.
187 export const cos
= createArrowFunction(Math
.cos
);
190 * Returns the cosh of the provided value.
192 * ※ This function is effectively an alias for `Math.cosh`.
194 * ☡ This function does not allow big·int arguments.
196 export const cosh
= createArrowFunction(Math
.cosh
);
199 * Returns the Euler number raised to the provided value.
201 * ※ This function is effectively an alias for `Math.exp`.
203 * ☡ This function does not allow big·int arguments.
205 export const exp
= createArrowFunction(Math
.exp
);
208 * Returns the Euler number raised to the provided value, minus one.
210 * ※ This function is effectively an alias for `Math.expm1`.
212 * ☡ This function does not allow big·int arguments.
214 export const expm1
= createArrowFunction(Math
.expm1
);
217 * Returns the floor of the provided value.
219 * ※ This function is effectively an alias for `Math.floor`.
221 * ☡ This function does not allow big·int arguments.
223 export const floor
= createArrowFunction(Math
.floor
);
226 * Returns the square root of the sum of the squares of the provided
229 * ※ This function is effectively an alias for `Math.hypot`.
231 * ☡ This function does not allow big·int arguments.
233 export const hypot
= createArrowFunction(Math
.hypot
);
236 * Returns whether the provided value is a finite number.
238 * ※ This function is effectively an alias for `Number.isFinite`.
240 export const isFiniteNumber
= createArrowFunction(
242 { name
: "isFiniteNumber" },
246 * Returns whether the provided value is an integral number.
248 * ※ This function is effectively an alias for `Number.isInteger`.
250 export const isIntegralNumber
= createArrowFunction(
252 { name
: "isIntegralNumber" },
256 * Returns whether the provided value is nan.
258 * ※ This function is effectively an alias for `Number.isNaN`.
260 export const isNan
= createArrowFunction(
266 * Returns whether the provided value is a safe integral number.
268 * ※ This function is effectively an alias for `Number.isSafeInteger`.
270 export const isSafeIntegralNumber
= createArrowFunction(
271 Number
.isSafeInteger
,
272 { name
: "isSafeIntegralNumber" },
276 * Returns the ln of the provided value.
278 * ※ This function is effectively an alias for `Math.log`.
280 * ☡ This function does not allow big·int arguments.
282 export const ln
= createArrowFunction(Math
.log
, { name
: "ln" });
285 * Returns the ln of one plus the provided value.
287 * ※ This function is effectively an alias for `Math.log1p`.
289 * ☡ This function does not allow big·int arguments.
291 export const ln1p
= createArrowFunction(Math
.log1p
, { name
: "ln1p" });
294 * Returns the log10 of the provided value.
296 * ※ This function is effectively an alias for `Math.log10`.
298 * ☡ This function does not allow big·int arguments.
300 export const log10
= createArrowFunction(Math
.log10
);
303 * Returns the log2 of the provided value.
305 * ※ This function is effectively an alias for `Math.log2`.
307 * ☡ This function does not allow big·int arguments.
309 export const log2
= createArrowFunction(Math
.log2
);
312 * Returns the highest value of the provided arguments, or negative
313 * infinity if no argument is provided.
315 * ※ Unlike `Math.max`, this function accepts either number or big·int
316 * values. All values must be of the same type, or this function will
319 * ☡ If no argument is supplied, the result will be a number, not a
322 export const max
= Object
.defineProperties((...$s
) => {
323 let highest
= UNDEFINED
;
324 for (let i
= 0; i
< $s
.length
; ++i
) {
325 // Iterate over all the numbers.
326 const number
= toNumeric($s
[i
]);
327 if (highest
=== UNDEFINED
) {
328 // The current number is the first one.
330 // The current number is nan.
333 // The current number is not nan.
337 if (typeof highest
!== typeof number
) {
338 // The type of the current number and the lowest number don’t
340 throw new TypeError("Piscēs: Type mismatch.");
341 } else if (isNan(number
)) {
342 // The current number is nan.
344 } else if (sameValue(number
, 0) && sameValue(highest
, -0)) {
345 // The current number is +0 and the highest number is -0.
347 } else if (number
> highest
) {
348 // The current number is greater than the highest number.
351 // The current number is less than or equal to the lowest
357 return highest
?? NEGATIVE_INFINITY
;
359 name
: defineOwnDataProperty(Object
.create(null), "value", "max"),
360 length
: defineOwnDataProperty(Object
.create(null), "value", 2),
364 * Returns the lowest value of the provided arguments, or positive
365 * infinity if no argument is provided.
367 * ※ Unlike `Math.min`, this function accepts either number or big·int
368 * values. All values must be of the same type, or this function will
371 * ☡ If no argument is supplied, the result will be a number, not a
374 export const min
= Object
.defineProperties((...$s
) => {
375 let lowest
= UNDEFINED
;
376 for (let i
= 0; i
< $s
.length
; ++i
) {
377 // Iterate over all the numbers.
378 const number
= toNumeric($s
[i
]);
379 if (lowest
=== UNDEFINED
) {
380 // The current number is the first one.
382 // The current number is nan.
385 // The current number is not nan.
389 // The current number is not the first one.
390 if (typeof lowest
!== typeof number
) {
391 // The type of the current number and the lowest number don’t
393 throw new TypeError("Piscēs: Type mismatch.");
394 } else if (isNan(number
)) {
395 // The current number is nan.
397 } else if (sameValue(number
, -0) && sameValue(lowest
, 0)) {
398 // The current number is -0 and the lowest number is +0.
400 } else if (number
< lowest
) {
401 // The current number is less than the lowest number.
404 // The current number is greater than or equal to the lowest
410 return lowest
?? POSITIVE_INFINITY
;
412 name
: defineOwnDataProperty(Object
.create(null), "value", "min"),
413 length
: defineOwnDataProperty(Object
.create(null), "value", 2),
417 * Returns a pseudo·random value in the range [0, 1).
419 * ※ This function is effectively an alias for `Math.random`.
421 export const rand
= createArrowFunction(
427 * Returns the round of the provided value.
429 * ※ This function is effectively an alias for `Math.round`.
431 * ☡ This function does not allow big·int arguments.
433 export const round
= createArrowFunction(Math
.round
);
436 * Returns a unit value with the same sign as the provided value, or
437 * the provided value itself if it is not a number or (potentially
440 * For big·ints, the return value of this function is 0n if the
441 * provided value is 0n, −1n if the provided value is negative, and +1n
444 * For numbers, the return value is nan, −0, or +0 if the provided
445 * value is nan, −0, or +0, respectively, and −1 if the provided value
446 * is negative and +1 if the provided value is positive otherwise. Note
447 * that positive and negative infinity will return +1 and −1
450 * ※ Unlike `Math.sign`, this function accepts either number or
453 export const sgn
= ($) => {
454 const n
= toNumeric($);
455 return typeof n
=== "bigint"
456 ? n
=== 0n
? 0n
: n
< 0n
? -1n
: 1n
457 : isNan(n
) || n
=== 0
459 //deno-lint-ignore no-compare-neg-zero
466 * Returns the sin of the provided value.
468 * ※ This function is effectively an alias for `Math.sin`.
470 * ☡ This function does not allow big·int arguments.
472 export const sin
= createArrowFunction(Math
.sin
);
475 * Returns the sinh of the provided value.
477 * ※ This function is effectively an alias for `Math.sinh`.
479 * ☡ This function does not allow big·int arguments.
481 export const sinh
= createArrowFunction(Math
.sinh
);
484 * Returns the square root of the provided value.
486 * ※ This function is effectively an alias for `Math.sqrt`.
488 * ☡ This function does not allow big·int arguments.
490 export const sqrt
= createArrowFunction(Math
.sqrt
);
493 * Returns the tan of the provided value.
495 * ※ This function is effectively an alias for `Math.tan`.
497 * ☡ This function does not allow big·int arguments.
499 export const tan
= createArrowFunction(Math
.tan
);
502 * Returns the tanh of the provided value.
504 * ※ This function is effectively an alias for `Math.tanh`.
506 * ☡ This function does not allow big·int arguments.
508 export const tanh
= createArrowFunction(Math
.tanh
);
511 * Returns the result of converting the provided value to a big·int.
513 * ※ This method is safe to use with numbers.
515 * ※ This is effectively an alias for `BigInt`.
517 export const { toBigInt
} = (() => {
518 const makeBigInt
= BigInt
;
519 return { toBigInt
: ($) => makeBigInt($) };
524 * Returns the result of converting the provided value to an
525 * exponential notation string.
527 * If a second argument is provided, it gives the number of
528 * fractional digits to use in the mantissa. Otherwise, the smallest
529 * number which does not result in a reduction in precision is used.
531 * ※ This method is safe to use with big·ints.
533 toExponentialNotation
,
536 * Returns the result of converting the provided value to a fixed
537 * decimal notation string with the provided number of fractional
540 * ※ This method is safe to use with big·ints.
542 toFixedDecimalNotation
,
545 toExponential
: numberToExponential
,
546 toFixed
: numberToFixed
,
547 } = Number
.prototype;
548 const { toString
: bigintToString
} = BigInt
.prototype;
550 toExponentialNotation
: ($, fractionDigits
) => {
551 const n
= toNumeric($);
552 const f
= toIntegralNumberOrInfinity(fractionDigits
);
553 if (!isFiniteNumber(f
) || f
< 0 || f
> 100) {
554 throw new RangeError(
555 `Piscēs: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`,
558 if (typeof n
=== "number") {
562 [fractionDigits
=== UNDEFINED
? fractionDigits
: f
],
565 const digits
= call(bigintToString
, n
, [10]);
566 const { length
} = digits
;
567 if (fractionDigits
=== UNDEFINED
) {
570 : `${digits[0]}.${substring(digits, 1)}e+${length - 1}`;
571 } else if (f
=== 0) {
572 return `${digits[0]}e+0`;
574 const fractionalPart
= toString(
577 stringPadEnd(substring(digits
, 1, f
+ 1), f
, "0"),
579 digits
[f
+ 1] || "0",
583 return `${digits[0]}.${fractionalPart}e+${length - 1}`;
588 toFixedDecimalNotation
: ($, fractionDigits
) => {
589 const f
= toIntegralNumberOrInfinity(fractionDigits
);
590 if (!isFiniteNumber(f
) || f
< 0 || f
> 100) {
591 throw new RangeError(
592 `Piscēs: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`,
595 const n
= toNumeric($);
596 if (typeof n
=== "number") {
597 return call(numberToFixed
, n
, [f
]);
599 const digits
= call(bigintToString
, n
, [10]);
602 : `${digits}.${stringRepeat("0", f)}`;
610 * Returns the result of converting the provided number to an integral
613 * ※ This function will never return negative zero.
615 export const toIntegralNumber
= ($) => {
616 const n
= toIntegralNumberOrInfinity($);
617 return !isFiniteNumber(n
) || n
== 0 ? 0 : n
;
621 * Returns the result of converting the provided number to an integer
624 * ※ Unlike the ToIntegerOrInfinity function defined in the Ecmascript
625 * specification, this function is safe to use with big·ints. However,
626 * the result will always be a number.
628 * ※ This function will never return negative zero.
630 export const toIntegralNumberOrInfinity
= ($) => {
631 const integer
= trunc(toNumber($));
632 if (isNan(integer
) || integer
== 0) {
633 // The provided value truncs to nan or (positive or negative) zero.
635 } else if (integer
== POSITIVE_INFINITY
) {
636 // The provided value truncs to positive infinity.
637 return POSITIVE_INFINITY
;
638 } else if (integer
== NEGATIVE_INFINITY
) {
639 // The provided value truncs to negative infinity.
640 return NEGATIVE_INFINITY
;
642 // The provided value truncs to an integer.
648 * Returns the result of converting the provided value to a number.
650 * ※ This function is safe to use with big·ints.
652 * ※ This is effectively a nonconstructible version of the `Number`
655 export const { toNumber
} = (() => {
656 const makeNumber
= Number
;
657 return { toNumber
: ($) => makeNumber($) };
661 * Returns the result of converting the provided value to a number or
664 * ※ If the result of converting the provided value to a primitive is
665 * not a big·int, this function will return a number.
667 export const toNumeric
= ($) => {
668 const primValue
= toPrimitive($, "number");
669 return typeof primValue
=== "bigint" ? primValue
: +primValue
;
674 * Returns the result of converting the provided value to fit within
675 * the provided number of bits as a signed integer.
677 * ※ Unlike `BigInt.asIntN`, this function accepts both big·int and
680 * ☡ The first argument, the number of bits, must be a number.
682 toSignedIntegralNumeric
,
685 * Returns the result of converting the provided value to fit within
686 * the provided number of bits as an unsigned integer.
688 * ※ Unlike `BigInt.asUintN`, this function accepts both big·int and
691 * ☡ The first argument, the number of bits, must be a number.
693 toUnsignedIntegralNumeric
,
695 const { asIntN
, asUintN
} = BigInt
;
697 toSignedIntegralNumeric
: (n
, $) => {
698 const prim
= toPrimitive($);
699 if (typeof prim
=== "bigint") {
700 // The primitive value is a big·int.
701 return asIntN(n
, prim
);
703 // The primitive value is not a big·int.
704 const int = trunc(prim
);
705 if (!isFiniteNumber(int) || int == 0) {
706 // The truncated value is zero or not finite.
709 // The truncated value is finite.
710 return toNumber(asIntN(n
, toBigInt(int)));
714 toUnsignedIntegralNumeric
: (n
, $) => {
715 const prim
= toPrimitive($);
716 if (typeof prim
=== "bigint") {
717 // The primitive value is a big·int.
718 return asUintN(n
, prim
);
720 // The primitive value is not a big·int.
721 const int = trunc(prim
);
722 if (!isFiniteNumber(int) || int == 0) {
723 // The truncated value is zero or not finite.
726 // The truncated value is finite.
727 return toNumber(asUintN(n
, toBigInt(int)));
735 * Returns the trunc of the provided value.
737 * ※ This function is effectively an alias for `Math.trunc`.
739 * ☡ This function does not allow big·int arguments.
741 export const trunc
= createArrowFunction(Math
.trunc
);