Files
rspade_system/node_modules/fraction.js/dist/fraction.mjs
root 77b4d10af8 Refactor filename naming system and apply convention-based renames
Standardize settings file naming and relocate documentation files
Fix code quality violations from rsx:check
Reorganize user_management directory into logical subdirectories
Move Quill Bundle to core and align with Tom Select pattern
Simplify Site Settings page to focus on core site information
Complete Phase 5: Multi-tenant authentication with login flow and site selection
Add route query parameter rule and synchronize filename validation logic
Fix critical bug in UpdateNpmCommand causing missing JavaScript stubs
Implement filename convention rule and resolve VS Code auto-rename conflict
Implement js-sanitizer RPC server to eliminate 900+ Node.js process spawns
Implement RPC server architecture for JavaScript parsing
WIP: Add RPC server infrastructure for JS parsing (partial implementation)
Update jqhtml terminology from destroy to stop, fix datagrid DOM preservation
Add JQHTML-CLASS-01 rule and fix redundant class names
Improve code quality rules and resolve violations
Remove legacy fatal error format in favor of unified 'fatal' error type
Filter internal keys from window.rsxapp output
Update button styling and comprehensive form/modal documentation
Add conditional fly-in animation for modals
Fix non-deterministic bundle compilation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 19:10:02 +00:00

