Numbers and Arithmetic

<-Previous | ^UP^ | Next->

In the Defining Objects section, we briefly touched on numbers and arithmetic

(define-object my-box-4 (box):input-slots(length(width 4)(height 4))):computed-slots((density 7800)(mass (* (div (the volume) 1000000000) (the density)))))

In this section we will take a bit more detailed look at how GendL handles numbers and arithmetic.

The majority of this is pure Common Lisp (CL), although GendL does define a few Convenience Functions which may be classed as arithmetic.

CL has four number types:

  • Integers (e.g. 1, 38, 183749372628)
  • Floating Point (e.g. 253.67, 2.52E+26)
  • Ratios (e.g. 6/7, 347/395)
  • Complex (e.g. (#C(0 5), representing the square root of -25)
  • In contrast with other languages, you don't need to worry too much about the type of number you are using, as the CL runtime system will sort that out for us (unless you need to intervene for specific performance reasons by bypassing the dynamic typing feature).

    CL can handle rational numbers with "infinite" precision. For example, the number 1/3 represents one-third with no loss of precision as happens with the decimal representation of 0.33333... truncated to some arbitray number of decimal places.

    And there is no realistic limit on the maximum size of a number that CL can represent (although Integers up to a certain size may be processed more efficiently than arbitrarily huge Integers).

    Arithmetic functions

    There are four basic CL arithmetic functions

    • +
    • -
    • *
    • /
    Additionally GendL defines a fifth:
    • div
    and two shortcut functions
    • half
    • twice

    As with all Lisp dialects, CL uses prefix notation for functions. All five basic arithmetic functions (+, -, *, /, and div) can take one or more arguments, while + and * can also take zero arguments.

    CL function +

    The return value from + depends on the number of arguments it is given.

    • Zero Arguments - returns 0
    • One Argument - returns the argument
    • Two or more arguments - returns the sum of all the arguments

    GDL-USER> (+)

    0

    GDL-USER> (+ 5)

    5

    GDL-USER> (+ 5 1 9 2)

    17

    Also note that because Lisp evaluates functions inside-out, (+ 1 2 3) is equivalent to (+ (+ 1 2) 3)

    More about functions later.

    CL function -

    The - function requires at least one argument. If no arguments are supplied, then an error will result.

    The return value from - depends on the number of arguments it is given.

    • One Argument - returns the negative value of the supplied argument
    • Two or more arguments - accumulates the value of each argument subrtacted from the previous argument and returns the final result.

    GDL-USER> (- 5)

    -5

    GDL-USER> (- 5 1 9 2)

    -7

    GDL-USER> (- 1 -5)

    6

    CL function *

    The return value from * depends on the number of arguments it is given.

    • Zero Arguments - returns 1.
    • One Argument - returns the argument.
    • Two or more arguments - returns the product of all the arguments.

    GDL-USER> (*)

    1

    GDL-USER> (* 2)

    2

    GDL-USER> (* 2 3 4)

    24

    GDL-USER> (* 2 -3 4)

    -24

    CL function /

    The / requires at least one argument. If no arguments are supplied, then an error will result.

    The return value from / depends on the number of arguments it is given and the value of the result

    • One Argument - returns the reciprocal of the argument as a ratio (1/argument).
    • Two or more arguments - returns the value of the first argument divided by the product of the remaining arguments. If the resulting answer is a whole number, then the return value will be a whole number. Otherwise it will be a ratio with the least possible whole denominator.

    GDL-USER> (/ 3)

    1/3

    GDL-USER> (/ 10 2)

    5

    GDL-USER> (/ 10 3)

    10/3

    GDL-USER> (/ 10 2 5)

    1

    GDL-USER> (/ 10 1 6)

    5/3

    GendL function div

    The GendL function div is identical in operation to the Lisp function / except it uses rational division and converts the return value to a floating point number

    GDL-USER> (div 3)

    0.3333333333333333

    GDL-USER> (div 10 2)

    5.0

    GDL-USER> (div 10 3)

    3.3333333333333333

    GDL-USER> (div 10 2 5)

    1.0

    GDL-USER> (div 10 1 6)

    1.6666666666666667

    GendL function half

    The GendL function half takes a single argument and returns the result of dividing that argument by the integer 2. The type of the returned number will depend on the type of the argument

    GDL-USER> (half 5)

    5/2

    GDL-USER> (half 5.0)

    2.5

    GDL-USER> (half 5/3)

    5/6

    GendL function twice

    The GendL function twice takes a single argument and returns the result of multiplying The argument by the integer 2. The type of the returned number will depend on the type of the argument.

    GDL-USER> (twice 5)

    10

    GDL-USER> (twice 5.0)

    10.0

    GDL-USER> (twice 5/3)

    10/3

    Arithmetic Precedence

    Due to Lisp's generalized prefix notation for functions, and the basic rule that functions are evaluated inside-out (in other words, the innermost functions are evaluated first), precedence of arithmetic operators is completely explicit in Lisp. The example below shows conceptually how a long arithmetic expression is broken down during evaluation

    GDL-USER> (/ (* (+ 2 3) (- 3 4)) (* (- 2 6) (+ 2 (* 2 3))))

    5/32

    GDL-USER> (/ (* (+ 2 3) (- 3 4)) (* (- 2 6) (+ 2 6)))

    5/32

    GDL-USER> (/ (* 5 -1) (* -4 8))

    5/32

    GDL-USER> (/ -5 -32)

    5/32

    So back to our code, my-box-4

    (define-object my-box-4 (box):input-slots(length(width 4)(height 4))):computed-slots((density 7800)(mass (* (div (the volume) 1000000000) (the density)))))

    In the :computed-slots, density has been assigned the value of 7800.

    Because the box dimensions are in mm, and the density is in kg/m3, we first divide the volume by 1000000000 to convert into cubic metres. We then multiply this result by the value of density to get the mass in kg. The result will always be a floating point number, since div indeed always returns a floating point number.

    Resources

    numbers.lisp