# aiken/math/rational

This module implements operations between rational numbers. Internally, rational aren’t automatically reduced as this is only done on-demand.

Thus, for example:

``````rational.new(2, 3) != rational.new(4, 6)
``````

Comparing rational values should, therefore, only happen after reduction (see reduce) or via the compare method.

# Types

## Rational

Opaque type used to ensure the sign of the Rational is managed strictly in the numerator.

# Functions

## `abs(self: Rational) -> Rational`

Absolute value of a `Rational`.

``````expect Some(x) = rational.new(3, 2)
expect Some(y) = rational.new(-3, 2)

rational.abs(x) == x
rational.abs(y) == x
``````

## `add(left: Rational, right: Rational) -> Rational`

Addition: sum of two rational values

``````expect Some(x) = rational.new(2, 3)
expect Some(y) = rational.new(3, 4)

``````

## `arithmetic_mean(self: List<Rational>) -> Option<Rational>`

Calculate the arithmetic mean between two `Rational` values.

``````let x = rational.from_int(0)
let y = rational.from_int(1)
let z = rational.from_int(2)

expect Some(result) = rational.arithmetic_mean([x, y, z])

rational.compare(result, y) == Equal
``````

## `ceil(self: Rational) -> Int`

Returns the smallest `Int` not less than a given `Rational`

``````expect Some(x) = rational.new(2, 3)
rational.ceil(x) == 1

expect Some(y) = rational.new(44, 14)
rational.ceil(y) == 4

expect Some(z) = rational.new(-14, 3)
rational.ceil(z) == -4
``````

## `compare(left: Rational, right: Rational) -> Ordering`

Compare two rationals for an ordering. This is safe to use even for non-reduced rationals.

``````expect Some(x) = rational.new(2, 3)
expect Some(y) = rational.new(3, 4)
expect Some(z) = rational.new(4, 6)

compare(x, y) == Less
compare(y, x) == Greater
compare(x, x) == Equal
compare(x, z) == Equal
``````

## ```compare_with( left: Rational, with: fn(Int, Int) -> Bool, right: Rational, ) -> Bool```

Comparison of two rational values using a chosen heuristic. For example:

``````expect Some(x) = rational.new(2, 3)
expect Some(y) = rational.new(3, 4)

rational.compare_with(x, >, y) == False
rational.compare_with(y, >, x) == True
rational.compare_with(x, >, x) == False
rational.compare_with(x, >=, x) == True
rational.compare_with(x, ==, x) == True
rational.compare_with(x, ==, y) == False
``````

## `denominator(self: Rational) -> Int`

Get the denominator of a rational value.

``````expect Some(x) = rational.new(2, 3)
rational.denominator(x) == 3
``````

## `div(left: Rational, right: Rational) -> Option<Rational>`

Division: quotient of two rational values. Returns `None` when the second value is null.

``````expect Some(x) = rational.new(2, 3)
expect Some(y) = rational.new(3, 4)

rational.div(x, y) == rational.new(8, 9)
``````

## `floor(self: Rational) -> Int`

Returns the greatest `Int` no greater than a given `Rational`

``````expect Some(x) = rational.new(2, 3)
rational.floor(x) == 0

expect Some(y) = rational.new(44, 14)
rational.floor(y) == 3

expect Some(z) = rational.new(-14, 3)
rational.floor(z) == -5
``````

## `from_int(numerator: Int) -> Rational`

Create a new `Rational` from an `Int`.

``````Some(rational.from_int(14)) == rational.new(14, 1)
Some(rational.from_int(-5)) == rational.new(-5, 1)
Some(rational.from_int(0)) == rational.new(0, 1)
``````

## `geometric_mean(left: Rational, right: Rational) -> Option<Rational>`

Calculate the geometric mean between two `Rational` values. This returns either the exact result or the smallest integer nearest to the square root for the numerator and denominator.

``````expect Some(x) = rational.new(1, 3)
expect Some(y) = rational.new(1, 6)

rational.geometric_mean(x, y) == rational.new(1, 4)
``````

## `mul(left: Rational, right: Rational) -> Rational`

Multiplication: the product of two rational values.

``````expect Some(x) = rational.new(2, 3)
expect Some(y) = rational.new(3, 4)

Some(rational.mul(x, y)) == rational.new(6, 12)
``````

## `negate(a: Rational) -> Rational`

Change the sign of a `Rational`.

``````expect Some(x) = rational.new(3, 2)
expect Some(y) = rational.new(-3, 2)

rational.negate(x) == y
rational.negate(y) == x
``````

## `new(numerator: Int, denominator: Int) -> Option<Rational>`

Make a `Rational` number from the ratio of two integers.

Returns `None` when the denominator is null.

``````rational.new(14, 42) == Some(r)
rational.new(14, 0) == None
``````

## `numerator(self: Rational) -> Int`

Get the numerator of a rational value.

``````expect Some(x) = rational.new(2, 3)
rational.numerator(x) == 2
``````

## `proper_fraction(self: Rational) -> (Int, Rational)`

Returns the proper fraction of a given `Rational` `r`. That is, a pair of an `Int` and `Rational` (n, f) such that:

• `r = n + f`;
• `n` and `f` have the same sign as `r`;
• `f` has an absolute value less than 1.

## `reciprocal(self: Rational) -> Option<Rational>`

Reciprocal of a `Rational` number. That is, a new `Rational` where the numerator and denominator have been swapped.

``````expect Some(x) = rational.new(2, 5)
rational.reciprocal(x) == rational.new(5, 2)

let y = rational.zero()
rational.reciprocal(y) == None
``````

## `reduce(self: Rational) -> Rational`

Reduce a rational to its irreducible form. This operation makes the numerator and denominator coprime.

``````expect Some(x) = rational.new(80, 200)
Some(rational.reduce(x)) == rational.new(2, 5)
``````

## `round(self: Rational) -> Int`

Round the argument to the nearest whole number. If the argument is equidistant between two values, the greater value is returned (it rounds half towards positive infinity).

``````expect Some(x) = rational.new(2, 3)
rational.round(x) == 1

expect Some(y) = rational.new(3, 2)
rational.round(y) == 2

expect Some(z) = rational.new(-3, 2)
rational.round(z) == -1
``````

⚠️ This behaves differently than Haskell. If you’re coming from `PlutusTx`, beware that in Haskell, rounding on equidistant values depends on the whole number being odd or even. If you need this behaviour, use `round_even`.

## `round_even(self: Rational) -> Int`

Round the argument to the nearest whole number. If the argument is equidistant between two values, it returns the value that is even (it rounds half to even, also known as ‘banker’s rounding’).

``````expect Some(w) = rational.new(2, 3)
rational.round_even(w) == 1

expect Some(x) = rational.new(3, 2)
rational.round_even(x) == 2

expect Some(y) = rational.new(5, 2)
rational.round_even(y) == 2

expect Some(y) = rational.new(-3, 2)
rational.round_even(y) == -2
``````

## `sub(left: Rational, right: Rational) -> Rational`

Subtraction: difference of two rational values

``````expect Some(x) = rational.new(2, 3)
expect Some(y) = rational.new(3, 4)

Some(rational.sub(x, y)) == rational.new(-1, 12)
``````

## `truncate(self: Rational) -> Int`

Returns the nearest `Int` between zero and a given `Rational`.

``````expect Some(x) = rational.new(2, 3)
rational.truncate(x) == 0

expect Some(y) = rational.new(44, 14)
rational.truncate(y) == 3

expect Some(z) = rational.new(-14, 3)
rational.truncate(z) == -4
``````

## `zero() -> Rational`

A null `Rational`.