UNPKG

@typester/big-rational

Version:

BigRational is a ~1kB arbitrary precision rational number library powered by the native BigInt type.

179 lines (177 loc) 5.88 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { BigRational: () => BigRational }); module.exports = __toCommonJS(src_exports); var re = (() => { const inner = "[0-9]+(?:[.][0-9]*)?"; const nonNegativeDecimal = `(${inner})`; const decimal = `(-?${inner})`; const ws = "\\s*"; const make = (parts) => new RegExp(["^", ...parts, "$"].join(ws)); return [ make([decimal]), make([decimal, "/", nonNegativeDecimal]), make([decimal, nonNegativeDecimal, "/", nonNegativeDecimal]) ]; })(); var BigRational = class _BigRational { #numerator; #denominator; // Creates a new BigRational without simplifying the fraction or checking that // the denominator is positive. constructor(numerator, denominator) { this.#numerator = numerator; this.#denominator = denominator; } static from(numerator, denominator) { if (denominator === 0n) throw new Error("denominator cannot be zero"); if (denominator === 1n) return new _BigRational(numerator, 1n); if (denominator < 0) { numerator = -numerator; denominator = -denominator; } const gcd_ = gcd(abs(numerator), denominator); return new _BigRational(numerator / gcd_, denominator / gcd_); } static fromString(string) { const match0 = string.match(re[0]); if (match0) { return parseOne(match0[1]); } const match1 = string.match(re[1]); if (match1) { return parseOne(match1[1]).divide(parseOne(match1[2])); } const match2 = string.match(re[2]); if (match2) { const whole = parseOne(match2[1]); const fraction = parseOne(match2[2]).divide(parseOne(match2[3])); return whole.#numerator >= 0n ? whole.add(fraction) : whole.subtract(fraction); } throw new Error(`Invalid BigRational: ${string}`); } numerator() { return this.#numerator; } denominator() { return this.#denominator; } add(other) { return _BigRational.from( this.#numerator * other.#denominator + other.#numerator * this.#denominator, this.#denominator * other.#denominator ); } subtract(other) { return _BigRational.from( this.#numerator * other.#denominator - other.#numerator * this.#denominator, this.#denominator * other.#denominator ); } multiply(other) { return _BigRational.from( this.#numerator * other.#numerator, this.#denominator * other.#denominator ); } divide(other) { return _BigRational.from( this.#numerator * other.#denominator, this.#denominator * other.#numerator ); } compare(other) { const a = this.#numerator * other.#denominator; const b = other.#numerator * this.#denominator; return a === b ? 0 : a > b ? 1 : -1; } power(n) { return _BigRational.from(this.#numerator ** n, this.#denominator ** n); } modulo(other) { return this.subtract( other.multiply(new _BigRational(this.divide(other).floor(), 1n)) ); } // Round towards negative infinity. floor() { return (this.#numerator >= 0 ? this.#numerator : this.#numerator - this.#denominator + 1n) / this.#denominator; } // Round towards positive infinity. ceil() { return (this.#numerator >= 0 ? this.#numerator + this.#denominator - 1n : this.#numerator) / this.#denominator; } // Round towards zero. truncate() { return this.#numerator / this.#denominator; } negate() { return new _BigRational(-this.#numerator, this.#denominator); } inverse() { if (this.#numerator === 0n) throw new Error("cannot take inverse of zero"); return this.#numerator < 0n ? new _BigRational(-this.#denominator, -this.#numerator) : new _BigRational(this.#denominator, this.#numerator); } abs() { return this.#numerator < 0n ? this.negate() : this; } toNumberApproximate() { const whole = this.#numerator / this.#denominator; const numerator = this.#numerator % this.#denominator; return Number(whole) + Number(numerator) / Number(this.#denominator); } toFractionString() { return this.#denominator === 1n ? `${this.#numerator}` : `${this.#numerator}/${this.#denominator}`; } toMixedString() { const whole = this.#numerator / this.#denominator; let numerator = this.#numerator % this.#denominator; if (whole < 0) numerator = -numerator; return numerator === 0n ? `${whole}` : whole === 0n ? `${numerator}/${this.#denominator}` : `${whole} ${numerator}/${this.#denominator}`; } toString() { return this.toFractionString(); } }; var abs = (a) => a >= 0n ? a : -a; var gcd = (a, b) => { while (b !== 0n) { const t = b; b = a % b; a = t; } return a; }; var parseOne = (string) => { const indexOfDot = string.indexOf("."); if (indexOfDot === -1) { return BigRational.from(BigInt(string), 1n); } const before = string.slice(0, indexOfDot); const after = string.slice(indexOfDot + 1); return BigRational.from(BigInt(before + after), 10n ** BigInt(after.length)); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BigRational });