_Rational

it.grypho.scala.leonardo.core._Rational
See the_Rational companion object
final class _Rational extends _Value, Ordered[_Rational]

An exact rational number, held as an unreduced BigInt pair with the sign in the numerator and a strictly positive denominator.

A sibling _Value of _Number, exactly as _Complex and _Truth are — _Number is not replaced and not widened, so every existing _Number(x) pattern match keeps firing unchanged and the Double path stays byte-identical. A _Rational only ever enters an expression through the parser's exact mode; see Environment for the working precision that bounds it.

The promotion lattice (the Int → Double analogy logic.asTruth already uses): rational ⊕ rational is exact, rational ⊕ number is a _Numberfloat contagion. Contagion is deliberate and it is the asymmetric choice: absorbing the _Number into the rational would be perfectly lossless, since every finite Double is a dyadic rational, but it would launder representation error into an exact-looking value. Once a value is inexact it should stay visibly inexact. The contagion needs no code of its own: _Complex.parts reads a _Rational as a Double, so the existing complex kernels produce it for free.

Why a private BigInt pair rather than spire's Rational. spire normalises to lowest terms on every construction, which would have settled GcdPolicy at GcdPolicy.Eager by fiat and made the gcd-policy benchmark unrunnable. spire remains the intended engine for irrationals (Real / Algebraic); the rational representation stays in-house.

Equality is by value, not by representation: 2/6 == 1/3 holds under every policy. hashCode therefore has to reduce, which means a GcdPolicy.Lazy rational used as a hash key pays the gcd it was avoiding.

Value parameters

den

the denominator, always strictly positive

num

the numerator, carrying the sign

Attributes

Companion
object
Graph
Supertypes
trait Ordered[_Rational]
trait Comparable[_Rational]
trait _Value
trait _Expression
class Object
trait Matchable
class Any
Show all

Members list

Value members

Concrete methods

def abs: _Rational

The absolute value.

The absolute value.

Attributes

def add(that: _Rational, policy: GcdPolicy): _Rational

