1 // SPDX-FileCopyrightText: 2022, 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
2 // SPDX-License-Identifier: MPL-2.0
4 * ⁌ ♓🧩 Piscēs ∷ numeric.js
6 * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer].
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
13 import { call
, createArrowFunction
} from "./function.js";
14 import { defineOwnDataProperty
} from "./object.js";
31 const PISC
ĒS
= "♓🧩 Piscēs";
34 * Returns the magnitude (absolute value) of the provided value.
36 * ※ Unlike `Math.abs´, this function can take big·int arguments.
38 export const abs
= ($) => {
39 const n
= toNumeric($);
40 return typeof n
=== "bigint"
46 : sameValue(n
, NEGATIVE_INFINITY
)
54 * Returns the arccos of the provided value.
56 * ※ This function is effectively an alias for `Math.acos´.
58 * ☡ This function does not allow big·int arguments.
60 export const arccos
= createArrowFunction(
66 * Returns the arccosh of the provided value.
68 * ※ This function is effectively an alias for `Math.acosh´.
70 * ☡ This function does not allow big·int arguments.
72 export const arccosh
= createArrowFunction(
78 * Returns the arcsin of the provided value.
80 * ※ This function is effectively an alias for `Math.asin´.
82 * ☡ This function does not allow big·int arguments.
84 export const arcsin
= createArrowFunction(
90 * Returns the arcsinh of the provided value.
92 * ※ This function is effectively an alias for `Math.asinh´.
94 * ☡ This function does not allow big·int arguments.
96 export const arcsinh
= createArrowFunction(
102 * Returns the arctan of the provided value.
104 * ※ This function is effectively an alias for `Math.atan´.
106 * ☡ This function does not allow big·int arguments.
108 export const arctan
= createArrowFunction(
115 * Returns the arctangent of the dividend of the provided values.
117 * ※ Unlike `Math.atan2´, this function can take big·int arguments.
118 * However, the result will always be a number.
123 * Returns the number of leading zeroes in the 32‐bit representation
124 * of the provided value.
126 * ※ Unlike `Math.clz32´, this function accepts either number or
132 * Returns the 32‐bit float which best approximate the provided
135 * ※ Unlike `Math.fround´, this function can take big·int arguments.
136 * However, the result will always be a number.
140 const { atan2
, fround
, clz32
} = Math
;
142 arctan2: (y
, x
) => atan2(toNumber(y
), toNumber(x
)),
144 const n
= toNumeric($);
146 typeof n
=== "bigint"
147 ? toNumber(toUnsignedIntegralNumeric(32, n
))
151 toFloat32: ($) => fround(toNumber($)),
156 * Returns the arctanh of the provided value.
158 * ※ This function is effectively an alias for `Math.atanh´.
160 * ☡ This function does not allow big·int arguments.
162 export const arctanh
= createArrowFunction(
168 * Returns the cube root of the provided value.
170 * ※ This function is effectively an alias for `Math.cbrt´.
172 * ☡ This function does not allow big·int arguments.
174 export const cbrt
= createArrowFunction(Math
.cbrt
);
177 * Returns the ceiling of the provided value.
179 * ※ This function is effectively an alias for `Math.ceil´.
181 * ☡ This function does not allow big·int arguments.
183 export const ceil
= createArrowFunction(Math
.ceil
);
186 * Returns the cos of the provided value.
188 * ※ This function is effectively an alias for `Math.cos´.
190 * ☡ This function does not allow big·int arguments.
192 export const cos
= createArrowFunction(Math
.cos
);
195 * Returns the cosh of the provided value.
197 * ※ This function is effectively an alias for `Math.cosh´.
199 * ☡ This function does not allow big·int arguments.
201 export const cosh
= createArrowFunction(Math
.cosh
);
204 * Returns the Euler number raised to the provided value.
206 * ※ This function is effectively an alias for `Math.exp´.
208 * ☡ This function does not allow big·int arguments.
210 export const exp
= createArrowFunction(Math
.exp
);
213 * Returns the Euler number raised to the provided value, minus one.
215 * ※ This function is effectively an alias for `Math.expm1´.
217 * ☡ This function does not allow big·int arguments.
219 export const expm1
= createArrowFunction(Math
.expm1
);
222 * Returns the floor of the provided value.
224 * ※ This function is effectively an alias for `Math.floor´.
226 * ☡ This function does not allow big·int arguments.
228 export const floor
= createArrowFunction(Math
.floor
);
231 * Returns the square root of the sum of the squares of the provided
234 * ※ This function is effectively an alias for `Math.hypot´.
236 * ☡ This function does not allow big·int arguments.
238 export const hypot
= createArrowFunction(Math
.hypot
);
241 * Returns whether the provided value is a finite number.
243 * ※ This function is effectively an alias for `Number.isFinite´.
245 export const isFiniteNumber
= createArrowFunction(
247 { name: "isFiniteNumber" },
251 * Returns whether the provided value is an integral number.
253 * ※ This function is effectively an alias for `Number.isInteger´.
255 export const isIntegralNumber
= createArrowFunction(
257 { name: "isIntegralNumber" },
261 * Returns whether the provided value is nan.
263 * ※ This function is effectively an alias for `Number.isNaN´.
265 export const isNan
= createArrowFunction(
271 * Returns whether the provided value is a safe integral number.
273 * ※ This function is effectively an alias for `Number.isSafeInteger´.
275 export const isSafeIntegralNumber
= createArrowFunction(
276 Number
.isSafeInteger
,
277 { name: "isSafeIntegralNumber" },
281 * Returns the ln of the provided value.
283 * ※ This function is effectively an alias for `Math.log´.
285 * ☡ This function does not allow big·int arguments.
287 export const ln
= createArrowFunction(Math
.log
, { name: "ln" });
290 * Returns the ln of one plus the provided value.
292 * ※ This function is effectively an alias for `Math.log1p´.
294 * ☡ This function does not allow big·int arguments.
296 export const ln1p
= createArrowFunction(Math
.log1p
, { name: "ln1p" });
299 * Returns the log10 of the provided value.
301 * ※ This function is effectively an alias for `Math.log10´.
303 * ☡ This function does not allow big·int arguments.
305 export const log10
= createArrowFunction(Math
.log10
);
308 * Returns the log2 of the provided value.
310 * ※ This function is effectively an alias for `Math.log2´.
312 * ☡ This function does not allow big·int arguments.
314 export const log2
= createArrowFunction(Math
.log2
);
317 * Returns the highest value of the provided arguments, or negative
318 * infinity if no argument is provided.
320 * ※ Unlike `Math.max´, this function accepts either number or big·int
321 * values. All values must be of the same type, or this function will
324 * ☡ If no argument is supplied, the result will be a number, not a
327 export const max
= Object
.defineProperties((...$s
) => {
328 let highest
= UNDEFINED
;
329 for (let i
= 0; i
< $s
.length
; ++i
) {
330 // Iterate over all the numbers.
331 const number
= toNumeric($s
[i
]);
332 if (highest
=== UNDEFINED
) {
333 // The current number is the first one.
335 // The current number is nan.
338 // The current number is not nan.
342 if (typeof highest
!== typeof number
) {
343 // The type of the current number and the lowest number don¦t
345 throw new TypeError(`${PISCĒS}: Type mismatch.`);
346 } else if (isNan(number
)) {
347 // The current number is nan.
349 } else if (sameValue(number
, 0) && sameValue(highest
, -0)) {
350 // The current number is +0 and the highest number is -0.
352 } else if (number
> highest
) {
353 // The current number is greater than the highest number.
356 // The current number is less than or equal to the lowest
362 return highest
?? NEGATIVE_INFINITY
;
364 name: defineOwnDataProperty(Object
.create(null), "value", "max"),
365 length: defineOwnDataProperty(Object
.create(null), "value", 2),
369 * Returns the lowest value of the provided arguments, or positive
370 * infinity if no argument is provided.
372 * ※ Unlike `Math.min´, this function accepts either number or big·int
373 * values. All values must be of the same type, or this function will
376 * ☡ If no argument is supplied, the result will be a number, not a
379 export const min
= Object
.defineProperties((...$s
) => {
380 let lowest
= UNDEFINED
;
381 for (let i
= 0; i
< $s
.length
; ++i
) {
382 // Iterate over all the numbers.
383 const number
= toNumeric($s
[i
]);
384 if (lowest
=== UNDEFINED
) {
385 // The current number is the first one.
387 // The current number is nan.
390 // The current number is not nan.
394 // The current number is not the first one.
395 if (typeof lowest
!== typeof number
) {
396 // The type of the current number and the lowest number don¦t
398 throw new TypeError(`${PISCĒS}: Type mismatch.`);
399 } else if (isNan(number
)) {
400 // The current number is nan.
402 } else if (sameValue(number
, -0) && sameValue(lowest
, 0)) {
403 // The current number is -0 and the lowest number is +0.
405 } else if (number
< lowest
) {
406 // The current number is less than the lowest number.
409 // The current number is greater than or equal to the lowest
415 return lowest
?? POSITIVE_INFINITY
;
417 name: defineOwnDataProperty(Object
.create(null), "value", "min"),
418 length: defineOwnDataProperty(Object
.create(null), "value", 2),
422 * Returns a pseudo·random value in the range [0, 1).
424 * ※ This function is effectively an alias for `Math.random´.
426 export const rand
= createArrowFunction(
432 * Returns the round of the provided value.
434 * ※ This function is effectively an alias for `Math.round´.
436 * ☡ This function does not allow big·int arguments.
438 export const round
= createArrowFunction(Math
.round
);
441 * Returns a unit value with the same sign as the provided value, or
442 * the provided value itself if it is not a number or (potentially
445 * For big·ints, the return value of this function is 0n if the
446 * provided value is 0n, −1n if the provided value is negative, and +1n
449 * For numbers, the return value is nan, −0, or +0 if the provided
450 * value is nan, −0, or +0, respectively, and −1 if the provided value
451 * is negative and +1 if the provided value is positive otherwise. Note
452 * that positive and negative infinity will return +1 and −1
455 * ※ Unlike `Math.sign´, this function accepts either number or
458 export const sgn
= ($) => {
459 const n
= toNumeric($);
460 return typeof n
=== "bigint"
461 ? n
=== 0n
? 0n : n
< 0n
? -1n : 1n
462 : isNan(n
) || n
=== 0
464 //deno-lint-ignore no-compare-neg-zero
471 * Returns the sin of the provided value.
473 * ※ This function is effectively an alias for `Math.sin´.
475 * ☡ This function does not allow big·int arguments.
477 export const sin
= createArrowFunction(Math
.sin
);
480 * Returns the sinh of the provided value.
482 * ※ This function is effectively an alias for `Math.sinh´.
484 * ☡ This function does not allow big·int arguments.
486 export const sinh
= createArrowFunction(Math
.sinh
);
489 * Returns the square root of the provided value.
491 * ※ This function is effectively an alias for `Math.sqrt´.
493 * ☡ This function does not allow big·int arguments.
495 export const sqrt
= createArrowFunction(Math
.sqrt
);
498 * Returns the tan of the provided value.
500 * ※ This function is effectively an alias for `Math.tan´.
502 * ☡ This function does not allow big·int arguments.
504 export const tan
= createArrowFunction(Math
.tan
);
507 * Returns the tanh of the provided value.
509 * ※ This function is effectively an alias for `Math.tanh´.
511 * ☡ This function does not allow big·int arguments.
513 export const tanh
= createArrowFunction(Math
.tanh
);
516 * Returns the result of converting the provided value to a big·int.
518 * ※ This method is safe to use with numbers.
520 * ※ This is effectively an alias for `BigInt´.
522 export const { toBigInt
} = (() => {
523 const makeBigInt
= BigInt
;
524 return { toBigInt: ($) => makeBigInt($) };
529 * Returns the result of converting the provided value to an
530 * exponential notation string.
532 * If a second argument is provided, it gives the number of
533 * fractional digits to use in the mantissa. Otherwise, the smallest
534 * number which does not result in a reduction in precision is used.
536 * ※ This method is safe to use with big·ints.
538 toExponentialNotation
,
541 * Returns the result of converting the provided value to a fixed
542 * decimal notation string with the provided number of fractional
545 * ※ This method is safe to use with big·ints.
547 toFixedDecimalNotation
,
550 toExponential: numberToExponential
,
551 toFixed: numberToFixed
,
552 } = Number
.prototype;
553 const { toString: bigintToString
} = BigInt
.prototype;
555 toExponentialNotation: ($, fractionDigits
) => {
556 const n
= toNumeric($);
557 const f
= toIntegralNumberOrInfinity(fractionDigits
);
558 if (!isFiniteNumber(f
) || f
< 0 || f
> 100) {
559 throw new RangeError(
560 `${PISCĒS}: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`,
563 if (typeof n
=== "number") {
567 [fractionDigits
=== UNDEFINED
? fractionDigits : f
],
570 const digits
= call(bigintToString
, n
, [10]);
571 const { length
} = digits
;
572 if (fractionDigits
=== UNDEFINED
) {
575 : `${digits[0]}.${substring(digits, 1)}e+${length - 1}`;
576 } else if (f
=== 0) {
577 return `${digits[0]}e+0`;
579 const fractionalPart
= toString(
582 stringPadEnd(substring(digits
, 1, f
+ 1), f
, "0"),
584 digits
[f
+ 1] || "0",
588 return `${digits[0]}.${fractionalPart}e+${length - 1}`;
593 toFixedDecimalNotation: ($, fractionDigits
) => {
594 const f
= toIntegralNumberOrInfinity(fractionDigits
);
595 if (!isFiniteNumber(f
) || f
< 0 || f
> 100) {
596 throw new RangeError(
597 `${PISCĒS}: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`,
600 const n
= toNumeric($);
601 if (typeof n
=== "number") {
602 return call(numberToFixed
, n
, [f
]);
604 const digits
= call(bigintToString
, n
, [10]);
607 : `${digits}.${stringRepeat("0", f)}`;
615 * Returns the result of converting the provided number to an integral
618 * ※ This function will never return negative zero.
620 export const toIntegralNumber
= ($) => {
621 const n
= toIntegralNumberOrInfinity($);
622 return !isFiniteNumber(n
) || n
== 0 ? 0 : n
;
626 * Returns the result of converting the provided number to an integer
629 * ※ Unlike the ToIntegerOrInfinity function defined in the Ecmascript
630 * specification, this function is safe to use with big·ints. However,
631 * the result will always be a number.
633 * ※ This function will never return negative zero.
635 export const toIntegralNumberOrInfinity
= ($) => {
636 const integer
= trunc(toNumber($));
637 if (isNan(integer
) || integer
== 0) {
638 // The provided value truncs to nan or (positive or negative) zero.
640 } else if (integer
== POSITIVE_INFINITY
) {
641 // The provided value truncs to positive infinity.
642 return POSITIVE_INFINITY
;
643 } else if (integer
== NEGATIVE_INFINITY
) {
644 // The provided value truncs to negative infinity.
645 return NEGATIVE_INFINITY
;
647 // The provided value truncs to an integer.
653 * Returns the result of converting the provided value to a number.
655 * ※ This function is safe to use with big·ints.
657 * ※ This is effectively a nonconstructible version of the `Number´
660 export const toNumber
= createArrowFunction(
662 { name: "toNumber" },
666 * Returns the result of converting the provided value to a number or
669 * ※ If the result of converting the provided value to a primitive is
670 * not a big·int, this function will return a number.
672 export const toNumeric
= ($) => {
673 const primValue
= toPrimitive($, "number");
674 return typeof primValue
=== "bigint" ? primValue : +primValue
;
679 * Returns the result of converting the provided value to fit within
680 * the provided number of bits as a signed integer.
682 * ※ Unlike `BigInt.asIntN´, this function accepts both big·int and
685 * ☡ The first argument, the number of bits, must be a number.
687 toSignedIntegralNumeric
,
690 * Returns the result of converting the provided value to fit within
691 * the provided number of bits as an unsigned integer.
693 * ※ Unlike `BigInt.asUintN´, this function accepts both big·int and
696 * ☡ The first argument, the number of bits, must be a number.
698 toUnsignedIntegralNumeric
,
700 const { asIntN
, asUintN
} = BigInt
;
702 toSignedIntegralNumeric: (n
, $) => {
703 const prim
= toPrimitive($);
704 if (typeof prim
=== "bigint") {
705 // The primitive value is a big·int.
706 return asIntN(n
, prim
);
708 // The primitive value is not a big·int.
709 const int = trunc(prim
);
710 if (!isFiniteNumber(int) || int == 0) {
711 // The truncated value is zero or not finite.
714 // The truncated value is finite.
715 return toNumber(asIntN(n
, toBigInt(int)));
719 toUnsignedIntegralNumeric: (n
, $) => {
720 const prim
= toPrimitive($);
721 if (typeof prim
=== "bigint") {
722 // The primitive value is a big·int.
723 return asUintN(n
, prim
);
725 // The primitive value is not a big·int.
726 const int = trunc(prim
);
727 if (!isFiniteNumber(int) || int == 0) {
728 // The truncated value is zero or not finite.
731 // The truncated value is finite.
732 return toNumber(asUintN(n
, toBigInt(int)));
740 * Returns the trunc of the provided value.
742 * ※ This function is effectively an alias for `Math.trunc´.
744 * ☡ This function does not allow big·int arguments.
746 export const trunc
= createArrowFunction(Math
.trunc
);