UNPKG

@rgsoft/math

Version:
985 lines (972 loc) 21.8 kB
// src/bases.ts var alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); function toBase(n, b) { if (!Number.isInteger(n) || n < 0) { throw new Error("The number must be positive integer"); } if (!Number.isInteger(b) || b <= 0) { throw new Error("The base must be a positive integer"); } if (b < 2) { throw new Error("The min base is 2"); } if (b > alphabet.length) { throw new Error(`The max base allowed is ${alphabet.length}`); } let e = 1; const digits = []; while (n / (e * b) >= 1) { e *= b; } do { digits.push(alphabet[Math.floor(n / e)]); n = n % e; e /= b; } while (e >= 1); return digits.join(""); } function fromBase(d, b) { if (!Number.isInteger(b) || b <= 0) { throw new Error("The base must be a positive integer"); } if (b < 2) { throw new Error("The min base is 2"); } if (b > alphabet.length) { throw new Error(`The max base allowed is ${alphabet.length}`); } const digits = d.split("").reverse(); return digits.reduce((prev, curr, e) => { const n = alphabet.indexOf(curr); if (n < 0) { throw new Error(`Digit ${curr} not found`); } if (n >= b) { throw new Error(`Invalid digit ${curr} for base ${b}`); } return prev + n * b ** e; }, 0); } // src/combination.ts function factorial(n, m = NaN) { if (!Number.isInteger(n) || n < 0) { throw new Error("The number must be a positive integer"); } if (isNaN(m)) { m = 1; } else { if (!Number.isInteger(m) || m < 0) { throw new Error("The lower limit must be a positive integer"); } if (n < m) { throw new Error("The lower limit cannot be higher than the number"); } } if (n === 0) { return 1; } let f = 1; while (n >= m) { f *= n; n--; } return f; } function combination(n, k) { if (!Number.isInteger(n) || n < 0) { throw new Error("The number of elements must be a positive integer"); } if (!Number.isInteger(k) || k < 0) { throw new Error("The group quantity must be a positive integer"); } if (k > n) { throw new Error("The group quantity cannot be greater than the total elements"); } if (k === 0 || k === n) { return 1; } return factorial(n, Math.max(k + 1, n - k + 1)) / factorial(Math.min(k, n - k)); } function permutation(n, k) { if (!Number.isInteger(n) || n < 0) { throw new Error("The number of elements must be a positive integer"); } if (!Number.isInteger(k) || k < 0) { throw new Error("The group quantity must be a positive integer"); } if (k > n) { throw new Error("The group quantity cannot be greater than the total elements"); } if (k === 0) { return 1; } return factorial(n, n - k + 1); } // src/complex.ts var Complex = class _Complex { constructor(a, b) { this.a = a; this.b = b; return this; } /** * * @param { number | Complex} n */ add(n) { let { a, b } = this; if (typeof n === "number") { a += n; } else if (n instanceof _Complex) { a += n.a; b += n.b; } return new _Complex(a, b); } /** * * @param { number | Complex} n */ sub(n) { let { a, b } = this; if (typeof n === "number") { a -= n; } else if (n instanceof _Complex) { a -= n.a; b -= n.b; } return new _Complex(a, b); } /** * * @param { number | Complex} n */ mult(n) { let { a, b } = this; if (typeof n === "number") { a *= n; b *= n; } else if (n instanceof _Complex) { a = this.a * n.a - this.b * n.b; b = this.a * n.b + this.b * n.a; } return new _Complex(a, b); } /** * * @param { number | Complex} n */ div(n) { let { a, b } = this; if (typeof n === "number") { a /= n; b /= n; } else if (n instanceof _Complex) { const d = n.a * n.a + n.b * n.b; a = (this.a * n.a + this.b * n.b) / d; b = (this.b * n.a - this.a * n.b) / d; } return new _Complex(a, b); } sqrt() { let { a, b } = this; const m = Math.sqrt(this.mag); const phi = Math.atan2(this.b, this.a) * 0.5; a = m * Math.cos(phi); b = m * Math.sin(phi); return new _Complex(a, b); } conjugate() { return new _Complex(this.a, -1 * this.b); } toString() { let str = ""; if (this.a !== 0) { str += `${this.a}`; } if (this.b > 0) { if (this.b === 1) { str += ` + i`; } else { str += ` + ${this.b}i`; } } else if (this.b < 0) { if (this.b === -1) { str += ` - i`; } else { str += ` - ${Math.abs(this.b)}i`; } } return str.trim(); } /** * @returns { number } */ get mag() { if (this._mag === void 0) { this._mag = Math.sqrt(this.a * this.a + this.b * this.b); } return this._mag; } }; // src/vector.ts var Vector = class _Vector { /** * * @param { number } x * @param { number } y */ constructor(x, y) { this._x = x; this._y = y; this.resetValues(); } resetValues() { this._mag = void 0; this._angle = void 0; } /** * @returns { number } */ get mag() { if (this._mag === void 0) { this._mag = Math.sqrt(this._x * this._x + this._y * this._y); } return this._mag; } /** * @param { number } value */ set mag(value) { if (value < 0) { throw new Error("New magnitude must be positive"); } this.normalize(); this.mult(value); this._mag = value; } /** * @returns { number } */ get angle() { if (this._angle === void 0) { if (this.mag > 0) { this._angle = Math.atan2(this._y, this._x); } else { this._angle = 0; } } return this._angle; } /** * @returns { number } */ get x() { return this._x; } /** * @param { number } value */ set x(value) { this._x = value; this.resetValues(); } /** * @returns { number } */ get y() { return this._y; } /** * @param { number } value */ set y(value) { this._y = value; this.resetValues(); } /** * * @returns { Vector } */ normalize() { if (this.mag === 0) { return this; } this._x /= this.mag; this._y /= this.mag; this.resetValues(); return this; } /** * * @param { number} num * @returns { Vector } */ mult(num) { this._x *= num; this._y *= num; this.resetValues(); return this; } /** * * @param { number} num * @returns { Vector } */ div(num) { this._x /= num; this._y /= num; this.resetValues(); return this; } /** * @param {Vector} v * @returns {number} */ dot(v) { return this._x * v._x + this._y * v._y; } /** * * @param { Vector } vector * @returns { Vector } */ add(vector) { this._x += vector._x; this._y += vector._y; this.resetValues(); return this; } /** * * @param { Vector } vector * @returns { Vector } */ sub(vector) { this._x -= vector._x; this._y -= vector._y; this.resetValues(); return this; } /** * * @param { Vector } vector * @returns { number } */ dist(vector) { const dx = this._x - vector._x; const dy = this._y - vector._y; return Math.sqrt(dx * dx + dy * dy); } /** * * @param { Vector } vector * @returns { boolean } */ equals(vector) { return vector.x === this._x && vector.y === this.y; } /** * * @param { Vector } vector * @returns { number } */ angleTo(vector) { const cp = this.dot(vector); if (this.mag === 0 || vector.mag === 0) { return NaN; } return Math.acos(cp / (this.mag * vector.mag)); } /** * Calculates the projection on another vector * @param { Vector } vector * @returns { Vector } */ projection(vector) { const cp = this.dot(vector); const sqrtMag = vector.dot(vector); const proj = vector.copy(); proj.mult(cp / sqrtMag); return proj; } /** * @returns { Vector } */ copy() { return new _Vector(this._x, this._y); } transpose() { const aux = this._y; this._y = this._x; this._x = aux; this.resetValues(); } /** * * @param { number } mag */ limit(mag) { if (this.mag <= mag) { return; } this.mag = mag; } /** * * @param { number } angle * @returns { Vector } */ static fromAngle(angle) { const instance = new _Vector(Math.cos(angle), Math.sin(angle)); instance._angle = angle; return instance; } /** * * @param { Vector } v * @param { Vector } w * @returns { Vector } */ static add(v, w) { const instance = v.copy(); return instance.add(w); } /** * * @param { Vector } v * @param { Vector } w * @returns { Vector } */ static sub(v, w) { const instance = v.copy(); return instance.sub(w); } /** * * @param { Vector } v * @param { number } n * @returns { Vector } */ static mult(v, n) { const instance = v.copy(); return instance.mult(n); } /** * * @param { Vector } v * @param { number } n * @returns { Vector } */ static div(v, n) { const instance = v.copy(); return instance.div(n); } }; // src/line.ts var Line = class _Line { constructor(m, a) { this.m = m; this.a = a; } static fromPoints(p, q) { const m = p.x === q.x ? NaN : (p.y - q.y) / (p.x - q.x); const a = isNaN(m) ? p.x : -1 * m * p.x + p.y; return new _Line(m, a); } static mediatrix(p, q) { const a = q.copy(); a.sub(p); a.mult(0.5); const b = Vector.fromAngle(a.angle + Math.PI * 0.5); a.add(p); b.add(a); return _Line.fromPoints(a, b); } /** * Calculates a line intersection point with another * @param { Line } line * @returns { Vector } */ intersectionPoint(line) { let x, y; if (this.m === line.m) { throw new Error("The slopes are equal"); } if (isNaN(this.m)) { x = this.a; y = line.m * x + line.a; } else if (isNaN(line.m)) { x = line.a; y = this.m * x + this.a; } else { x = (line.a - this.a) / (this.m - line.m); y = this.m * x + this.a; } return new Vector(x, y); } }; // src/number.ts function mod(n, m) { if (!Number.isInteger(n)) { throw new Error("The number must be an integer"); } if (!Number.isInteger(m) || m <= 0) { throw new Error("Modulo must be a positive integer"); } return (n % m + m) % m; } function gcd(a, b) { if (!Number.isInteger(a) || a <= 0) { throw new Error("Both numbers must be positive integers"); } if (!Number.isInteger(b) || b <= 0) { throw new Error("Both numbers must be positive integers"); } if (a === b) { return a; } let d; do { d = Math.abs(a - b); a = Math.min(a, b); b = d; } while (d !== a && d > 0); return d; } function lcm(a, b) { if (!Number.isInteger(a) || a <= 0) { throw new Error("Both numbers must be positive integers"); } if (!Number.isInteger(b) || b <= 0) { throw new Error("Both numbers must be positive integers"); } const d = gcd(a, b); return a * b / d; } function prime(n) { if (!Number.isInteger(n) || n <= 0) { throw new Error("The number must be positive integer"); } const l = Math.sqrt(n); for (let i = 2; i <= l; i++) { if (n % i === 0) { return false; } } return true; } function factors(n) { if (!Number.isInteger(n) || n <= 0) { throw new Error("The number must be positive integer"); } if (n === 1) { return [[1, 1]]; } const factors2 = []; let i = 2; let factor = [i, 0]; while (n > 1) { if (n % i === 0) { n /= i; factor[1]++; } else { i++; if (factor[1] > 0) { factors2.push(factor); } factor = [i, 0]; } } if (factor[1] > 0) { factors2.push(factor); } return factors2; } function totient(m) { if (!Number.isInteger(m) || m <= 0) { throw new Error("The number must be positive integer"); } const factorization = factors(m); let a = 1; let b = 1; factorization.forEach((f) => { a *= f[0]; b *= f[0] - 1; }); return b * m / a; } function collatz(n, limit = 1e4) { if (!Number.isInteger(n) || n <= 0) { throw new Error("The number must be positive integer"); } const seq = [n]; for (let i = 1; i < limit; i++) { if (n === 1) { break; } if (n % 2 === 0) { n = n * 0.5; } else { n = 3 * n + 1; } seq.push(n); } return seq; } function digitalRoots(n) { if (!Number.isInteger(n) || n <= 0) { throw new Error("The number must be positive integer"); } if (n < 10) { return n; } do { let chars = n.toString().split(""); n = chars.reduce((prev, c) => prev += Number(c), 0); } while (n >= 10); return n; } // src/pdf/erf.ts function erf(z) { const t = 1 / (1 + 0.5 * Math.abs(z)); const tau = t * Math.exp( -z * z - 1.26551223 + 1.00002368 * t + 0.37409196 * t ** 2 + 0.09678418 * t ** 3 - 0.18628806 * t ** 4 + 0.27886807 * t ** 5 - 1.13520398 * t ** 6 + 1.48851587 * t ** 7 - 0.82215223 * t ** 8 + 0.17087277 * t ** 9 ); return z >= 0 ? 1 - tau : tau - 1; } // src/pdf/exponential.ts var Exponential = class { constructor(mean) { this.mean = mean; this.m = 1 / mean; } getAccumulated(x) { if (x < 0) { return 0; } return 1 - Math.exp(-this.m * x); } getValue() { const p = Math.random(); if (p === 1) { return Infinity; } return -1 * Math.log(1 - p) * this.mean; } getMean() { return this.mean; } }; // src/pdf/gaussian.ts var Gaussian = class { constructor(m = 0, v = 1) { this.m = m; this.v = v; if (v <= 0) { throw new Error("Variance must be positive"); } this.stdDev = Math.sqrt(v); } getAccumulated(x) { const z = (x - this.m) / Math.sqrt(2 * this.v); return 0.5 * (1 + erf(z)); } inverseCFD(p) { if (p < 0 || p > 1) { throw new Error("Invalid value for p"); } if (p === 0) return -Infinity; if (p === 1) return Infinity; const a = [-39.6968302866538, 220.946098424521, -275.928510446969, 138.357751867269, -30.6647980661472, 2.50662827745924]; const b = [-54.4760987982241, 161.585836858041, -155.698979859887, 66.8013118877197, -13.2806815528857]; const c = [-0.00778489400243029, -0.322396458041136, -2.40075827716184, -2.54973253934373, 4.37466414146497, 2.93816398269878]; const d = [0.00778469570904146, 0.32246712907004, 2.445134137143, 3.75440866190742]; let q, r; if (p < 0.02425) { q = Math.sqrt(-2 * Math.log(p)); return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1); } else if (p > 1 - 0.02425) { q = Math.sqrt(-2 * Math.log(1 - p)); return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1); } else { q = p - 0.5; r = q * q; return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1); } } getMean() { return this.m; } getValue() { const p = Math.random(); const z = this.inverseCFD(p); return this.m + z * this.stdDev; } }; // src/pdf/uniform.ts var Uniform = class { constructor(min, max) { this.min = min; this.max = max; if (min > max) { throw new Error("Min cannot be greater than max"); } } getAccumulated(x) { if (x < this.min) { return 0; } if (x > this.max) { return 1; } return (x - this.min) / (this.max - this.min); } getMean() { return (this.max + this.min) * 0.5; } getValue() { return Math.random() * (this.max - this.min) + this.min; } }; // src/pmf/binomial.ts var Binomial = class { constructor(n, p) { this.n = n; this.p = p; if (!Number.isInteger(n) || n < 1) { throw new Error("The number of experiments must be a positive integer"); } if (!(p >= 0 && p <= 1)) { throw new Error("The success probability must be between 0 and 1"); } this.probabilities = Array(n + 1).fill(0).map((_, i) => combination(n, i) * p ** i * (1 - p) ** (n - i)); let acc = 0; this.accumulative = this.probabilities.map((p2) => { acc += p2; return acc; }); } getAccumulated(x) { x = Math.floor(x); if (isNaN(x)) { throw new Error("Number expected"); } if (x < 0) { return 0; } if (x > this.n) { return 1; } return this.accumulative[x]; } getValue() { const rnd = Math.random(); return this.accumulative.findIndex((acc) => rnd < acc); } probability(x) { if (!Number.isInteger(x) || x < 0) { throw new Error("The value must be a positive integer"); } if (x > this.n) { throw new Error("The value cannot ve larger than the experiments number"); } return this.probabilities[x]; } }; // src/pmf/negative-binomial.ts var NegativeBinomial = class { constructor(r, p) { this.r = r; this.p = p; this.accumulative = []; if (!Number.isInteger(r) || r < 1) { throw new Error("The number of experiments must be a positive integer"); } if (!(p >= 0 && p <= 1)) { throw new Error("The success probability must be between 0 and 1"); } } getAccumulated(x) { x = Math.floor(x); if (isNaN(x)) { throw new Error("Number expected"); } if (x < 0) { return 0; } if (this.accumulative.length > x) { return this.accumulative[x]; } let i = this.accumulative.length; let acc = i > 0 ? this.accumulative[i - 1] : 0; do { acc += this.probability(i); this.accumulative.push(acc); i++; } while (i <= x); return this.accumulative[x]; } getValue() { const rnd = Math.random(); let i = 0; while (i < this.accumulative.length) { if (rnd < this.accumulative[i]) { return i; } i++; } let acc = i > 0 ? this.accumulative[i - 1] : 0; do { acc += this.probability(i); this.accumulative.push(acc); i++; } while (rnd > acc); return i - 1; } probability(x) { if (!Number.isInteger(x) || x < 0) { throw new Error("The value must be a positive integer"); } return combination(this.r + x - 1, x) * this.p ** this.r * (1 - this.p) ** x; } }; // src/pmf/poisson.ts var Poisson = class { constructor(l) { this.l = l; this.accumulative = []; if (!Number.isInteger(l) || l < 0) { throw new Error("The number of experiments must be a positive integer"); } } getAccumulated(x) { x = Math.floor(x); if (isNaN(x)) { throw new Error("Number expected"); } if (x < 0) { return 0; } if (this.accumulative.length > x) { return this.accumulative[x]; } let i = this.accumulative.length; let acc = i > 0 ? this.accumulative[i - 1] : 0; do { acc += this.probability(i); this.accumulative.push(acc); i++; } while (i <= x); return this.accumulative[x]; } getValue() { const rnd = Math.random(); let i = 0; while (i < this.accumulative.length) { if (rnd < this.accumulative[i]) { return i; } i++; } let acc = i > 0 ? this.accumulative[i - 1] : 0; do { acc += this.probability(i); this.accumulative.push(acc); i++; } while (rnd > acc); return i - 1; } probability(x) { if (!Number.isInteger(x) || x < 0) { throw new Error("The value must be a positive integer"); } return this.l ** x * Math.exp(-this.l) / factorial(x); } }; // src/segment.ts var Segment = class { constructor(p, q) { this.p = p; this.q = q; } /** * * @param { Vector } r * @returns { boolean } */ isOnSegment(r) { return (this.q.x - this.p.x) * (r.y - this.p.y) === (this.q.y - this.p.y) * (r.x - this.p.x); } /** * To find orientation of ordered triplet (p, q, r). * The function returns following values * 0 when p, q and r are collinear; -1 when clockwise, 1 counterclockwise * * @param { Vector } p * @param { Vector } q * @param { Vector } r * @returns { number } */ getOrientation(p, q, r) { let val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); if (val == 0) return 0; return val > 0 ? -1 : 1; } /** * * Returns true if intersects with this segment * * @param { Segment } segment * @returns { boolean } */ intersects(segment) { let o1 = this.getOrientation(this.p, this.q, segment.p); let o2 = this.getOrientation(this.p, this.q, segment.q); let o3 = this.getOrientation(segment.p, segment.q, this.p); let o4 = this.getOrientation(segment.p, segment.q, this.q); if (o1 != o2 && o3 != o4) { return true; } if (o1 == 0 && this.isOnSegment(segment.p)) { return true; } if (o2 == 0 && this.isOnSegment(segment.q)) { return true; } if (o3 == 0 && segment.isOnSegment(this.p)) { return true; } if (o4 == 0 && segment.isOnSegment(this.q)) { return true; } return false; } }; export { Binomial, Complex, Exponential, Gaussian, Line, NegativeBinomial, Poisson, Segment, Uniform, Vector, collatz, combination, digitalRoots, erf, factorial, factors, fromBase, gcd, lcm, mod, permutation, prime, toBase, totient }; //# sourceMappingURL=index.mjs.map