NAME
Sidef::Types::Number::Fraction - A ratio of two numeric (or symbolic) values.
DESCRIPTION
This class represents a fraction: a numerator and a denominator kept as a pair, rather than eagerly reduced to a single numeric value. This avoids the rounding that immediate division would cause and lets you inspect the numerator and denominator separately.
The numerator and denominator are not restricted to plain integers — anything that behaves like a Number works, including another Fraction or a Polynomial. This lets a Fraction double as a symbolic rational expression (a ratio of two polynomials) as well as an ordinary numeric fraction; see "eval" and "CONSTRUCTION" below.
SYNOPSIS
var f = Fraction(3, 4)
say f.class # "Fraction"
var a = Fraction(1, 2)
var b = Fraction(1, 3)
say (a + b) # Fraction(5, 6)
say (a - b) # Fraction(1, 6)
say (a * b) # Fraction(1, 6)
say (a / b) # Fraction(3, 2)
say f.numerator # 3
say f.denominator # 4
say f.to_n # 0.75
INHERITS
Inherits methods from Sidef::Types::Number::Number.
CONSTRUCTION
new
Fraction(num, den)
Fraction(num)
Fraction()
Creates a new Fraction with numerator num and denominator den. den defaults to 1 if omitted, and num defaults to 0, so Fraction() is 0 and Fraction(5) is 5.
say Fraction(3, 4) # Fraction(3, 4)
say Fraction(5) # Fraction(5, 1)
say Fraction() # Fraction(0, 1)
Calling .new (or the equivalent bareword call) on an existing Fraction instead evaluates it as a symbolic rational expression at the given value — the same thing "eval" does:
var f = Fraction(Poly("x"), 1)
say f.new(3) # evaluates f at x=3
Aliases: call
with_value
self.with_value(num, den)
Builds a new Fraction with the given numerator and denominator, ignoring the receiver's own value. Useful in generic code that has a Fraction in hand and wants to construct another one of the same type without naming the class directly.
var f = Fraction(1, 2)
var g = f.with_value(3, 4)
say g # Fraction(3, 4)
COMPONENTS
nu
self.nu
Returns the numerator.
say Fraction(3, 4).nu # 3
Aliases: num, numerator
de
self.de
Returns the denominator, exactly as stored (no sign normalization is applied by this class).
say Fraction(3, 4).de # 4
Aliases: den, denominator
nude
self.nude
Returns both the numerator and denominator together.
var (num, den) = Fraction(3, 4).nude
say "#{num}/#{den}" # "3/4"
parts
self.parts
Returns an array containing the numerator and the denominator: [numerator, denominator].
say Fraction(3, 4).parts # [3, 4]
as_mixed
self.as_mixed
Returns a three-element array [quotient, remainder, denominator] representing the fraction as a mixed number, computed as numerator.divmod(denominator) plus the original denominator.
say Fraction(5, 3).as_mixed # [1, 2, 3] (i.e. 1 and 2/3)
TYPE CONVERSION
to_n
self.to_n
Converts the fraction to a plain numeric value by dividing the numerator by the denominator (after first reducing each side with its own to_n, so a symbolic numerator/denominator is resolved too). This backs the fraction's boolean and numeric contexts, so a Fraction is falsy exactly when to_n is zero.
say Fraction(3, 4).to_n # 0.75
say Fraction(6, 2).to_n # 3
if (Fraction(0, 5)) { say "truthy" } else { say "falsy" } # falsy
lift
self.lift
Returns a new Fraction with both the numerator and denominator "lifted" via their own lift method — typically used to promote plain values into a more general symbolic context (e.g. when mixing fractions with polynomials).
STRING REPRESENTATION
stringify
self.stringify
Returns a readable math-style representation of the fraction, built from each side's own stringify, in the form (numerator)/(denominator). This is different from "to_s"/"dump", which use a constructor-style form instead.
say Fraction(3, 4).stringify # "(3)/(4)"
Aliases: pretty
to_s
self.to_s
Returns the constructor-style string representation of the fraction, e.g. "Fraction(3, 4)". This is also what a Fraction produces when stringified implicitly (e.g. via interpolation).
say Fraction(3, 4).to_s # "Fraction(3, 4)"
say "f = #{Fraction(3,4)}" # "f = Fraction(3, 4)"
dump
self.dump
Same as "to_s" — returns the constructor-style string representation, e.g. "Fraction(3, 4)".
say Fraction(3, 4).dump # "Fraction(3, 4)"
ARITHMETIC OPERATIONS
add
a + b
Adds two values. If b is also a Fraction, the two are added via cross-multiplication (a/b + c/d = (ad+bc)/bd); otherwise b is treated as b/1.
say (Fraction(1, 2) + Fraction(1, 3)) # Fraction(5, 6)
say (Fraction(1, 2) + 1) # Fraction(3, 2)
Aliases: +
sub
a - b
Subtracts b from the fraction (implemented as a + (-b)).
say (Fraction(1, 2) - Fraction(1, 3)) # Fraction(1, 6)
Aliases: -
mul
a * b
Multiplies two values. If b is also a Fraction, numerators and denominators are multiplied pairwise; otherwise b only multiplies the numerator.
say (Fraction(1, 2) * Fraction(2, 3)) # Fraction(1, 3)
say (Fraction(1, 2) * 3) # Fraction(3, 2)
Aliases: *
div
a / b
Divides the fraction by b. If b is also a Fraction, this multiplies by its reciprocal; otherwise b only multiplies the denominator.
say (Fraction(1, 2) / Fraction(1, 3)) # Fraction(3, 2)
say (Fraction(1, 2) / 2) # Fraction(1, 4)
Aliases: /, ÷
sqr
self.sqr
Returns the fraction squared (numerator and denominator each squared).
say Fraction(2, 3).sqr # Fraction(4, 9)
inv
self.inv
Returns the reciprocal of the fraction (numerator and denominator swapped).
say Fraction(3, 4).inv # Fraction(4, 3)
neg
self.neg
-f
Returns the negation of the fraction (numerator negated).
say Fraction(3, 4).neg # Fraction(-3, 4)
inc
self.inc
Returns the fraction plus one.
say Fraction(1, 2).inc # Fraction(3, 2)
Aliases: ++
dec
self.dec
Returns the fraction minus one.
say Fraction(1, 2).dec # Fraction(-1, 2)
Aliases: --
pow
a ** n
Raises the fraction to the power n. A negative exponent inverts the fraction and applies the absolute exponent instead, i.e. (a/b)**(-n) == (b/a)**n.
say (Fraction(2, 3) ** 2) # Fraction(4, 9)
say (Fraction(2, 3) ** -2) # Fraction(9, 4)
Aliases: **
mod
a % b
Computes the fraction modulo b. If b is not a Fraction, this instead builds a new Fraction whose numerator and denominator are each reduced modulo b (deferring to Sidef::Types::Number::Mod arithmetic) — useful as a stepping stone for modular-inverse computations such as "invmod". If b is itself a Fraction, the ordinary real-number definition is used: a - b * floor(a/b).
say (Fraction(7, 2) % Fraction(1, 1)) # Fraction(1, 2)
Aliases: %
invmod
self.invmod(n)
Computes the modular inverse of the fraction with respect to n, via self.inv.mod(n).
powmod
self.powmod(n, m)
Computes self**n modulo m efficiently, using binary exponentiation. Supports negative exponents (via "invmod" on the final result).
say Fraction(3, 1).powmod(10, 1000) # 3**10 mod 1000
BIT SHIFTING
lsft
a << n
Left-shifts the fraction by n bits — equivalent to multiplying by 2**n — by shifting the numerator.
say (Fraction(3, 4) << 2) # Fraction(12, 4)
Aliases: <<
rsft
a >> n
Right-shifts the fraction by n bits — equivalent to dividing by 2**n — by left-shifting the denominator.
say (Fraction(3, 4) >> 2) # Fraction(3, 16)
Aliases: >>
ROUNDING
floor
self.floor
Returns the largest integer less than or equal to the fraction.
say Fraction(7, 2).floor # 3
say Fraction(-7, 2).floor # -4
ceil
self.ceil
Returns the smallest integer greater than or equal to the fraction.
say Fraction(7, 2).ceil # 4
round
self.round
Rounds the fraction to the nearest integer.
say Fraction(7, 2).round # 4
trunc
self.trunc
Truncates the fraction toward zero.
say Fraction(7, 2).trunc # 3
say Fraction(-7, 2).trunc # -3
COMPARISON
All comparisons work by cross-multiplication: comparing a/b to c/d compares a*d to b*c directly, without computing either division. If the right-hand side isn't already a Fraction, it's treated as value/1 first.
eq
a == b
Returns true if the two values represent the same fraction.
say ((Fraction(1, 2) == Fraction(2, 4))) # true
Aliases: ==
ne
a != b
Returns true if the two values do not represent the same fraction.
Aliases: !=
lt
a < b
Returns true if the fraction is less than b.
Aliases: <
le
a <= b
Returns true if the fraction is less than or equal to b.
Aliases: <=, ≤
gt
a > b
Returns true if the fraction is greater than b.
Aliases: >
ge
a >= b
Returns true if the fraction is greater than or equal to b.
Aliases: >=, ≥
cmp
a <=> b
Three-way comparison: returns -1, 0, or 1.
Aliases: <=>
BITWISE-STYLE OPERATIONS
and
a & b
Cross-multiplies a and b the same way the comparison operators do, then applies the underlying numeric and (bitwise AND) to the two products.
Aliases: &
or
a | b
Cross-multiplies a and b, then applies the underlying numeric or (bitwise OR) to the two products.
Aliases: |
xor
a ^ b
Cross-multiplies a and b, then applies the underlying numeric xor (bitwise XOR) to the two products.
Aliases: ^
PREDICATES
is_zero
self.is_zero
Returns true if the fraction is equal to zero.
is_one
self.is_one
Returns true if the fraction is equal to one.
is_mone
self.is_mone
Returns true if the fraction is equal to negative one.
is_proper
self.is_proper
Returns true if the numerator is less than the denominator (a direct comparison — not of absolute values). Note that this means any fraction with a negative numerator and a positive denominator is "proper" by this test, regardless of magnitude.
say Fraction(2, 3).is_proper # true
say Fraction(5, 3).is_proper # false
say Fraction(-5, 3).is_proper # true
is_improper
self.is_improper
The negation of "is_proper".
is_nan
self.is_nan
Returns true if the fraction is 0/0, or if either the numerator or the denominator is itself NaN.
is_real
self.is_real
Returns false for 0/0; otherwise returns true only if both the numerator and the denominator are real.
SYMBOLIC EVALUATION
eval
self.eval(value)
Evaluates the fraction as a rational expression at value, by evaluating the numerator and denominator separately and dividing the results. For a Fraction of plain numbers this just returns the fraction's own value; it's most useful when the numerator and/or denominator are polynomials.
var f = Fraction(Poly("x")**2, Poly("x") + 1)
say f.eval(3) # (3**2) / (3+1) = 9/4
EXAMPLES
Basic Fraction Arithmetic
var a = Fraction(1, 3)
var b = Fraction(1, 6)
say (a + b) # Fraction(1, 2)
say (a - b) # Fraction(1, 6)
say (a * b) # Fraction(1, 18)
say (a / b) # Fraction(2, 1)
Converting to a Mixed Number
var f = Fraction(17, 5)
var mixed = f.as_mixed
say "#{mixed[0]} and #{mixed[1]}/#{mixed[2]}" # "3 and 2/5"
Comparing Fractions
var half = Fraction(1, 2)
var third = Fraction(1, 3)
say ((half > third)) # true
say (half <=> third) # 1
Modular Exponentiation
var f = Fraction(3, 1)
say f.powmod(100, 1000007)
NOTES
Fraction inherits from Sidef::Types::Number::Number, so a number of general numeric methods — such as abs, sign, is_pos, is_neg, is_int, and conversions like int/to_i and float/to_f — are available on Fraction objects even though they aren't defined in this file. Consult Number's own documentation for their exact behavior.
This class does not normalize the sign of the denominator or automatically reduce fractions to lowest terms; the numerator and denominator are kept exactly as given (or as produced by an arithmetic operation).