# Rational tutorial¶

`rational`

is a class that builds upon `integer`

to provide
an implementation of rational numbers represented as a numerator-denominator
`integer`

pairs.

Like `integer`

, `rational`

is parametrised over
an integral value `SSize`

which represents the number of limbs that will be
stored directly within both the numerator and the denominator before resorting to dynamic memory allocation
(see the integer tutorial for a detailed explanation of the meaning
of the `SSize`

parameter).

The `rational`

class adopts the usual *canonical* representation of rational numbers:

numerator and denominator are coprime,

the denominator is always strictly positive.

This representation is usually enforced automatically by the `rational`

API (however,
a couple of low-level functions are available to access and mutate directly the numerator and the denominator
in performance-critical scenarios).

In addition to the features common to all mp++ classes, the `rational`

API provides
a few additional capabilities:

it is possible to construct a

`rational`

from an integral pair of arguments representing the numerator and the denominator:rat_t q1{3, 4}; // Construction from int numerator and denominator. rat_t q2{long(-6), short(-8)}; // Construction from mixed numerator and denominator types. assert(q1 == q2); // Construction canonicalises the rational.

it is possible to get const and mutable references to the

`integer`

objects representing the numerator and the denominator via the`mppp::rational::get_num()`

,`mppp::rational::get_den()`

,`mppp::rational::_get_num()`

and`mppp::rational::_get_den()`

member functions. These accessors allow to use any function from the`integer`

API on the numerator and on the denominator:rat_t q1{2, 5}; assert(q1.get_num() == 2); // Const access to numerator and denominator. assert(q1.get_den() == 5); q1._get_num() = 1; // Mutable access to numerator and denominator. q1._get_den() = 3; assert(q1 == rat_t{1, 3});

the

`mppp::rational::canonicalise()`

member function (and its free function counterpart) can be used to canonicalise a`rational`

. This is normally not necessary, unless the numerator or the denominator have been changed manually via the mutable getters:rat_t q1{1, 6}; q1._get_num() = 9; // Change the numerator using the mutable getter. // WARNING: q1 = 9/6, not in canonical form any more! q1.canonicalise(); // Canonicalise q1. assert(q1 == rat_t{3, 2});

a few additional arithmetic and comparison functions are available;

a few exponentiation and number-theoretic functions are available;

like

`integer`

,`rational`

also provides a specialisation of`std::hash`

for use in the standard unordered containers.

Many of these features, which are documented in detail in the rational reference, are available in multiple overloads, often both as free and member functions.

## Interacting with the GMP API¶

Like `integer`

, `rational`

provides facilities for interfacing
with the GMP library. Currently, the interoperability is limited to
`rational`

objects being able to be constructed and assigned from both `mpz_t`

and `mpq_t`

objects:

```
mpz_t m;
mpz_init_set_si(m, -4); // Init an mpz_t with the value -4.
rat_t q1{m}; // Init a rat_t from the mpz_t.
assert(q1 == -4); // Verify that the value is correct.
mpq_t q;
mpq_init(q);
mpq_set_si(q, 3, 4); // Init an mpq_t with the value 3/4.
rat_t q2{q}; // Init a rat_t from the mpq_t.
assert((q2 == rat_t{3, 4})); // Verify that the value is correct.
rat_t q3;
q3 = m; // Assign the mpz_t to another rat_t.
assert(q3 == -4); // Verify that the value is correct.
rat_t q4;
q4 = q; // Assign the mpq_t to another rat_t.
assert((q4 == rat_t{3, 4})); // Verify that the value is correct.
mpz_clear(m); // Clear the mpz_t.
mpq_clear(q); // Clear the mpq_t.
```