Sum: (a·d' + a'·d) / (d·d').

Sum: (a·d' + a'·d) / (d·d').

Deliberately the naive cross-multiplication rather than the usual gcd(d, d') refinement — that refinement is an eager-flavoured optimisation and would confound the two arms of the gcd-policy benchmark, which must vary reduction alone.

Value parameters

policy

reduction policy for the result

that

the addend

Attributes

Returns

the sum

def approximate(maxDen: BigInt): _Rational

Best rational approximation to this value with a denominator not exceeding maxDen.

Best rational approximation to this value with a denominator not exceeding maxDen.

This is the step that makes bounded-denominator rational arithmetic work: it is what keeps operands from growing without limit, and under GcdPolicy.Lazy it is the only thing that does. The algorithm is the classical continued-fraction (Stern–Brocot) truncation — walk the convergents hᵢ/kᵢ until the denominator would exceed the bound, then choose between the last convergent and the best semiconvergent that still fits, whichever lies closer. Both are already in lowest terms, so no further reduction is needed.

Depends only on the value, never on the representation, so every GcdPolicy approximates identically — the invariant the cross-policy equality test rests on.

Value parameters

maxDen

the largest denominator allowed; values below 1 leave this unchanged

Attributes

Returns

the closest rational with denominator ≤ maxDen

See also
def approximateToDigits(digits: Int): _Rational

Best rational approximation with a denominator not exceeding 10^digits.

Best rational approximation with a denominator not exceeding 10^digits.

The working-precision form of approximate: digits is the number of decimal places the approximation is good for.

Value parameters

digits

the working precision in decimal digits

Attributes

Returns

the closest rational at that precision

override def children: List[_Expression]

Sub-expressions subject to recursive structural traversal. Binder positions (e.g. the differentiation variable) are excluded.

Sub-expressions subject to recursive structural traversal. Binder positions (e.g. the differentiation variable) are excluded.

Attributes

Definition Classes
override def compare(that: _Rational): Int

Orders by value, valid because the denominator is always strictly positive.

Orders by value, valid because the denominator is always strictly positive.

Value parameters

that

the rational to compare against

Attributes

Returns

a negative, zero or positive Int as usual

Definition Classes
Ordered
def display(precision: Int): String

Renders this rational for reading: the exact fraction when it is short enough to take in, a decimal at precision places otherwise.

Renders this rational for reading: the exact fraction when it is short enough to take in, a decimal at precision places otherwise.

The two things a rational can be are very different to read. 1/3 says more as a fraction than 0.33333 does; a rational approximation of pi at 30 working digits says nothing at all as 31415.../10000..., and everything as 3.14159. So the threshold is _Rational.MaxDisplayDigits digits on either term, applied to the reduced form so an unreduced representation cannot push a short value over it.

This is display only. exact is what gets serialized, so nothing is lost.

Value parameters

precision

decimal places for the decimal form

Attributes

Returns

the fraction or the decimal, whichever reads better

def divide(that: _Rational, policy: GcdPolicy): Option[_Rational]

Quotient: (a·d') / (d·a').

Quotient: (a·d') / (d·a').

Value parameters

policy

reduction policy for the result

that

the divisor

Attributes

Returns

the quotient, or None when that is zero

override def equals(that: Any): Boolean

Value equality, by cross-multiplication — so representation never leaks.

Value equality, by cross-multiplication — so representation never leaks.

Value parameters

that

the object to compare against

Attributes

Definition Classes
Any
override def eval(env: Environment): Either[_Expression, _Value]

Returns Right(this) — a concrete rational needs no further reduction.

Returns Right(this) — a concrete rational needs no further reduction.

Value parameters

env

unused; a literal value is independent of the bindings

Attributes

Definition Classes
def exact: String

The exact fraction, always, in lowest terms: n/d, or n when the denominator is 1.

The exact fraction, always, in lowest terms: n/d, or n when the denominator is 1.

The serialization form, kept apart from display on purpose. Session writes this into a :save script, so a rational that displays as a rounded decimal still round-trips exactly — the same split that lets a graded truth value display as unknown while saving as a portable literal.

Reduces first, so the reduction policy in force never leaks into a saved script.

Attributes

override def hashCode: Int

Hashes the reduced form, as value equality requires. Note this forces the gcd a GcdPolicy.Lazy rational was avoiding.

Hashes the reduced form, as value equality requires. Note this forces the gcd a GcdPolicy.Lazy rational was avoiding.

Attributes

Definition Classes
Any
def isZero: Boolean

Whether this is exactly zero.

Whether this is exactly zero.

Attributes

def maxBitLength: Int

The larger of the two terms' bit lengths — the size measure the gcd-policy benchmark records, since it is what explains the wall-clock and predicts behaviour at precisions that were not measured.

The larger of the two terms' bit lengths — the size measure the gcd-policy benchmark records, since it is what explains the wall-clock and predicts behaviour at precisions that were not measured.

Attributes

def multiply(that: _Rational, policy: GcdPolicy): _Rational

Product: (a·a') / (d·d').

Product: (a·a') / (d·d').

Value parameters

policy

reduction policy for the result

that

the multiplier

Attributes

Returns

the product

The additive inverse.

The additive inverse.

Attributes

def pow(k: Int, policy: GcdPolicy): Option[_Rational]

Integer power.

Integer power.

Declines when the result would exceed _Rational.MaxExactPowerBits: BigInt.pow is willing to attempt a multi-gigabyte allocation, and the caller stays symbolic on None, so refusing costs an answer nobody could have used anyway (see the cap's own note).

Value parameters

k

the exponent; negative exponents invert

policy

reduction policy for the result

Attributes

Returns

this^k, None for a negative power of zero or a result above the size cap

override def rebuild(c: List[_Expression]): _Expression

Reconstructs the same node shape with replacement sub-expressions.

Reconstructs the same node shape with replacement sub-expressions.

Value parameters

newChildren

replacements in the same order and count as children

Attributes

Definition Classes
def reciprocal(policy: GcdPolicy): Option[_Rational]

The multiplicative inverse.

The multiplicative inverse.

Value parameters

policy

reduction policy for the result

Attributes

Returns

d/a, or None when this is zero

def signum: Int

-1, 0 or 1 according to the sign.

-1, 0 or 1 according to the sign.

Attributes

def subtract(that: _Rational, policy: GcdPolicy): _Rational

Difference: (a·d' − a'·d) / (d·d').

Difference: (a·d' − a'·d) / (d·d').

Value parameters

policy

reduction policy for the result

that

the subtrahend

Attributes

Returns

the difference

def toBigDecimal(digits: Int): BigDecimal

This value as a BigDecimal at digits significant digits.

This value as a BigDecimal at digits significant digits.

Value parameters

digits

the significant digits to produce (at least 1)

Attributes

Returns

the decimal expansion

def toBigIntExact: Option[BigInt]

This value as an exact integer, when it is one.

This value as an exact integer, when it is one.

Reduces first, because a policy that defers gcd can leave an integer-valued rational looking like 6/3 — testing den == 1 on the raw representation would miss it and silently downgrade an exact integer power to an approximation.

Attributes

Returns

Some(n) when this is the integer n, None otherwise

def toDouble: Double

This value as a Double, via a 17-digit decimal expansion so that a numerator or denominator too large for Double does not become an infinity on the way.

This value as a Double, via a 17-digit decimal expansion so that a numerator or denominator too large for Double does not become an infinity on the way.

Attributes

override def toString: String

Renders at Environment.DefaultPrecision decimal places, matching _Number.

Renders at Environment.DefaultPrecision decimal places, matching _Number.

Attributes

Definition Classes
Any

Inherited methods

def <(that: _Rational): Boolean

Attributes

Inherited from:
Ordered
def <=(that: _Rational): Boolean

Attributes

Inherited from:
Ordered
def >(that: _Rational): Boolean

Attributes

Inherited from:
Ordered
def >=(that: _Rational): Boolean

Attributes

Inherited from:
Ordered
def compareTo(that: _Rational): Int

Attributes

Inherited from:
Ordered

Concrete fields

val den: BigInt
val num: BigInt

Inherited fields

lazy val freeVars: Set[String]

Cached set of free variable names; O(1) after the first access.

Cached set of free variable names; O(1) after the first access.

Attributes

Inherited from:
_Expression