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).

SEE ALSO

Sidef::Types::Number::Number