diff --git a/README.md b/README.md deleted file mode 100644 index ff1f904..0000000 --- a/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# EsoMath - -## Intro - -Most math libs are focused on arithmetic and algebra, and practical applications like cryptography. This lib is targeted at Pure Math, Number Theory, and recreational math. - -## Usage - -If you want to import individual modules, import from [`lib`](./src/lib). If you want the whole lib, import [main `index`](./src/index.js). The [`mod`](./src/mod) dir is for *internal use* only, **don't import** it. - -## ⚠DISCLAIMER - -This is still in the process of migrating from IIFE format to ESM format, so currently **A LOT** of files in this repo are unfinished, in need of refactoring, or all at the same time (sorry lol). If you're unsure and want to avoid problems, just read the Issues tab, most bugs and unfinished stuff are described there. - -The API is **extremely unstable** right now, expect many breaking changes. - -I'll remove a lot of features, to keep only the stuff that hasn't been already done. See [issue 32](https://github.com/Rudxain/NTML.js/issues/32). diff --git a/src/lib/decay.js b/src/lib/decay.js index 915de61..0390254 100644 --- a/src/lib/decay.js +++ b/src/lib/decay.js @@ -1,7 +1,9 @@ import {isBigInt as isIntN} from '../mod/type check' import {signabs} from '../mod/std' -//Division by repeated subtraction, but the divisor gets decremented each iteration +/** +Division by repeated subtraction, but the divisor gets decremented each iteration +*/ export const decayDiv = (n, d) => { [n, d] = [signabs(n), signabs(d)] @@ -41,4 +43,4 @@ export const decayMult0 = (f, d) => { const decayMult1 = (f, m) => { } -*/ \ No newline at end of file +*/ diff --git a/src/mod/std.js b/src/mod/std.js deleted file mode 100644 index fe5aee3..0000000 --- a/src/mod/std.js +++ /dev/null @@ -1,109 +0,0 @@ -import '../typedefs' -import { isInt, isNegZero } from './value check' -import { autoN } from './sanitize' -import { trunc, floor } from '../lib/rounding' - -const IntN = BigInt, lb = Math.log2 //in general, lb has better precision and performance than ln - -/** -absolute value -@template {numeric} T -@param {T} x -*/ -export const abs = x => /**@type {T}*/(x < 0 || isNegZero(x) ? -x : x) - -/** -@template {numeric} T -@param {T} x -@return {T} -*/ -export const sign = x => x == 0 ? autoN(0, x) : (x < 0 ? autoN(-1, x) : autoN(1, x)) - -/** -get a 2-tuple with both the sign and absolute value of `x`. similar to `divrem` -@template {numeric} T -@param {T} x -@return {[T, T]} -*/ -export const signabs = x => [sign(x), abs(x)] - -/** -calculate truncated division with remainder, returning both values in a 2-tuple -@template {numeric} T -@param {T} n dividend/numerator -@param {T} d divisor/denominator -*/ -export const divrem = (n, d) => /**@type {[T, T]}*/([trunc(n / d), n % d]) - -/** -calculate Euclidean division with remainder, returning both values in a 2-tuple. - -Currently, this is incorrect for `BigInt`s -@template {numeric} T -@param {T} n dividend/numerator -@param {T} d divisor/denominator -*/ -export const divEuclid = (n, d) => /**@type {T}*/(floor(n / abs(d)) * sign(d)) - -/** -@param {*} x -*/ -export const isEven = x => isInt(x) && x % autoN(2, x) == 0 - -/** -@param {*} x -*/ -export const isOdd = x => isInt(x) && x % autoN(2, x) != 0 - -/** -@template {numstr} T -@param {T} x -@param {T} min -@param {T} max -*/ -export const clamp = (x, min, max) => x > max ? max : x < min ? min : x - -/** -@template {NumberConstructor | BigIntConstructor | StringConstructor} T -@param {numstr[]} arr values to compare -@param {boolean} op falsy: min, truthy: max -@param {T} f type coercion fn -*/ -export const minmax = (arr, op, f) => { - let i = 0 - let v = /**@type {T extends NumberConstructor ? number : T extends BigIntConstructor ? bigint : string}*/( - f(arr[i]) - ) - let m = v - while (++i < arr.length) { - v = /**@type {T extends NumberConstructor ? number : T extends BigIntConstructor ? bigint : string}*/( - f(arr[i]) - ) - if (op ? v > m : v < m) m = v - } - return m -} - -/** -Logarithm in any base -@template {numeric} T -@param {T} x get exponent of this -@param {T} b base of logarithm -@return {T extends number ? number : numeric} -*/ -export const logB = (x, b) => { - //@ts-ignore - if (x < 0 || b == 0 || b == 1) return NaN - //@ts-ignore - if (x == 0) return -Infinity - //@ts-ignore - if (x == 1) return autoN(0, x) - //@ts-ignore - if (typeof x != 'bigint') return lb(x) / lb(b) - - const b_int = IntN(b) - let i = 0n - while (/**@type {bigint}*/(x) /= b_int) i++ - //@ts-ignore - return i -} \ No newline at end of file diff --git a/src/mod/std.ts b/src/mod/std.ts new file mode 100644 index 0000000..f1057b1 --- /dev/null +++ b/src/mod/std.ts @@ -0,0 +1,94 @@ +import '../typedefs' +import { isInt, isNegZero } from './value-check' +import { autoN } from './sanitize' +import { trunc, floor } from '../lib/rounding' + +const IntN = BigInt, lb = Math.log2 + +export class AssertionError extends Error { + constructor(msg = "") { + super(msg); + this.name = AssertionError.name; + } +} + +/** +{@link https://es.discourse.group/t/error-assert/356} +*/ +export function assert(p: boolean, msg = ""): asserts p { + if (!p) throw new AssertionError(msg); +} + +/** +absolute value +*/ +export function abs(x: number): number +export function abs(x: bigint): bigint +export function abs(x: numeric): numeric +export function abs(x: numeric) { + return (x < 0 || isNegZero(x) ? -x : x) +} +export function sign(x: number): -1 | -0 | 0 | 1 | typeof NaN +export function sign(x: bigint): -1n | 0n | 1n +export function sign(x: numeric): -1 | -1n | -0 | 0 | 0n | 1 | 1n | typeof NaN +export function sign(x: numeric) { + return x == 0 ? autoN(0, x as 0 | 0n) : (x < 0 ? autoN(-1, x) : autoN(1, x)) +} +/** +get a 2-tuple with both the sign and absolute value of `x`. similar to `divrem` +*/ +export const signabs = (x: numeric) => [sign(x), abs(x)] + +/** +calculate truncated division with remainder, returning both values in a 2-tuple +*/ +export function divrem(n: number, d: number): [number, number] +export function divrem(n: bigint, d: bigint): [bigint, bigint] +export function divrem(n: numeric, d: numeric) { + //@ts-expect-error + return [trunc(n / d), n % d] +} + +/** +calculate Euclidean division with remainder, returning both values in a 2-tuple. + +Currently, this is incorrect for `BigInt`s +*/ +export function logB(x: number, b: number): number +export function logB(x: bigint, b: bigint): numeric +export const divEuclid = (n, d) => + (floor(n / abs(d)) * sign(d)) + +export const isEven = (x: unknown) => + isInt(x) && x % autoN(2, x) == 0 + +export const isOdd = (x: unknown) => + isInt(x) && x % autoN(2, x) != 0 + +export function clamp(x: number, min: number, max: number): number +export function clamp(x: bigint, min: bigint, max: bigint): bigint +export function clamp(x: string, min: string, max: string): string +export function clamp(x: numstr, min: numstr, max: numstr) { + return x > max ? max : x < min ? min : x +} + +/** +Logarithm in any base +*/ +export function logB(x: number, b: number): number +export function logB(x: bigint, b: bigint): numeric +export function logB(x: numeric, b: numeric): numeric { + if (x < 0 || b == 0 || b == 1) return NaN + if (x == 0) return -Infinity + if (x == 1) return autoN(0, x) + if (typeof x == 'number') + // in general, + // `lb` has better precision and performance + // than `ln` + return lb(x) / lb(b as number) + + let i = 0n + while ((x as bigint) /= (b as bigint)) + i++ + return i +} diff --git a/src/mod/value check.js b/src/mod/value-check.ts similarity index 88% rename from src/mod/value check.js rename to src/mod/value-check.ts index eca4405..0d875be 100644 --- a/src/mod/value check.js +++ b/src/mod/value-check.ts @@ -6,12 +6,12 @@ check if primitive integer this is not future proof: if `BigFloat`s are added, this will return `false` for any of them -@template T -@param {T} x */ -export const isInt = x => /**@type {T extends bigint ? true : T extends number ? boolean : false}*/( - (typeof x == 'number' && x % 1 == 0) || typeof x == 'bigint' -) +export function isInt(x: bigint): true +export function isInt(x: unknown): boolean +export function isInt(x: unknown) { + return (typeof x == 'number' && x % 1 == 0) || typeof x == 'bigint' +} /** check if either `Infinity` sign @@ -57,4 +57,4 @@ check if it has a sign (includes `-0`) */ export const isSigned = x => /**@type {T extends numeric ? boolean : false}*/( is_numeric(x) && (x < 0 || isNegZero(x)) -) \ No newline at end of file +)