Node: Number Types, Next: , Previous: Numbers, Up: Numbers

Number Types

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

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


  1. As of this writing the Complex and Float types have not been implemented.