Rational numbers are exact ratios of integers. JavaScript's native Number type instead stores a binary floating-point approximation, so even a calculation made entirely from rational values can accumulate a visible error:
1 / 98 * 98; // 0.9999999999999999
new Fraction(1).div(98).mul(98); // exactly 1 Fraction.js represents the sign, numerator, and denominator with BigInt. Every result is reduced to lowest terms, and arithmetic methods return new values instead of changing their operands. This makes the library a practical foundation for probability, financial ratios, unit conversions, symbolic coefficients, and any workflow where a fraction is the value rather than merely a display format.
Exact Rational Number Calculator
The parser accepts integers, fractions, finite decimals, mixed numbers, and explicitly repeating decimals. Parentheses mark the repeating block, so 0.1(6) means \(1/6\) and 33.(982) is exact rather than a rounded decimal sample.
- Reduced fraction
- Decimal expansion
- Continued fraction
Installation and Module Formats
Install the current package from npm:
npm install fraction.js Fraction.js supports both ECMAScript modules and CommonJS:
import Fraction from 'fraction.js';
const ratio = new Fraction(355, 113);
console.log(ratio.toFraction()); // 355/113 const Fraction = require('fraction.js');
const ratio = new Fraction('355/113'); A browser build can also expose the constructor as the global Fraction variable:
<script src="fraction.min.js"></script>
<script>
const ratio = new Fraction('3/4');
</script> Constructing Values
Every constructor form normalizes the sign and reduces the fraction. Numerators and denominators may be ordinary safe integers or BigInt values:
new Fraction(3, 4);
new Fraction([3, 4]);
new Fraction({ n: 3, d: 4 });
new Fraction(123n, 100n);
new Fraction('1.25'); // 5/4
new Fraction('4 3/7'); // 31/7
new Fraction('0.(3)'); // 1/3
new Fraction('12.34(56)'); // repeating 56 Use a string when a decimal must be interpreted exactly as written. Passing 0.1 as a number first creates a binary floating-point value; Fraction.js then finds a nearby rational through its numerical approximation logic. Passing '0.1' directly describes the exact decimal ratio \(1/10\) without that intermediate conversion. The distinction matters for long decimals and values outside JavaScript's safe-integer range.
Immutable Arithmetic
Arithmetic methods accept the same input forms as the constructor and return a new reduced fraction. The original operands remain unchanged:
const taxRate = new Fraction('19/100');
const net = new Fraction('2499/100');
const gross = net.mul(taxRate.add(1));
console.log(net.toFraction()); // 2499/100
console.log(gross.toFraction()); // 297381/10000 The core operations compose directly:
const value = new Fraction('7/12')
.add('5/18')
.sub('1/9')
.mul(6)
.div('3/2');
console.log(value.toFraction()); // 3 Unary methods include abs(), neg(), and inverse(). Comparisons use equals(), compare(), lt(), lte(), gt(), and gte(), avoiding an early conversion back to an imprecise Number.
Exact Powers and Logarithms
Integer powers of a rational number remain rational. Fraction.js also accepts rational exponents when the required roots are exact. If the mathematical result is irrational, pow() returns null rather than pretending that a floating-point approximation is an exact fraction:
new Fraction('16/81').pow('3/4').toFraction(); // 8/27
new Fraction(2).pow('1/2'); // null
new Fraction(8).log(2).toFraction(); // 3
new Fraction(2).log(10); // null This boundary is intentional. Fraction.js computes in \(\mathbb{Q}\); it is not an arbitrary-precision real-number or symbolic-algebra system.
Fractions, Decimals, and LaTeX
The same value can be serialized for different audiences:
const value = new Fraction('22/7');
value.toFraction(); // "22/7"
value.toFraction(true); // "3 1/7"
value.toString(); // "3.(142857)"
value.toLatex(); // "\\frac{22}{7}"
value.toContinued(); // [3, 7]
value.valueOf(); // an approximate JavaScript Number toFraction(), toString(), and toLatex() preserve exact information in a textual form. valueOf() is the explicit escape hatch into floating-point arithmetic and can overflow or round when the rational value exceeds what Number can represent. Continued-fraction coefficients are returned as BigInt values in current releases.
Repeating Decimals Are Rational
A repeating decimal is not an approximation. If \(x=0.(142857)\), then multiplying by \(10^6\) shifts one full period:
\[ 10^6x-x=142857, \qquad x=\frac{142857}{999999}=\frac17. \]
Fraction.js performs this conversion directly in its string parser:
const seventh = new Fraction('0.(142857)');
seventh.equals('1/7'); // true
seventh.toString(); // "0.(142857)" Parentheses or quotes must identify the repeating block explicitly. A finite sample such as '0.142857142857' is a different rational number; the parser cannot infer that omitted digits were meant to continue forever.
Remainders and Mathematical Modulo
mod() follows remainder semantics, so a negative dividend can produce a negative result. Normalize the remainder when an application needs a representative in the interval from zero up to the positive modulus:
const value = new Fraction(-1);
const modulus = new Fraction('10.99');
value.mod(modulus).toFraction(); // -1
value.mod(modulus).add(modulus).mod(modulus)
.toFraction(); // 999/100 Exact decimal parsing also avoids the familiar floating-point remainder artifact:
4.55 % 0.05; // 0.04999999999999957
new Fraction('4.55').mod('0.05').toString(); // "0" Controlled Approximation
Sometimes the input is deliberately approximate. simplify(epsilon) searches for a smaller fraction whose value remains within the requested absolute tolerance:
new Fraction('0.33333')
.simplify(0.001)
.toFraction(); // 1/3 The tolerance changes the value, so simplification should be an explicit domain decision. Do not apply it to money, counts, identifiers, or other quantities that were exact before the call.
BigInt Representation and Limits
The public attributes s, n, and d contain the sign, nonnegative numerator, and positive denominator. All three are BigInt values:
const value = new Fraction('-12345678901234567890/7');
value.s; // -1n
value.n; // 12345678901234567890n
value.d; // 7n BigInt removes the old 32-bit and safe-integer ceilings from exact internal arithmetic, but not every practical limit. Numerators and denominators can grow quickly under repeated multiplication, exponentiation, or addition of unrelated denominators. Runtime and memory therefore scale with operand size. Parsing errors and division by zero throw exceptions and should be handled at application boundaries.
Fraction.js is most effective when the problem is genuinely rational and exact. Keep values as fractions throughout the calculation, serialize them explicitly, and convert to Number only where a floating-point API such as canvas rendering requires it.