Lpp's type hierarchy for numbers is depicted in the following diagram
^{1}

Number | --------------------------- | | | Complex Float Rational | ----------------- | | Ratio Integer | ------------------------- | | BigInteger SmallInteger | ----------------- | | MinusBigInteger PlusBigInteger

All of the number types fall into a more general type above them in
the hierarchy. For example a `Rational`

is also a `Number`

type and an `Integer`

is also a `Rational`

type and a
`Number`

type, and so on and so forth. In Lpp this can be
demonstrated by the code

let x = L(18); typep(x, type(Number)) => t typep(x, type(Integer)) => t typep(x, type(SmallInteger)) => t typep(x, type(BigInteger)) => nil typep(x, type(Ratio)) => nil

The `Integer`

type is by far the most important for doing
symbolic mathematics where overflow or underflow can not be tolerated,
such as systems that manipulate polynomials symbolically. Thus
integers can fall into the range of minus infinity to plus infinity.
Lpp implements this with the `BigInteger`

type. When an integer
starts out in Lpp it can be a `SmallInteger`

or `BigInteger`

let x = L(21); let y = readFromString("2222222222222222221111111111111111111);

In this example `x`

starts off as a `SmallInteger`

and
`y`

starts off as a `BigInteger`

. More specifically
`y`

is a `PlusBigInteger`

print(typeOf(x)) => <Lpp Type for SmallInteger> print(typeOf(y)) => <Lpp Type for PlusBigInteger>

As Lpp math functions are applied to an integer it can expand from a
`SmallInteger`

into a `BigInteger`

and vice verse. If the
following code were allowed to loop

while(1) { x = inc(x); y = dec(y);}

then `x`

would eventually transform from a `SmallInteger`

to
a `BigInteger`

and `y`

from a `BigInteger`

back into a
`SmallInteger`

. `BigInteger`

objects can grow unlimited
toward plus or minus infinity.

A `Rational`

number can either be an `Integer`

or a
`Ratio`

, where a `Ratio`

is nothing more than a pair of
`Integer`

objects. The first of the pair being the numerator of
the ratio and the second being the denominator. A `Ratio`

number
can start off being read from an s-expression stream or as the result
of a math function

let a = readFromString("12/3"); let w = readFromString("21/22222222221111111111");' let z = divide(x, y);

As with Common Lisp in Lpp any computation or notation that produces a
ratio such that the numerator and denominator can be evenly divided by
an integer then the numerator and denominator are immediately
converted to the divided results. Or in other words the result is
always immediately canonicalized. So given the variables `a`

and
`w`

in the above example

print(a) => 4 print(w) => 7/7407407407037037037

Note that the canonicalization takes place immediately on the
`readFromString`

or `divide`

above and not just on the
`print`

, so that there never exists a non-canonicalized rational
number in Lpp.