1044 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/**
*
* This class offers the possibility to calculate fractions.
* You can pass a fraction in different formats. Either as array, as double, as string or as an integer.
*
* Array/Object form
* [ 0 => <numerator>, 1 => <denominator> ]
* { n => <numerator>, d => <denominator> }
*
* Integer form
* - Single integer value as BigInt or Number
*
* Double form
* - Single double value as Number
*
* String form
* 123.456 - a simple double
* 123/456 - a string fraction
* 123.'456' - a double with repeating decimal places
* 123.(456) - synonym
* 123.45'6' - a double with repeating last place
* 123.45(6) - synonym
*
* Example:
* let f = new Fraction("9.4'31'");
* f.mul([-4, 3]).div(4.9);
*
*/
// Set Identity function to downgrade BigInt to Number if needed
if (typeof BigInt === 'undefined') BigInt = function (n) { if (isNaN(n)) throw new Error(""); return n; };
const C_ZERO = BigInt(0);
const C_ONE = BigInt(1);
const C_TWO = BigInt(2);
const C_THREE = BigInt(3);
const C_FIVE = BigInt(5);
const C_TEN = BigInt(10);
const MAX_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
// Maximum search depth for cyclic rational numbers. 2000 should be more than enough.
// Example: 1/7 = 0.(142857) has 6 repeating decimal places.
// If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits
const MAX_CYCLE_LEN = 2000;
// Parsed data to avoid calling "new" all the time
const P = {
"s": C_ONE,
"n": C_ZERO,
"d": C_ONE
};
function assign(n, s) {
try {
n = BigInt(n);
} catch (e) {
throw InvalidParameter();
}
return n * s;
}
function ifloor(x) {
return typeof x === 'bigint' ? x : Math.floor(x);
}
// Creates a new Fraction internally without the need of the bulky constructor
function newFraction(n, d) {
if (d === C_ZERO) {
throw DivisionByZero();
}
const f = Object.create(Fraction.prototype);
f["s"] = n < C_ZERO ? -C_ONE : C_ONE;
n = n < C_ZERO ? -n : n;
const a = gcd(n, d);
f["n"] = n / a;
f["d"] = d / a;
return f;
}
const FACTORSTEPS = [C_TWO * C_TWO, C_TWO, C_TWO * C_TWO, C_TWO, C_TWO * C_TWO, C_TWO * C_THREE, C_TWO, C_TWO * C_THREE]; // repeats
function factorize(n) {
const factors = Object.create(null);
if (n <= C_ONE) {
factors[n] = C_ONE;
return factors;
}
const add = (p) => { factors[p] = (factors[p] || C_ZERO) + C_ONE; };
while (n % C_TWO === C_ZERO) { add(C_TWO); n /= C_TWO; }
while (n % C_THREE === C_ZERO) { add(C_THREE); n /= C_THREE; }
while (n % C_FIVE === C_ZERO) { add(C_FIVE); n /= C_FIVE; }
// 30-wheel trial division: test only residues coprime to 2*3*5
// Residue step pattern after 5: 7,11,13,17,19,23,29,31, ...
for (let si = 0, p = C_TWO + C_FIVE; p * p <= n;) {
while (n % p === C_ZERO) { add(p); n /= p; }
p += FACTORSTEPS[si];
si = (si + 1) & 7; // fast modulo 8
}
if (n > C_ONE) add(n);
return factors;
}
const parse = function (p1, p2) {
let n = C_ZERO, d = C_ONE, s = C_ONE;
if (p1 === undefined || p1 === null) { // No argument
/* void */
} else if (p2 !== undefined) { // Two arguments
if (typeof p1 === "bigint") {
n = p1;
} else if (isNaN(p1)) {
throw InvalidParameter();
} else if (p1 % 1 !== 0) {
throw NonIntegerParameter();
} else {
n = BigInt(p1);
}
if (typeof p2 === "bigint") {
d = p2;
} else if (isNaN(p2)) {
throw InvalidParameter();
} else if (p2 % 1 !== 0) {
throw NonIntegerParameter();
} else {
d = BigInt(p2);
}
s = n * d;
} else if (typeof p1 === "object") {
if ("d" in p1 && "n" in p1) {
n = BigInt(p1["n"]);
d = BigInt(p1["d"]);
if ("s" in p1)
n *= BigInt(p1["s"]);
} else if (0 in p1) {
n = BigInt(p1[0]);
if (1 in p1)
d = BigInt(p1[1]);
} else if (typeof p1 === "bigint") {
n = p1;
} else {
throw InvalidParameter();
}
s = n * d;
} else if (typeof p1 === "number") {
if (isNaN(p1)) {
throw InvalidParameter();
}
if (p1 < 0) {
s = -C_ONE;
p1 = -p1;
}
if (p1 % 1 === 0) {
n = BigInt(p1);
} else {
let z = 1;
let A = 0, B = 1;
let C = 1, D = 1;
let N = 10000000;
if (p1 >= 1) {
z = 10 ** Math.floor(1 + Math.log10(p1));
p1 /= z;
}
// Using Farey Sequences
while (B <= N && D <= N) {
let M = (A + C) / (B + D);
if (p1 === M) {
if (B + D <= N) {
n = A + C;
d = B + D;
} else if (D > B) {
n = C;
d = D;
} else {
n = A;
d = B;
}
break;
} else {
if (p1 > M) {
A += C;
B += D;
} else {
C += A;
D += B;
}
if (B > N) {
n = C;
d = D;
} else {
n = A;
d = B;
}
}
}
n = BigInt(n) * BigInt(z);
d = BigInt(d);
}
} else if (typeof p1 === "string") {
let ndx = 0;
let v = C_ZERO, w = C_ZERO, x = C_ZERO, y = C_ONE, z = C_ONE;
let match = p1.replace(/_/g, '').match(/\d+|./g);
if (match === null)
throw InvalidParameter();
if (match[ndx] === '-') {// Check for minus sign at the beginning
s = -C_ONE;
ndx++;
} else if (match[ndx] === '+') {// Check for plus sign at the beginning
ndx++;
}
if (match.length === ndx + 1) { // Check if it's just a simple number "1234"
w = assign(match[ndx++], s);
} else if (match[ndx + 1] === '.' || match[ndx] === '.') { // Check if it's a decimal number
if (match[ndx] !== '.') { // Handle 0.5 and .5
v = assign(match[ndx++], s);
}
ndx++;
// Check for decimal places
if (ndx + 1 === match.length || match[ndx + 1] === '(' && match[ndx + 3] === ')' || match[ndx + 1] === "'" && match[ndx + 3] === "'") {
w = assign(match[ndx], s);
y = C_TEN ** BigInt(match[ndx].length);
ndx++;
}
// Check for repeating places
if (match[ndx] === '(' && match[ndx + 2] === ')' || match[ndx] === "'" && match[ndx + 2] === "'") {
x = assign(match[ndx + 1], s);
z = C_TEN ** BigInt(match[ndx + 1].length) - C_ONE;
ndx += 3;
}
} else if (match[ndx + 1] === '/' || match[ndx + 1] === ':') { // Check for a simple fraction "123/456" or "123:456"
w = assign(match[ndx], s);
y = assign(match[ndx + 2], C_ONE);
ndx += 3;
} else if (match[ndx + 3] === '/' && match[ndx + 1] === ' ') { // Check for a complex fraction "123 1/2"
v = assign(match[ndx], s);
w = assign(match[ndx + 2], s);
y = assign(match[ndx + 4], C_ONE);
ndx += 5;
}
if (match.length <= ndx) { // Check for more tokens on the stack
d = y * z;
s = /* void */
n = x + d * v + z * w;
} else {
throw InvalidParameter();
}
} else if (typeof p1 === "bigint") {
n = p1;
s = p1;
d = C_ONE;
} else {
throw InvalidParameter();
}
if (d === C_ZERO) {
throw DivisionByZero();
}
P["s"] = s < C_ZERO ? -C_ONE : C_ONE;
P["n"] = n < C_ZERO ? -n : n;
P["d"] = d < C_ZERO ? -d : d;
};
function modpow(b, e, m) {
let r = C_ONE;
for (; e > C_ZERO; b = (b * b) % m, e >>= C_ONE) {
if (e & C_ONE) {
r = (r * b) % m;
}
}
return r;
}
function cycleLen(n, d) {
for (; d % C_TWO === C_ZERO;
d /= C_TWO) {
}
for (; d % C_FIVE === C_ZERO;
d /= C_FIVE) {
}
if (d === C_ONE) // Catch non-cyclic numbers
return C_ZERO;
// If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem:
// 10^(d-1) % d == 1
// However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone,
// as we want to translate the numbers to strings.
let rem = C_TEN % d;
let t = 1;
for (; rem !== C_ONE; t++) {
rem = rem * C_TEN % d;
if (t > MAX_CYCLE_LEN)
return C_ZERO; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1`
}
return BigInt(t);
}
function cycleStart(n, d, len) {
let rem1 = C_ONE;
let rem2 = modpow(C_TEN, len, d);
for (let t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE)
// Solve 10^s == 10^(s+t) (mod d)
if (rem1 === rem2)
return BigInt(t);
rem1 = rem1 * C_TEN % d;
rem2 = rem2 * C_TEN % d;
}
return 0;
}
function gcd(a, b) {
if (!a)
return b;
if (!b)
return a;
while (1) {
a %= b;
if (!a)
return b;
b %= a;
if (!b)
return a;
}
}
/**
* Module constructor
*
* @constructor
* @param {number|Fraction=} a
* @param {number=} b
*/
function Fraction(a, b) {
parse(a, b);
if (this instanceof Fraction) {
a = gcd(P["d"], P["n"]); // Abuse a
this["s"] = P["s"];
this["n"] = P["n"] / a;
this["d"] = P["d"] / a;
} else {
return newFraction(P['s'] * P['n'], P['d']);
}
}
const DivisionByZero = function () { return new Error("Division by Zero"); };
const InvalidParameter = function () { return new Error("Invalid argument"); };
const NonIntegerParameter = function () { return new Error("Parameters must be integer"); };
Fraction.prototype = {
"s": C_ONE,
"n": C_ZERO,
"d": C_ONE,
/**
* Calculates the absolute value
*
* Ex: new Fraction(-4).abs() => 4
**/
"abs": function () {
return newFraction(this["n"], this["d"]);
},
/**
* Inverts the sign of the current fraction
*
* Ex: new Fraction(-4).neg() => 4
**/
"neg": function () {
return newFraction(-this["s"] * this["n"], this["d"]);
},
/**
* Adds two rational numbers
*
* Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30
**/
"add": function (a, b) {
parse(a, b);
return newFraction(
this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"],
this["d"] * P["d"]
);
},
/**
* Subtracts two rational numbers
*
* Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30
**/
"sub": function (a, b) {
parse(a, b);
return newFraction(
this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"],
this["d"] * P["d"]
);
},
/**
* Multiplies two rational numbers
*
* Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111
**/
"mul": function (a, b) {
parse(a, b);
return newFraction(
this["s"] * P["s"] * this["n"] * P["n"],
this["d"] * P["d"]
);
},
/**
* Divides two rational numbers
*
* Ex: new Fraction("-17.(345)").inverse().div(3)
**/
"div": function (a, b) {
parse(a, b);
return newFraction(
this["s"] * P["s"] * this["n"] * P["d"],
this["d"] * P["n"]
);
},
/**
* Clones the actual object
*
* Ex: new Fraction("-17.(345)").clone()
**/
"clone": function () {
return newFraction(this['s'] * this['n'], this['d']);
},
/**
* Calculates the modulo of two rational numbers - a more precise fmod
*
* Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6)
* Ex: new Fraction(20, 10).mod().equals(0) ? "is Integer"
**/
"mod": function (a, b) {
if (a === undefined) {
return newFraction(this["s"] * this["n"] % this["d"], C_ONE);
}
parse(a, b);
if (C_ZERO === P["n"] * this["d"]) {
throw DivisionByZero();
}
/**
* I derived the rational modulo similar to the modulo for integers
*
* https://raw.org/book/analysis/rational-numbers/
*
* n1/d1 = (n2/d2) * q + r, where 0 ≤ r < n2/d2
* => d2 * n1 = n2 * d1 * q + d1 * d2 * r
* => r = (d2 * n1 - n2 * d1 * q) / (d1 * d2)
* = (d2 * n1 - n2 * d1 * floor((d2 * n1) / (n2 * d1))) / (d1 * d2)
* = ((d2 * n1) % (n2 * d1)) / (d1 * d2)
*/
return newFraction(
this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]),
P["d"] * this["d"]);
},
/**
* Calculates the fractional gcd of two rational numbers
*
* Ex: new Fraction(5,8).gcd(3,7) => 1/56
*/
"gcd": function (a, b) {
parse(a, b);
// https://raw.org/book/analysis/rational-numbers/
// gcd(a / b, c / d) = gcd(a, c) / lcm(b, d)
return newFraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]);
},
/**
* Calculates the fractional lcm of two rational numbers
*
* Ex: new Fraction(5,8).lcm(3,7) => 15
*/
"lcm": function (a, b) {
parse(a, b);
// https://raw.org/book/analysis/rational-numbers/
// lcm(a / b, c / d) = lcm(a, c) / gcd(b, d)
if (P["n"] === C_ZERO && this["n"] === C_ZERO) {
return newFraction(C_ZERO, C_ONE);
}
return newFraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]));
},
/**
* Gets the inverse of the fraction, means numerator and denominator are exchanged
*
* Ex: new Fraction([-3, 4]).inverse() => -4 / 3
**/
"inverse": function () {
return newFraction(this["s"] * this["d"], this["n"]);
},
/**
* Calculates the fraction to some integer exponent
*
* Ex: new Fraction(-1,2).pow(-3) => -8
*/
"pow": function (a, b) {
parse(a, b);
// Trivial case when exp is an integer
if (P['d'] === C_ONE) {
if (P['s'] < C_ZERO) {
return newFraction((this['s'] * this["d"]) ** P['n'], this["n"] ** P['n']);
} else {
return newFraction((this['s'] * this["n"]) ** P['n'], this["d"] ** P['n']);
}
}
// Negative roots become complex
// (-a/b)^(c/d) = x
// ⇔ (-1)^(c/d) * (a/b)^(c/d) = x
// ⇔ (cos(pi) + i*sin(pi))^(c/d) * (a/b)^(c/d) = x
// ⇔ (cos(c*pi/d) + i*sin(c*pi/d)) * (a/b)^(c/d) = x # DeMoivre's formula
// From which follows that only for c=0 the root is non-complex
if (this['s'] < C_ZERO) return null;
// Now prime factor n and d
let N = factorize(this['n']);
let D = factorize(this['d']);
// Exponentiate and take root for n and d individually
let n = C_ONE;
let d = C_ONE;
for (let k in N) {
if (k === '1') continue;
if (k === '0') {
n = C_ZERO;
break;
}
N[k] *= P['n'];
if (N[k] % P['d'] === C_ZERO) {
N[k] /= P['d'];
} else return null;
n *= BigInt(k) ** N[k];
}
for (let k in D) {
if (k === '1') continue;
D[k] *= P['n'];
if (D[k] % P['d'] === C_ZERO) {
D[k] /= P['d'];
} else return null;
d *= BigInt(k) ** D[k];
}
if (P['s'] < C_ZERO) {
return newFraction(d, n);
}
return newFraction(n, d);
},
/**
* Calculates the logarithm of a fraction to a given rational base
*
* Ex: new Fraction(27, 8).log(9, 4) => 3/2
*/
"log": function (a, b) {
parse(a, b);
if (this['s'] <= C_ZERO || P['s'] <= C_ZERO) return null;
const allPrimes = Object.create(null);
const baseFactors = factorize(P['n']);
const T1 = factorize(P['d']);
const numberFactors = factorize(this['n']);
const T2 = factorize(this['d']);
for (const prime in T1) {
baseFactors[prime] = (baseFactors[prime] || C_ZERO) - T1[prime];
}
for (const prime in T2) {
numberFactors[prime] = (numberFactors[prime] || C_ZERO) - T2[prime];
}
for (const prime in baseFactors) {
if (prime === '1') continue;
allPrimes[prime] = true;
}
for (const prime in numberFactors) {
if (prime === '1') continue;
allPrimes[prime] = true;
}
let retN = null;
let retD = null;
// Iterate over all unique primes to determine if a consistent ratio exists
for (const prime in allPrimes) {
const baseExponent = baseFactors[prime] || C_ZERO;
const numberExponent = numberFactors[prime] || C_ZERO;
if (baseExponent === C_ZERO) {
if (numberExponent !== C_ZERO) {
return null; // Logarithm cannot be expressed as a rational number
}
continue; // Skip this prime since both exponents are zero
}
// Calculate the ratio of exponents for this prime
let curN = numberExponent;
let curD = baseExponent;
// Simplify the current ratio
const gcdValue = gcd(curN, curD);
curN /= gcdValue;
curD /= gcdValue;
// Check if this is the first ratio; otherwise, ensure ratios are consistent
if (retN === null && retD === null) {
retN = curN;
retD = curD;
} else if (curN * retD !== retN * curD) {
return null; // Ratios do not match, logarithm cannot be rational
}
}
return retN !== null && retD !== null
? newFraction(retN, retD)
: null;
},
/**
* Check if two rational numbers are the same
*
* Ex: new Fraction(19.6).equals([98, 5]);
**/
"equals": function (a, b) {
parse(a, b);
return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"];
},
/**
* Check if this rational number is less than another
*
* Ex: new Fraction(19.6).lt([98, 5]);
**/
"lt": function (a, b) {
parse(a, b);
return this["s"] * this["n"] * P["d"] < P["s"] * P["n"] * this["d"];
},
/**
* Check if this rational number is less than or equal another
*
* Ex: new Fraction(19.6).lt([98, 5]);
**/
"lte": function (a, b) {
parse(a, b);
return this["s"] * this["n"] * P["d"] <= P["s"] * P["n"] * this["d"];
},
/**
* Check if this rational number is greater than another
*
* Ex: new Fraction(19.6).lt([98, 5]);
**/
"gt": function (a, b) {
parse(a, b);
return this["s"] * this["n"] * P["d"] > P["s"] * P["n"] * this["d"];
},
/**
* Check if this rational number is greater than or equal another
*
* Ex: new Fraction(19.6).lt([98, 5]);
**/
"gte": function (a, b) {
parse(a, b);
return this["s"] * this["n"] * P["d"] >= P["s"] * P["n"] * this["d"];
},
/**
* Compare two rational numbers
* < 0 iff this < that
* > 0 iff this > that
* = 0 iff this = that
*
* Ex: new Fraction(19.6).compare([98, 5]);
**/
"compare": function (a, b) {
parse(a, b);
let t = this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"];
return (C_ZERO < t) - (t < C_ZERO);
},
/**
* Calculates the ceil of a rational number
*
* Ex: new Fraction('4.(3)').ceil() => (5 / 1)
**/
"ceil": function (places) {
places = C_TEN ** BigInt(places || 0);
return newFraction(ifloor(this["s"] * places * this["n"] / this["d"]) +
(places * this["n"] % this["d"] > C_ZERO && this["s"] >= C_ZERO ? C_ONE : C_ZERO),
places);
},
/**
* Calculates the floor of a rational number
*
* Ex: new Fraction('4.(3)').floor() => (4 / 1)
**/
"floor": function (places) {
places = C_TEN ** BigInt(places || 0);
return newFraction(ifloor(this["s"] * places * this["n"] / this["d"]) -
(places * this["n"] % this["d"] > C_ZERO && this["s"] < C_ZERO ? C_ONE : C_ZERO),
places);
},
/**
* Rounds a rational numbers
*
* Ex: new Fraction('4.(3)').round() => (4 / 1)
**/
"round": function (places) {
places = C_TEN ** BigInt(places || 0);
/* Derivation:
s >= 0:
round(n / d) = ifloor(n / d) + (n % d) / d >= 0.5 ? 1 : 0
= ifloor(n / d) + 2(n % d) >= d ? 1 : 0
s < 0:
round(n / d) =-ifloor(n / d) - (n % d) / d > 0.5 ? 1 : 0
=-ifloor(n / d) - 2(n % d) > d ? 1 : 0
=>:
round(s * n / d) = s * ifloor(n / d) + s * (C + 2(n % d) > d ? 1 : 0)
where C = s >= 0 ? 1 : 0, to fix the >= for the positve case.
*/
return newFraction(ifloor(this["s"] * places * this["n"] / this["d"]) +
this["s"] * ((this["s"] >= C_ZERO ? C_ONE : C_ZERO) + C_TWO * (places * this["n"] % this["d"]) > this["d"] ? C_ONE : C_ZERO),
places);
},
/**
* Rounds a rational number to a multiple of another rational number
*
* Ex: new Fraction('0.9').roundTo("1/8") => 7 / 8
**/
"roundTo": function (a, b) {
/*
k * x/y ≤ a/b < (k+1) * x/y
⇔ k ≤ a/b / (x/y) < (k+1)
⇔ k = floor(a/b * y/x)
⇔ k = floor((a * y) / (b * x))
*/
parse(a, b);
const n = this['n'] * P['d'];
const d = this['d'] * P['n'];
const r = n % d;
// round(n / d) = ifloor(n / d) + 2(n % d) >= d ? 1 : 0
let k = ifloor(n / d);
if (r + r >= d) {
k++;
}
return newFraction(this['s'] * k * P['n'], P['d']);
},
/**
* Check if two rational numbers are divisible
*
* Ex: new Fraction(19.6).divisible(1.5);
*/
"divisible": function (a, b) {
parse(a, b);
if (P['n'] === C_ZERO) return false;
return (this['n'] * P['d']) % (P['n'] * this['d']) === C_ZERO;
},
/**
* Returns a decimal representation of the fraction
*
* Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183
**/
'valueOf': function () {
//if (this['n'] <= MAX_INTEGER && this['d'] <= MAX_INTEGER) {
return Number(this['s'] * this['n']) / Number(this['d']);
//}
},
/**
* Creates a string representation of a fraction with all digits
*
* Ex: new Fraction("100.'91823'").toString() => "100.(91823)"
**/
'toString': function (dec = 15) {
let N = this["n"];
let D = this["d"];
let cycLen = cycleLen(N, D); // Cycle length
let cycOff = cycleStart(N, D, cycLen); // Cycle start
let str = this['s'] < C_ZERO ? "-" : "";
// Append integer part
str += ifloor(N / D);
N %= D;
N *= C_TEN;
if (N)
str += ".";
if (cycLen) {
for (let i = cycOff; i--;) {
str += ifloor(N / D);
N %= D;
N *= C_TEN;
}
str += "(";
for (let i = cycLen; i--;) {
str += ifloor(N / D);
N %= D;
N *= C_TEN;
}
str += ")";
} else {
for (let i = dec; N && i--;) {
str += ifloor(N / D);
N %= D;
N *= C_TEN;
}
}
return str;
},
/**
* Returns a string-fraction representation of a Fraction object
*
* Ex: new Fraction("1.'3'").toFraction() => "4 1/3"
**/
'toFraction': function (showMixed = false) {
let n = this["n"];
let d = this["d"];
let str = this['s'] < C_ZERO ? "-" : "";
if (d === C_ONE) {
str += n;
} else {
const whole = ifloor(n / d);
if (showMixed && whole > C_ZERO) {
str += whole;
str += " ";
n %= d;
}
str += n;
str += '/';
str += d;
}
return str;
},
/**
* Returns a latex representation of a Fraction object
*
* Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}"
**/
'toLatex': function (showMixed = false) {
let n = this["n"];
let d = this["d"];
let str = this['s'] < C_ZERO ? "-" : "";
if (d === C_ONE) {
str += n;
} else {
const whole = ifloor(n / d);
if (showMixed && whole > C_ZERO) {
str += whole;
n %= d;
}
str += "\\frac{";
str += n;
str += '}{';
str += d;
str += '}';
}
return str;
},
/**
* Returns an array of continued fraction elements
*
* Ex: new Fraction("7/8").toContinued() => [0,1,7]
*/
'toContinued': function () {
let a = this['n'];
let b = this['d'];
const res = [];
while (b) {
res.push(ifloor(a / b));
const t = a % b;
a = b;
b = t;
}
return res;
},
"simplify": function (eps = 1e-3) {
// Continued fractions give best approximations for a max denominator,
// generally outperforming mediants in denominatoraccuracy trade-offs.
// Semiconvergents can further reduce the denominator within tolerance.
const ieps = BigInt(Math.ceil(1 / eps));
const thisABS = this['abs']();
const cont = thisABS['toContinued']();
for (let i = 1; i < cont.length; i++) {
let s = newFraction(cont[i - 1], C_ONE);
for (let k = i - 2; k >= 0; k--) {
s = s['inverse']()['add'](cont[k]);
}
let t = s['sub'](thisABS);
if (t['n'] * ieps < t['d']) { // More robust than Math.abs(t.valueOf()) < eps
return s['mul'](this['s']);
}
}
return this;
}
};
export {
Fraction as default, Fraction
};