X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/8fcb8f6d937fadd7aa8016f8ba33004d1bd79bf0..2e6fac40384b2e17dd3a6b8700abc787b0b57479:/numeric.js diff --git a/numeric.js b/numeric.js index 44c7cd5..c4d07f8 100644 --- a/numeric.js +++ b/numeric.js @@ -1,386 +1,39 @@ -// ♓🌟 Piscēs ∷ numeric.js -// ==================================================================== -// -// Copyright © 2022 Lady [@ Lady’s Computer]. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at . - -import { sameValue, toPrimitive } from "./value.js"; - -export const { - /** - * ln(10). - * - * ※ This is an alias for Math.LN10. - */ - LN10, - - /** - * ln(2). - * - * ※ This is an alias for Math.LN2. - */ - LN2, - - /** - * log10(ℇ). - * - * ※ This is an alias for Math.LOG10E. - */ - LOG10E: LOG10ℇ, - - /** - * log2(ℇ). - * - * ※ This is an alias for Math.LOG2E. - */ - LOG2E: LOG2ℇ, - - /** - * sqrt(.5). - * - * ※ This is an alias for Math.SQRT1_2. - */ - SQRT1_2: RECIPROCAL_SQRT2, - - /** - * sqrt(2). - * - * ※ This is an alias for Math.SQRT2. - */ - SQRT2, - - /** - * Returns the arccos of the provided value. - * - * ※ This is an alias for Math.acos. - * - * ☡ This function does not allow big·int arguments. - */ - acos: arccos, - - /** - * Returns the arccosh of the provided value. - * - * ※ This is an alias for Math.acosh. - * - * ☡ This function does not allow big·int arguments. - */ - acosh: arccosh, - - /** - * Returns the arcsin of the provided value. - * - * ※ This is an alias for Math.asin. - * - * ☡ This function does not allow big·int arguments. - */ - asin: arcsin, - - /** - * Returns the arcsinh of the provided value. - * - * ※ This is an alias for Math.asinh. - * - * ☡ This function does not allow big·int arguments. - */ - asinh: arcsinh, - - /** - * Returns the arctan of the provided value. - * - * ※ This is an alias for Math.atan. - * - * ☡ This function does not allow big·int arguments. - */ - atan: arctan, - - /** - * Returns the arctanh of the provided value. - * - * ※ This is an alias for Math.atanh. - * - * ☡ This function does not allow big·int arguments. - */ - atanh: arctanh, - - /** - * Returns the cube root of the provided value. - * - * ※ This is an alias for Math.cbrt. - * - * ☡ This function does not allow big·int arguments. - */ - cbrt, - - /** - * Returns the ceiling of the provided value. - * - * ※ This is an alias for Math.ceil. - * - * ☡ This function does not allow big·int arguments. - */ - ceil, - - /** - * Returns the cos of the provided value. - * - * ※ This is an alias for Math.cos. - * - * ☡ This function does not allow big·int arguments. - */ - cos, - - /** - * Returns the cosh of the provided value. - * - * ※ This is an alias for Math.cosh. - * - * ☡ This function does not allow big·int arguments. - */ - cosh, - - /** - * Returns the Euler number raised to the provided value. - * - * ※ This is an alias for Math.exp. - * - * ☡ This function does not allow big·int arguments. - */ - exp, - - /** - * Returns the Euler number raised to the provided value, minus one. - * - * ※ This is an alias for Math.expm1. - * - * ☡ This function does not allow big·int arguments. - */ - expm1, - - /** - * Returns the floor of the provided value. - * - * ※ This is an alias for Math.floor. - * - * ☡ This function does not allow big·int arguments. - */ - floor, - - /** - * Returns the square root of the sum of the squares of the provided - * arguments. - * - * ※ This is an alias for Math.hypot. - * - * ☡ This function does not allow big·int arguments. - */ - hypot, - - /** - * Returns the ln of the provided value. - * - * ※ This is an alias for Math.log. - * - * ☡ This function does not allow big·int arguments. - */ - log: ln, - - /** - * Returns the log10 of the provided value. - * - * ※ This is an alias for Math.log10. - * - * ☡ This function does not allow big·int arguments. - */ - log10, - - /** - * Returns the ln of one plus the provided value. - * - * ※ This is an alias for Math.log1p. - * - * ☡ This function does not allow big·int arguments. - */ - log1p: ln1p, - - /** - * Returns the log2 of the provided value. - * - * ※ This is an alias for Math.log2. - * - * ☡ This function does not allow big·int arguments. - */ - log2, - - /** - * Returns a pseudo·random value in the range [0, 1). - * - * ※ This is an alias for Math.random. - */ - random: rand, - - /** - * Returns the round of the provided value. - * - * ※ This is an alias for Math.round. - * - * ☡ This function does not allow big·int arguments. - */ - round, - - /** - * Returns the sinh of the provided value. - * - * ※ This is an alias for Math.sinh. - * - * ☡ This function does not allow big·int arguments. - */ - sinh, - - /** - * Returns the square root of the provided value. - * - * ※ This is an alias for Math.sqrt. - * - * ☡ This function does not allow big·int arguments. - */ - sqrt, - - /** - * Returns the tan of the provided value. - * - * ※ This is an alias for Math.tan. - * - * ☡ This function does not allow big·int arguments. - */ - tan, - - /** - * Returns the tanh of the provided value. - * - * ※ This is an alias for Math.tanh. - * - * ☡ This function does not allow big·int arguments. - */ - tanh, - - /** - * Returns the trunc of the provided value. - * - * ※ This is an alias for Math.trunc. - * - * ☡ This function does not allow big·int arguments. - */ - trunc, - - /** - * The mathematical constant π. - * - * ※ This is an alias for Math.PI. - */ - PI: Π, - - /** - * The Euler number. - * - * ※ This is an alias for Math.E. - */ - E: ℇ, -} = Math; - -export const { - /** - * The largest number value less than infinity. - * - * ※ This is an alias for Number.MAX_VALUE. - */ - MAX_VALUE: MAXIMUM_NUMBER, - - /** - * 2**53 - 1. - * - * ※ This is an alias for Number.MAX_SAFE_INTEGER. - */ - MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER, - - /** - * The smallest number value greater than negative infinity. - * - * ※ This is an alias for Number.MIN_VALUE. - */ - MIN_VALUE: MINIMUM_NUMBER, - - /** - * -(2**53 - 1). - * - * ※ This is an alias for Number.MIN_SAFE_INTEGER. - */ - MIN_SAFE_INTEGER: MINIMUM_SAFE_INTEGRAL_NUMBER, +// SPDX-FileCopyrightText: 2022, 2023, 2025 Lady +// SPDX-License-Identifier: MPL-2.0 +/** + * ⁌ ♓🧩 Piscēs ∷ numeric.js + * + * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer]. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . + */ - /** - * Negative infinity. - * - * ※ This is an alias for Number.NEGATIVE_INFINITY. - */ +import { call, createArrowFunction } from "./function.js"; +import { defineOwnDataProperty } from "./object.js"; +import { + stringCatenate, + stringPadEnd, + stringRepeat, + substring, + toString, +} from "./string.js"; +import { + NAN, NEGATIVE_INFINITY, - - /** - * Nan. - * - * ※ This is an alias for Number.NaN. - */ - NaN: NAN, - - /** - * Positive infinity. - * - * ※ This is an alias for Number.POSITIVE_INFINITY. - */ POSITIVE_INFINITY, + sameValue, + toPrimitive, + UNDEFINED, +} from "./value.js"; - /** - * The difference between 1 and the smallest number greater than 1. - * - * ※ This is an alias for Number.EPSILON. - */ - EPSILON: Ε, - - /** - * Returns whether the provided value is a finite number. - * - * ※ This is an alias for Number.isFinite. - */ - isFinite: isFiniteNumber, - - /** - * Returns whether the provided value is an integral number. - * - * ※ This is an alias for Number.isInteger. - */ - isInteger: isIntegralNumber, - - /** - * Returns whether the provided value is nan. - * - * ※ This is an alias for Number.isNaN. - */ - isNaN: isNan, - - /** - * Returns whether the provided value is a safe integral number. - * - * ※ This is an alias for Number.isSafeInteger. - */ - isSafeInteger: isSafeIntegralNumber, -} = Number; +const PISCĒS = "♓🧩 Piscēs"; /** * Returns the magnitude (absolute value) of the provided value. * - * ※ Unlike Math.abs, this function can take big·int arguments. + * ※ Unlike `Math.abs´, this function can take big·int arguments. */ export const abs = ($) => { const n = toNumeric($); @@ -397,21 +50,81 @@ export const abs = ($) => { : n; }; +/** + * Returns the arccos of the provided value. + * + * ※ This function is effectively an alias for `Math.acos´. + * + * ☡ This function does not allow big·int arguments. + */ +export const arccos = createArrowFunction( + Math.acos, + { name: "arccos" }, +); + +/** + * Returns the arccosh of the provided value. + * + * ※ This function is effectively an alias for `Math.acosh´. + * + * ☡ This function does not allow big·int arguments. + */ +export const arccosh = createArrowFunction( + Math.acosh, + { name: "arccosh" }, +); + +/** + * Returns the arcsin of the provided value. + * + * ※ This function is effectively an alias for `Math.asin´. + * + * ☡ This function does not allow big·int arguments. + */ +export const arcsin = createArrowFunction( + Math.asin, + { name: "arcsin" }, +); + +/** + * Returns the arcsinh of the provided value. + * + * ※ This function is effectively an alias for `Math.asinh´. + * + * ☡ This function does not allow big·int arguments. + */ +export const arcsinh = createArrowFunction( + Math.asinh, + { name: "arcsinh" }, +); + +/** + * Returns the arctan of the provided value. + * + * ※ This function is effectively an alias for `Math.atan´. + * + * ☡ This function does not allow big·int arguments. + */ +export const arctan = createArrowFunction( + Math.atan, + { name: "arctan" }, +); + export const { /** * Returns the arctangent of the dividend of the provided values. * - * ※ Unlike Math.atan2, this function can take big·int arguments. + * ※ Unlike `Math.atan2´, this function can take big·int arguments. * However, the result will always be a number. */ - atan2, + arctan2, /** - * Returns the number of leading zeroes in the 32‐bit representation of - * the provided value. + * Returns the number of leading zeroes in the 32‐bit representation + * of the provided value. * - * ※ Unlike Math.clz32, this function accepts either number or big·int - * values. + * ※ Unlike `Math.clz32´, this function accepts either number or + * big·int values. */ clz32, @@ -419,41 +132,204 @@ export const { * Returns the 32‐bit float which best approximate the provided * value. * - * ※ Unlike Math.fround, this function can take big·int arguments. + * ※ Unlike `Math.fround´, this function can take big·int arguments. * However, the result will always be a number. */ toFloat32, } = (() => { const { atan2, fround, clz32 } = Math; return { - atan2: (y, x) => atan2(toNumber(y), toNumber(x)), + arctan2: (y, x) => atan2(toNumber(y), toNumber(x)), clz32: ($) => { const n = toNumeric($); return clz32( - typeof n === "bigint" ? toNumber(toUintN(32, n)) : n, + typeof n === "bigint" + ? toNumber(toUnsignedIntegralNumeric(32, n)) + : n, ); }, toFloat32: ($) => fround(toNumber($)), }; })(); +/** + * Returns the arctanh of the provided value. + * + * ※ This function is effectively an alias for `Math.atanh´. + * + * ☡ This function does not allow big·int arguments. + */ +export const arctanh = createArrowFunction( + Math.atanh, + { name: "arctanh" }, +); + +/** + * Returns the cube root of the provided value. + * + * ※ This function is effectively an alias for `Math.cbrt´. + * + * ☡ This function does not allow big·int arguments. + */ +export const cbrt = createArrowFunction(Math.cbrt); + +/** + * Returns the ceiling of the provided value. + * + * ※ This function is effectively an alias for `Math.ceil´. + * + * ☡ This function does not allow big·int arguments. + */ +export const ceil = createArrowFunction(Math.ceil); + +/** + * Returns the cos of the provided value. + * + * ※ This function is effectively an alias for `Math.cos´. + * + * ☡ This function does not allow big·int arguments. + */ +export const cos = createArrowFunction(Math.cos); + +/** + * Returns the cosh of the provided value. + * + * ※ This function is effectively an alias for `Math.cosh´. + * + * ☡ This function does not allow big·int arguments. + */ +export const cosh = createArrowFunction(Math.cosh); + +/** + * Returns the Euler number raised to the provided value. + * + * ※ This function is effectively an alias for `Math.exp´. + * + * ☡ This function does not allow big·int arguments. + */ +export const exp = createArrowFunction(Math.exp); + +/** + * Returns the Euler number raised to the provided value, minus one. + * + * ※ This function is effectively an alias for `Math.expm1´. + * + * ☡ This function does not allow big·int arguments. + */ +export const expm1 = createArrowFunction(Math.expm1); + +/** + * Returns the floor of the provided value. + * + * ※ This function is effectively an alias for `Math.floor´. + * + * ☡ This function does not allow big·int arguments. + */ +export const floor = createArrowFunction(Math.floor); + +/** + * Returns the square root of the sum of the squares of the provided + * arguments. + * + * ※ This function is effectively an alias for `Math.hypot´. + * + * ☡ This function does not allow big·int arguments. + */ +export const hypot = createArrowFunction(Math.hypot); + +/** + * Returns whether the provided value is a finite number. + * + * ※ This function is effectively an alias for `Number.isFinite´. + */ +export const isFiniteNumber = createArrowFunction( + Number.isFinite, + { name: "isFiniteNumber" }, +); + +/** + * Returns whether the provided value is an integral number. + * + * ※ This function is effectively an alias for `Number.isInteger´. + */ +export const isIntegralNumber = createArrowFunction( + Number.isInteger, + { name: "isIntegralNumber" }, +); + +/** + * Returns whether the provided value is nan. + * + * ※ This function is effectively an alias for `Number.isNaN´. + */ +export const isNan = createArrowFunction( + Number.isNaN, + { name: "isNan" }, +); + +/** + * Returns whether the provided value is a safe integral number. + * + * ※ This function is effectively an alias for `Number.isSafeInteger´. + */ +export const isSafeIntegralNumber = createArrowFunction( + Number.isSafeInteger, + { name: "isSafeIntegralNumber" }, +); + +/** + * Returns the ln of the provided value. + * + * ※ This function is effectively an alias for `Math.log´. + * + * ☡ This function does not allow big·int arguments. + */ +export const ln = createArrowFunction(Math.log, { name: "ln" }); + +/** + * Returns the ln of one plus the provided value. + * + * ※ This function is effectively an alias for `Math.log1p´. + * + * ☡ This function does not allow big·int arguments. + */ +export const ln1p = createArrowFunction(Math.log1p, { name: "ln1p" }); + +/** + * Returns the log10 of the provided value. + * + * ※ This function is effectively an alias for `Math.log10´. + * + * ☡ This function does not allow big·int arguments. + */ +export const log10 = createArrowFunction(Math.log10); + +/** + * Returns the log2 of the provided value. + * + * ※ This function is effectively an alias for `Math.log2´. + * + * ☡ This function does not allow big·int arguments. + */ +export const log2 = createArrowFunction(Math.log2); + /** * Returns the highest value of the provided arguments, or negative * infinity if no argument is provided. * - * ※ Unlike Math.max, this function accepts either number or big·int + * ※ Unlike `Math.max´, this function accepts either number or big·int * values. All values must be of the same type, or this function will * throw an error. * * ☡ If no argument is supplied, the result will be a number, not a * big·int. */ -export const max = (...$s) => { - let highest = undefined; +export const max = Object.defineProperties((...$s) => { + let highest = UNDEFINED; for (let i = 0; i < $s.length; ++i) { // Iterate over all the numbers. const number = toNumeric($s[i]); - if (highest === undefined) { + if (highest === UNDEFINED) { // The current number is the first one. if (isNan(number)) { // The current number is nan. @@ -464,16 +340,16 @@ export const max = (...$s) => { } } else { if (typeof highest !== typeof number) { - // The type of the current number and the lowest number don’t + // The type of the current number and the lowest number don¦t // match. - throw new TypeError("Piscēs: Type mismatch."); + throw new TypeError(`${PISCĒS}: Type mismatch.`); } else if (isNan(number)) { // The current number is nan. return NAN; } else if (sameValue(number, 0) && sameValue(highest, -0)) { // The current number is +0 and the highest number is -0. highest = 0; - } else if (highest === undefined || number > highest) { + } else if (number > highest) { // The current number is greater than the highest number. highest = number; } else { @@ -484,25 +360,28 @@ export const max = (...$s) => { } } return highest ?? NEGATIVE_INFINITY; -}; +}, { + name: defineOwnDataProperty(Object.create(null), "value", "max"), + length: defineOwnDataProperty(Object.create(null), "value", 2), +}); /** * Returns the lowest value of the provided arguments, or positive * infinity if no argument is provided. * - * ※ Unlike Math.min, this function accepts either number or big·int + * ※ Unlike `Math.min´, this function accepts either number or big·int * values. All values must be of the same type, or this function will * throw an error. * * ☡ If no argument is supplied, the result will be a number, not a * big·int. */ -export const min = (...$s) => { - let lowest = undefined; +export const min = Object.defineProperties((...$s) => { + let lowest = UNDEFINED; for (let i = 0; i < $s.length; ++i) { // Iterate over all the numbers. const number = toNumeric($s[i]); - if (lowest === undefined) { + if (lowest === UNDEFINED) { // The current number is the first one. if (isNan(number)) { // The current number is nan. @@ -514,9 +393,9 @@ export const min = (...$s) => { } else { // The current number is not the first one. if (typeof lowest !== typeof number) { - // The type of the current number and the lowest number don’t + // The type of the current number and the lowest number don¦t // match. - throw new TypeError("Piscēs: Type mismatch."); + throw new TypeError(`${PISCĒS}: Type mismatch.`); } else if (isNan(number)) { // The current number is nan. return NAN; @@ -534,7 +413,29 @@ export const min = (...$s) => { } } return lowest ?? POSITIVE_INFINITY; -}; +}, { + name: defineOwnDataProperty(Object.create(null), "value", "min"), + length: defineOwnDataProperty(Object.create(null), "value", 2), +}); + +/** + * Returns a pseudo·random value in the range [0, 1). + * + * ※ This function is effectively an alias for `Math.random´. + */ +export const rand = createArrowFunction( + Math.random, + { name: "rand" }, +); + +/** + * Returns the round of the provided value. + * + * ※ This function is effectively an alias for `Math.round´. + * + * ☡ This function does not allow big·int arguments. + */ +export const round = createArrowFunction(Math.round); /** * Returns a unit value with the same sign as the provided value, or @@ -542,17 +443,17 @@ export const min = (...$s) => { * signed) zero. * * For big·ints, the return value of this function is 0n if the - * provided value is 0n, -1n if the provided value is negative, and +1n + * provided value is 0n, −1n if the provided value is negative, and +1n * otherwise. * - * For numbers, the return value is nan, -0, or +0 if the provided - * value is nan, -0, or +0, respectively, and -1 if the provided value + * For numbers, the return value is nan, −0, or +0 if the provided + * value is nan, −0, or +0, respectively, and −1 if the provided value * is negative and +1 if the provided value is positive otherwise. Note - * that positive and negative infinity will return +1 and -1 + * that positive and negative infinity will return +1 and −1 * respectively. * - * ※ Unlike Math.sign, this function accepts either number or big·int - * values. + * ※ Unlike `Math.sign´, this function accepts either number or + * big·int values. */ export const sgn = ($) => { const n = toNumeric($); @@ -560,18 +461,63 @@ export const sgn = ($) => { ? n === 0n ? 0n : n < 0n ? -1n : 1n : isNan(n) || n === 0 ? n - : //deno-lint-ignore no-compare-neg-zero - n < -0 - ? -1 - : 1; + //deno-lint-ignore no-compare-neg-zero + : n < -0 + ? -1 + : 1; }; +/** + * Returns the sin of the provided value. + * + * ※ This function is effectively an alias for `Math.sin´. + * + * ☡ This function does not allow big·int arguments. + */ +export const sin = createArrowFunction(Math.sin); + +/** + * Returns the sinh of the provided value. + * + * ※ This function is effectively an alias for `Math.sinh´. + * + * ☡ This function does not allow big·int arguments. + */ +export const sinh = createArrowFunction(Math.sinh); + +/** + * Returns the square root of the provided value. + * + * ※ This function is effectively an alias for `Math.sqrt´. + * + * ☡ This function does not allow big·int arguments. + */ +export const sqrt = createArrowFunction(Math.sqrt); + +/** + * Returns the tan of the provided value. + * + * ※ This function is effectively an alias for `Math.tan´. + * + * ☡ This function does not allow big·int arguments. + */ +export const tan = createArrowFunction(Math.tan); + +/** + * Returns the tanh of the provided value. + * + * ※ This function is effectively an alias for `Math.tanh´. + * + * ☡ This function does not allow big·int arguments. + */ +export const tanh = createArrowFunction(Math.tanh); + /** * Returns the result of converting the provided value to a big·int. * * ※ This method is safe to use with numbers. * - * ※ This is effectively an alias for BigInt. + * ※ This is effectively an alias for `BigInt´. */ export const { toBigInt } = (() => { const makeBigInt = BigInt; @@ -580,52 +526,114 @@ export const { toBigInt } = (() => { export const { /** - * Returns the result of converting the provided value to fit within - * the provided number of bits as a signed integer. + * Returns the result of converting the provided value to an + * exponential notation string. * - * ※ Unlike BigInt.asIntN, this function accepts both big·int and - * number values. + * If a second argument is provided, it gives the number of + * fractional digits to use in the mantissa. Otherwise, the smallest + * number which does not result in a reduction in precision is used. * - * ☡ The first argument, the number of bits, must be a number. + * ※ This method is safe to use with big·ints. */ - toIntN, + toExponentialNotation, /** - * Returns the result of converting the provided value to fit within - * the provided number of bits as an unsigned integer. + * Returns the result of converting the provided value to a fixed + * decimal notation string with the provided number of fractional + * digits. * - * ※ Unlike BigInt.asUintN, this function accepts both big·int and - * number values. - * - * ☡ The first argument, the number of bits, must be a number. + * ※ This method is safe to use with big·ints. */ - toUintN, + toFixedDecimalNotation, } = (() => { - const { asIntN, asUintN } = BigInt; + const { + toExponential: numberToExponential, + toFixed: numberToFixed, + } = Number.prototype; + const { toString: bigintToString } = BigInt.prototype; return { - toIntN: (n, $) => { - const prim = toPrimitive($); - const big·int = toBigInt(prim); - const intN = asIntN(n, big·int); - return typeof prim === "bigint" ? intN : toNumber(intN); + toExponentialNotation: ($, fractionDigits) => { + const n = toNumeric($); + const f = toIntegralNumberOrInfinity(fractionDigits); + if (!isFiniteNumber(f) || f < 0 || f > 100) { + throw new RangeError( + `${PISCĒS}: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`, + ); + } else { + if (typeof n === "number") { + return call( + numberToExponential, + n, + [fractionDigits === UNDEFINED ? fractionDigits : f], + ); + } else { + const digits = call(bigintToString, n, [10]); + const { length } = digits; + if (fractionDigits === UNDEFINED) { + return length === 1 + ? `${digits[0]}e+0` + : `${digits[0]}.${substring(digits, 1)}e+${length - 1}`; + } else if (f === 0) { + return `${digits[0]}e+0`; + } else { + const fractionalPart = toString( + round( + +stringCatenate( + stringPadEnd(substring(digits, 1, f + 1), f, "0"), + ".", + digits[f + 1] || "0", + ), + ), + ); + return `${digits[0]}.${fractionalPart}e+${length - 1}`; + } + } + } }, - toUintN: (n, $) => { - const prim = toPrimitive($); - const big·int = toBigInt(prim); - const uintN = asUintN(n, big·int); - return typeof prim === "bigint" ? uintN : toNumber(uintN); + toFixedDecimalNotation: ($, fractionDigits) => { + const f = toIntegralNumberOrInfinity(fractionDigits); + if (!isFiniteNumber(f) || f < 0 || f > 100) { + throw new RangeError( + `${PISCĒS}: The number of fractional digits must be a finite number between 0 and 100 inclusive; got: ${f}.`, + ); + } else { + const n = toNumeric($); + if (typeof n === "number") { + return call(numberToFixed, n, [f]); + } else { + const digits = call(bigintToString, n, [10]); + return f === 0 + ? digits + : `${digits}.${stringRepeat("0", f)}`; + } + } }, }; })(); +/** + * Returns the result of converting the provided number to an integral + * number. + * + * ※ This function will never return negative zero. + */ +export const toIntegralNumber = ($) => { + const n = toIntegralNumberOrInfinity($); + return !isFiniteNumber(n) || n == 0 ? 0 : n; +}; + /** * Returns the result of converting the provided number to an integer * or infinity. * - * ☡ This function does not allow big·int arguments. + * ※ Unlike the ToIntegerOrInfinity function defined in the Ecmascript + * specification, this function is safe to use with big·ints. However, + * the result will always be a number. + * + * ※ This function will never return negative zero. */ -export const toIntegerOrInfinity = ($) => { - const integer = trunc($); +export const toIntegralNumberOrInfinity = ($) => { + const integer = trunc(toNumber($)); if (isNan(integer) || integer == 0) { // The provided value truncs to nan or (positive or negative) zero. return 0; @@ -644,15 +652,15 @@ export const toIntegerOrInfinity = ($) => { /** * Returns the result of converting the provided value to a number. * - * ※ This method is safe to use with big·ints. + * ※ This function is safe to use with big·ints. * - * ※ This is effectively a nonconstructible version of the Number + * ※ This is effectively a nonconstructible version of the `Number´ * constructor. */ -export const { toNumber } = (() => { - const makeNumber = Number; - return { toNumber: ($) => makeNumber($) }; -})(); +export const toNumber = createArrowFunction( + Number, + { name: "toNumber" }, +); /** * Returns the result of converting the provided value to a number or @@ -665,3 +673,74 @@ export const toNumeric = ($) => { const primValue = toPrimitive($, "number"); return typeof primValue === "bigint" ? primValue : +primValue; }; + +export const { + /** + * Returns the result of converting the provided value to fit within + * the provided number of bits as a signed integer. + * + * ※ Unlike `BigInt.asIntN´, this function accepts both big·int and + * number values. + * + * ☡ The first argument, the number of bits, must be a number. + */ + toSignedIntegralNumeric, + + /** + * Returns the result of converting the provided value to fit within + * the provided number of bits as an unsigned integer. + * + * ※ Unlike `BigInt.asUintN´, this function accepts both big·int and + * number values. + * + * ☡ The first argument, the number of bits, must be a number. + */ + toUnsignedIntegralNumeric, +} = (() => { + const { asIntN, asUintN } = BigInt; + return { + toSignedIntegralNumeric: (n, $) => { + const prim = toPrimitive($); + if (typeof prim === "bigint") { + // The primitive value is a big·int. + return asIntN(n, prim); + } else { + // The primitive value is not a big·int. + const int = trunc(prim); + if (!isFiniteNumber(int) || int == 0) { + // The truncated value is zero or not finite. + return 0; + } else { + // The truncated value is finite. + return toNumber(asIntN(n, toBigInt(int))); + } + } + }, + toUnsignedIntegralNumeric: (n, $) => { + const prim = toPrimitive($); + if (typeof prim === "bigint") { + // The primitive value is a big·int. + return asUintN(n, prim); + } else { + // The primitive value is not a big·int. + const int = trunc(prim); + if (!isFiniteNumber(int) || int == 0) { + // The truncated value is zero or not finite. + return 0; + } else { + // The truncated value is finite. + return toNumber(asUintN(n, toBigInt(int))); + } + } + }, + }; +})(); + +/** + * Returns the trunc of the provided value. + * + * ※ This function is effectively an alias for `Math.trunc´. + * + * ☡ This function does not allow big·int arguments. + */ +export const trunc = createArrowFunction(Math.trunc);