Rational unstable
Exact rational numbers for ratios that decimal arithmetic cannot represent.
A Rational stores a bigint numerator and denominator in lowest terms, so
values such as one third survive multiplication, comparison and compounding
without rounding. Use BigDecimal for decimal quantities such as money, and
Rational when a ratio must stay exact until an explicit conversion.
Constructors
fromBigDecimal
unstableConverts a BigDecimal to the exact Rational it denotes.
When to use
Use as the exact route from decimal text: 0.1 becomes 1/10, which
fromNumber cannot produce.
See
- toBigDecimal for the rounded conversion back
Signature
declare function fromBigDecimal(n: BigDecimal): RationalExample Converting decimals exactly
import { BigDecimal, Rational } from "effect"
Rational.fromBigDecimal(BigDecimal.fromStringUnsafe("-12.50")) // => Rational.makeUnsafe(-25n, 2n)fromBigInt
unstableCreates an integer Rational from a bigint.
Signature
declare function fromBigInt(n: bigint): RationalExample Creating rationals from bigint
import { Rational } from "effect"
Rational.format(Rational.fromBigInt(-3n)) // => "-3/1"fromNumber
unstableCreates a Rational from a finite number, returning Option.none() for
NaN, +Infinity and -Infinity.
Details
The result is the exact binary value of the number, not its decimal display.
Negative zero becomes 0/1.
Gotchas
0.1 is not one tenth: the nearest double is 3602879701896397 / 2^55, and
that is the value this function returns. Use fromBigDecimal with a
decimal string when the decimal reading is intended.
See
- fromNumberUnsafe for throwing when the number is not finite
Signature
declare function fromNumber(n: number): Option<Rational>Example Creating rationals from numbers
import { Option, Rational } from "effect"
Rational.fromNumber(0.75) // => Option.some(Rational.makeUnsafe(3n, 4n))Rational.fromNumber(NaN) // => Option.none()fromNumberUnsafe
unstableCreates a Rational from a finite number.
Gotchas
Throws a RangeError if the number is not finite. See fromNumber
for why 0.1 does not become one tenth.
See
- fromNumber for returning
Option.nonewhen the number is not finite
Signature
declare function fromNumberUnsafe(n: number): RationalExample Creating rationals from trusted numbers
import { Rational } from "effect"
Rational.fromNumberUnsafe(0.5) // => Rational.makeUnsafe(1n, 2n)fromString
unstableParses an integer or fraction string into a Rational safely.
Details
Accepts [+-]digits or [+-]digits/[+-]digits. Reducible fractions and
negative denominators are normalized. Whitespace, decimal points, exponents,
the empty string and a zero denominator produce Option.none().
See
- fromStringUnsafe for parsing that throws on invalid input
- format for the inverse operation
Signature
declare function fromString(s: string): Option<Rational>Example Parsing fraction strings
import { Option, Rational } from "effect"
Rational.fromString("-4/-6") // => Option.some(Rational.makeUnsafe(2n, 3n))Rational.fromString("3") // => Option.some(Rational.fromBigInt(3n))Rational.fromString("1.5") // => Option.none()fromStringUnsafe
unstableParses an integer or fraction string into a Rational.
Gotchas
Throws an Error if the string is not a valid fraction. See
fromString for the accepted grammar.
See
- fromString for returning
Option.noneon invalid input
Signature
declare function fromStringUnsafe(s: string): RationalExample Parsing trusted fraction strings
import { Rational } from "effect"
Rational.fromStringUnsafe("6/5") // => Rational.makeUnsafe(6n, 5n)Creates a Rational from a numerator and denominator, returning
Option.none() when the denominator is zero.
Details
The result is reduced to lowest terms with a positive denominator, so
make(6n, -4n) and make(-3n, 2n) produce the same value.
See
- makeUnsafe for throwing on a zero denominator
Signature
declare function make(numerator: bigint, denominator: bigint): Option<Rational>Example Creating rationals safely
import { Option, Rational } from "effect"
Rational.make(6n, -4n) // => Option.some(Rational.makeUnsafe(-3n, 2n))Rational.make(1n, 0n) // => Option.none()makeUnsafe
unstableCreates a Rational from a numerator and denominator.
Gotchas
Throws a RangeError if the denominator is zero.
See
- make for returning
Option.noneon a zero denominator
Signature
declare function makeUnsafe(numerator: bigint, denominator: bigint): RationalExample Creating rationals from bigint pairs
import { Rational } from "effect"
Rational.format(Rational.makeUnsafe(2n, 6n)) // => "1/3"Converting
Formats a rational as numerator/denominator.
Details
The output is always a fraction in lowest terms, so integers render as
3/1 and zero as 0/1. It is the inverse of fromString.
Signature
declare function format(n: Rational): stringExample Formatting rationals
import { Rational } from "effect"
Rational.format(Rational.makeUnsafe(12n, 10n)) // => "6/5"Rational.format(Rational.fromBigInt(0n)) // => "0/1"toBigDecimal
unstableConverts a rational to a BigDecimal rounded at the given scale.
Details
scale is the number of decimal places to keep; a negative scale rounds to
tens, hundreds and so on. mode defaults to "half-from-zero", matching
BigDecimal.round.
Gotchas
Throws a RangeError if scale is not a safe integer.
See
- fromBigDecimal for the exact conversion back
Signature
declare const toBigDecimal: { (options: { readonly mode?: BigDecimal.RoundingMode; readonly scale: number; }): (self: Rational) => BigDecimal; (self: Rational, options: { readonly mode?: BigDecimal.RoundingMode; readonly scale: number; }): BigDecimal;}Example Rounding rationals to decimals
import { BigDecimal, Rational } from "effect"
const twoThirds = Rational.makeUnsafe(2n, 3n)
Rational.toBigDecimal(twoThirds, { scale: 3 }) // => BigDecimal.fromStringUnsafe("0.667")Rational.toBigDecimal(twoThirds, { scale: 3, mode: "floor" }) // => BigDecimal.fromStringUnsafe("0.666")toNumberUnsafe
unstableConverts a rational to the nearest JavaScript number.
Details
The ratio is rounded as a whole, so a numerator and denominator that each
exceed Number.MAX_VALUE still produce a finite result when their quotient
is finite. Every finite double round-trips through fromNumber.
Gotchas
This conversion is unsafe because most rationals are not representable as
doubles: the result is rounded, and very large magnitudes become
Infinity.
See
- toBigDecimal for a conversion with an explicit scale
Signature
declare function toNumberUnsafe(n: Rational): numberExample Converting rationals to numbers
import { Rational } from "effect"
Rational.toNumberUnsafe(Rational.makeUnsafe(1n, 3n)) // => 1 / 3Guards
isRational
unstableChecks whether a given value is a Rational.
Signature
declare function isRational(u: unknown): u is RationalExample Checking Rational values
import { Rational } from "effect"
Rational.isRational(Rational.fromBigInt(1n)) // => trueRational.isRational("1/3") // => falseInstances
Equivalence
unstableAn Equivalence instance for rationals. Canonical form makes this a field
comparison.
Signature
declare const Equivalence: Equ.Equivalence<Rational>An Order instance comparing rationals by exact value.
Signature
declare const Order: order.Order<Rational>Example Comparing rationals
import { BigDecimal, Rational } from "effect"
const third = Rational.makeUnsafe(1n, 3n)const nearlyThird = Rational.fromBigDecimal(BigDecimal.fromStringUnsafe("0.3333333333"))
Rational.Order(third, nearlyThird) // => 1Math
Returns the absolute value of a rational.
Signature
declare function abs(n: Rational): RationalRestricts a rational to an inclusive range.
Signature
declare const clamp: { (options: { maximum: Rational; minimum: Rational; }): (self: Rational) => Rational; (self: Rational, options: { maximum: Rational; minimum: Rational; }): Rational;}Divides self by that, returning Option.none() when that is zero.
See
- divideUnsafe for division that throws when the divisor is zero
Signature
declare const divide: { (that: Rational): (self: Rational) => Option<Rational>; (self: Rational, that: Rational): Option<Rational>;}Example Dividing rationals safely
import { Option, Rational } from "effect"
const third = Rational.makeUnsafe(1n, 3n)
Rational.divide(third, Rational.fromBigInt(3n)) // => Option.some(Rational.makeUnsafe(1n, 9n))Rational.divide(third, Rational.fromBigInt(0n)) // => Option.none()divideUnsafe
unstableDivides self by that.
Gotchas
Throws a RangeError if the divisor is zero.
See
- divide for division that returns
Option.nonewhen the divisor is zero
Signature
declare const divideUnsafe: { (that: Rational): (self: Rational) => Rational; (self: Rational, that: Rational): Rational;}Example Dividing rationals
import { Rational } from "effect"
Rational.divideUnsafe(Rational.makeUnsafe(-2n, 3n), Rational.makeUnsafe(4n, 9n)) // => Rational.makeUnsafe(-3n, 2n)Returns the larger of two rationals.
Signature
declare const max: { (that: Rational): (self: Rational) => Rational; (self: Rational, that: Rational): Rational;}Returns the smaller of two rationals.
Signature
declare const min: { (that: Rational): (self: Rational) => Rational; (self: Rational, that: Rational): Rational;}Multiplies two rationals exactly.
Signature
declare const multiply: { (that: Rational): (self: Rational) => Rational; (self: Rational, that: Rational): Rational;}Example Multiplying rationals
import { Rational } from "effect"
Rational.multiply(Rational.makeUnsafe(1n, 3n), Rational.fromBigInt(3n)) // => Rational.fromBigInt(1n)multiplyAll
unstableMultiplies all rationals in an iterable, returning one for an empty collection.
Signature
declare function multiplyAll(collection: Iterable<Rational>): RationalExample Compounding ratios
import { Rational } from "effect"
Rational.multiplyAll([Rational.makeUnsafe(3n, 2n), Rational.makeUnsafe(4n, 3n)]) // => Rational.fromBigInt(2n)Negates a rational.
Signature
declare function negate(n: Rational): RationalRaises a rational to an integer power, returning Option.none() for zero
raised to a negative exponent.
Details
A negative exponent inverts the fraction before raising it, and any value to the power zero is one, including zero itself.
Gotchas
The exponent must be a safe integer. Anything else, including 0.5, NaN
and Infinity, throws a RangeError instead of being rounded.
See
- powUnsafe for throwing when zero is raised to a negative exponent
Signature
declare const pow: { (exponent: number): (self: Rational) => Option<Rational>; (self: Rational, exponent: number): Option<Rational>;}Example Raising to integer powers
import { Option, Rational } from "effect"
Rational.pow(Rational.makeUnsafe(1n, 3n), -1) // => Option.some(Rational.fromBigInt(3n))Rational.pow(Rational.fromBigInt(0n), -1) // => Option.none()Raises a rational to an integer power.
Gotchas
Throws a RangeError for zero raised to a negative exponent, and for an
exponent that is not a safe integer.
See
- pow for returning
Option.nonewhen zero is raised to a negative exponent
Signature
declare const powUnsafe: { (exponent: number): (self: Rational) => Rational; (self: Rational, exponent: number): Rational;}Example Compounding a ratio
import { Rational } from "effect"
// Twelve pure fifths overshoot seven octaves by the Pythagorean comma.Rational.powUnsafe(Rational.makeUnsafe(3n, 2n), 12) // => Rational.makeUnsafe(531441n, 4096n)Returns the sign of a rational as an Ordering.
Signature
declare function sign(n: Rational): OrderingSubtracts that from self exactly.
Signature
declare const subtract: { (that: Rational): (self: Rational) => Rational; (self: Rational, that: Rational): Rational;}Example Subtracting rationals
import { Rational } from "effect"
Rational.subtract(Rational.fromBigInt(1n), Rational.makeUnsafe(1n, 3n)) // => Rational.makeUnsafe(2n, 3n)Adds two rationals exactly.
Signature
declare const sum: { (that: Rational): (self: Rational) => Rational; (self: Rational, that: Rational): Rational;}Example Adding rationals
import { Rational } from "effect"
Rational.sum(Rational.makeUnsafe(1n, 3n), Rational.makeUnsafe(1n, 6n)) // => Rational.makeUnsafe(1n, 2n)Sums all rationals in an iterable, returning zero for an empty collection.
Signature
declare function sumAll(collection: Iterable<Rational>): RationalExample Summing rationals
import { Rational } from "effect"
const third = Rational.makeUnsafe(1n, 3n)
Rational.sumAll([third, third, third]) // => Rational.fromBigInt(1n)Models
Represents an exact rational number as a reduced fraction.
Details
Every Rational is kept in canonical form: the numerator and denominator
share no common factor, the denominator is positive, and zero is 0/1.
Two rationals are equal exactly when their fields are equal.
Signature
interface Rational extends Equal, Pipeable, Inspectable { readonly "~effect/Rational": "~effect/Rational"; readonly denominator: bigint; readonly numerator: bigint;}Example Inspecting Rational storage
import { Rational } from "effect"
const r = Rational.makeUnsafe(6n, -4n)
r.numerator // => -3nr.denominator // => 2nPredicates
Checks whether a rational lies within an inclusive range.
Signature
declare const between: { (options: { maximum: Rational; minimum: Rational; }): (self: Rational) => boolean; (self: Rational, options: { maximum: Rational; minimum: Rational; }): boolean;}Checks whether two rationals are equal.
See
- Equivalence for passing rational equality to APIs that require an
Equivalence
Signature
declare const equals: { (that: Rational): (self: Rational) => boolean; (self: Rational, that: Rational): boolean;}isGreaterThan
unstableReturns true if the first argument is greater than the second.
Signature
declare const isGreaterThan: { (that: Rational): (self: Rational) => boolean; (self: Rational, that: Rational): boolean;}isGreaterThanOrEqualTo
unstableReturns true if the first argument is greater than or equal to the second.
Signature
declare const isGreaterThanOrEqualTo: { (that: Rational): (self: Rational) => boolean; (self: Rational, that: Rational): boolean;}Checks whether a rational is an integer, that is, whether its denominator is one.
Signature
declare function isInteger(n: Rational): booleanisLessThan
unstableReturns true if the first argument is less than the second.
Signature
declare const isLessThan: { (that: Rational): (self: Rational) => boolean; (self: Rational, that: Rational): boolean;}isLessThanOrEqualTo
unstableReturns true if the first argument is less than or equal to the second.
Signature
declare const isLessThanOrEqualTo: { (that: Rational): (self: Rational) => boolean; (self: Rational, that: Rational): boolean;}isNegative
unstableChecks whether a rational is strictly negative.
Signature
declare function isNegative(n: Rational): booleanisPositive
unstableChecks whether a rational is strictly positive.
Signature
declare function isPositive(n: Rational): booleanChecks whether a rational is zero.
Signature
declare function isZero(n: Rational): boolean