Nyquist / XLISP 2.0 - Contents | Tutorials | Examples | Reference

# Math

1. Number Types
2. Integer Limits
3. Rounding and Truncation

- cl:round - round towards the next integer
- cl:truncate - truncate towards zero
- cl:ceiling - truncate towards positive infinity
- cl:floor - truncate towards negative infinity

5. Remainder and Modulus

- cl:rem
- cl:mod

6. Power and Roots

- cl:exp - compute 'e' to the power of 'x'
- cl:expt - compute 'x' to the power of 'y'
- cl:log
- cl:sqrt

## Number Types

Nyquist/XLISP only knows two types of numers:

- fixnum - integer numbers
- flonum - floating-point numbers

In Nyquist/XLISP, there are no ratios or complex numbers. Even if the math functions on this page are modelled after Common Lisp, no attempt is made to emulate these numbers.

## Integer Limits

    (setq *most-positive-fixnum*  2147483647)
    (setq *most-negative-fixnum* -2147483648)

Note: these are the limits for 32-bit machines.

    (defun fixnum-bits ()
      (dolist (bits '(15 31 63) nil)
        (let ((fixnum (round (expt 2.0 bits))))
          (and (plusp (1- fixnum))
               (minusp fixnum)
               (return (1+ bits))))))

    (defun fixnum-limits ()
      (if (dolist (bits '(15 31 63) nil)
            (let* ((negative (round (expt 2.0 bits)))
                   (positive (1- negative)))
               (when (and (plusp  positive)
                          (minusp negative))
                 (setq most-positive-fixnum positive
                       most-negative-fixnum negative)
                 (return t))))
          most-positive-fixnum
          (error "fixnum limit not found")))

Back to top

## print-float

The 'print-float' function prints floating-point numbers ending in '.0' as floating-point numbers and not as integers:

    (defun print-float (item)
      (if (not (floatp item))
          item
          (let ((string (format nil "~a" item)))
            (if (not (string-search "." string))
                (strcat string ".0")
                string))))

Back to top

## divide-float

An easy way to force a sequence of integers to be divided as floating point numbers is to insert the number 1.0 after the first argument in the list of arguments to the divider function or to explicitely convert the first argument into a floating point number by using the XLISP float function:

    (defun divide-float (&rest args)
      (if (null args)
          (error "too few arguments")
          (apply #'/ (cons (float (first args)) (rest args)))))

See apply, cons, defun, error, first, float, if, null, rest, &rest.

Examples:

    (divide-float 1)    => 1.0
    (divide-float 1 2)  => 0.5

Back to top

## Rounding and Truncation

The cl:round, cl:truncate, cl:ceiling and cl:floor functions divide a number by a divisor, returning a quotient and a remainder:

(cl:round | number [divisor]) | ⇒ | quotient, remainder
(cl:truncate | number [divisor]) | ⇒ | quotient, remainder
(cl:ceiling | number [divisor]) | ⇒ | quotient, remainder
(cl:floor | number [divisor]) | ⇒ | quotient, remainder

quotient * divisor + remainder = number

The 'quotient' always represents a mathematical integer. The 'remainder' is an integer if both 'number' and 'divisor' arguments are integers, and a floating-point number if either the 'number' or the 'divisor' or both are floating-point numbers.

With Nyquist/XLISP, the 'quotient' is always directly returned by the function, while a list:

    (quotient remainder)

is stored in the Nyquist/XLISP *rslt* variable and the cl:*multiple-values* is set to T to signal that Multiple Values are returned.

Examples:

    (cl:round     3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:truncate  3.5)  =>  3  ; *rslt* = ( 3  0.5)
    (cl:ceiling   3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:floor     3.5)  =>  3  ; *rslt* = ( 3  0.5)

    (cl:round    -3.5)  => -4  ; *rslt* = (-4  0.5)
    (cl:truncate -3.5)  => -3  ; *rslt* = (-3 -0.5)
    (cl:ceiling  -3.5)  => -3  ; *rslt* = (-3 -0.5)
    (cl:floor    -3.5)  => -4  ; *rslt* = (-4  0.5)

Force integer division:

    (cl:truncate 3.0 2.0)              => 1
    (/ (truncate 3.0) (truncate 2.0))  => 1
    (/ 3 4)                            => 1

Implementation Notes

    (defun name (number &optional (divisor (if (integerp number) 1 1.0)))
      ... )

The integerp test in the parameter list signals an error if the 'number' argument is not a number, also the / [division] function signals errors if the 'divisor' argument is zero or not a number, so we do not explicitely need to test the arguments.

The cl:ceiling and cl:floor functions test if 'number' is an integer multiple of 'divisor' by comparing the results of an integer division and a floating-point division:

    (let ((i-quotient (/ (truncate number) (truncate divisor)))
          (f-quotient (/ (float number) divisor)))
      (if (= i-quotient f-quotient)
            ...

I'm not sure if this really catches all cases [e.g. regarding floating point precision], but have found no problems so far.

Back to top

## cl:round

The 'cl:round' function truncates towards the next integer:

(cl:round number [divisor])
  number - an integer or floating-point number
  divisor - an integer or floating-point number, except zero

  returns | - | the result of runding the result of number divided by divisor
  | - | the remainder of the round operation

    (defun cl:round (number &optional (divisor
                                      (if (integerp number) 1 1.0)
                                      divisor-p))
      (let* ((x (/ (float number) divisor))
             (quotient (cond ((and (not divisor-p) (integerp number)) number)
                             ((= number divisor) 1)
                             ((plusp x) (truncate (+ x 0.5)))
                             ((= (- x 0.5) (truncate (- x 0.5)))
                              (if (minusp x)
                                  (1- (truncate x))
                                  (truncate x)))
                             (t (truncate (- x 0.5))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))

The 'cl:round' function computes a quotient that has been rounded to the nearest mathematical integer. If the mathematical quotient is exactly halfway between two integers, [that is, it has the form 'integer+1/2'], then the quotient has been rounded to the even [divisible by two] integer. See Rounding and Truncation above for more details.

    (round  3.5)     =>  4
    (round -3.5)     => -3

    (cl:round  3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:round -3.5)  => -4  ; *rslt* = (-4  0.5)

Back to top

## cl:truncate

The 'cl:truncate' function truncates towards zero:

(cl:truncate number [divisor])
  number - an integer or floating-point number
  divisor - an integer or floating-point number, except zero

  returns | - | the result of truncating the result of number divided by divisor
  | - | the remainder of the truncate operation

    (defun cl:truncate (number &optional (divisor (if (integerp number) 1 1.0)))
      (let ((quotient (truncate (/ (float number) divisor))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))

The 'cl:truncate' function computes a quotient that has been truncated towards zero. That is, the quotient represents the mathematical integer of the same sign as the mathematical quotient, and that has the greatest integral magnitude not greater than that of the mathematical quotient. See Rounding and Truncation above for more details.

Back to top

## cl:ceiling

The 'cl:ceiling' function truncates towards positive infinity:

(cl:ceiling number [divisor])
  number - an integer or floating-point number
  divisor - an integer or floating-point number, except zero

  returns | - | the result of truncating the result of number divided by divisor
  | - | the remainder of the truncate operation

    (defun cl:ceiling (number &optional (divisor
                                        (if (integerp number) 1 1.0)
                                        divisor-p))
      (let ((quotient
              (cond ((and (not divisor-p) (integerp number)) number)
                    ((= number divisor) 1)
                    (t (let ((i-quotient (/ (truncate number) (truncate divisor)))
                             (f-quotient (/ (float number) divisor)))
                         (if (or (= i-quotient f-quotient)  ; integer result
                                 (not (plusp f-quotient)))
                              (truncate f-quotient)
                              (1+ (truncate f-quotient))))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))

The 'cl:ceiling' function computes a quotient that has been truncated toward positive infinity. That is, the quotient represents the smallest mathematical integer that is not smaller than the mathematical result. See Rounding and Truncation above for more details.

Back to top

## cl:floor

The 'cl:floor' function truncates towards negative infinity:

(cl:floor number [divisor])
  number - an integer or floating-point number
  divisor - an integer or floating-point number, except zero

  returns | - | the result of truncating the result of number divided by divisor
  | - | the remainder of the truncate operation

    (defun cl:floor (number &optional (divisor
                                      (if (integerp number) 1 1.0)
                                      divisor-p))
      (let ((quotient
              (cond ((and (not divisor-p) (integerp number)) number)
                    ((= number divisor) 1)
                    (t (let ((i-quotient (/ (truncate number) (truncate divisor)))
                             (f-quotient (/ (float number) divisor)))
                         (if (or (= i-quotient f-quotient)  ; integer result
                                 (not (minusp f-quotient)))
                              (truncate f-quotient)
                              (1- (truncate f-quotient))))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))

The 'cl:floor' function computes a quotient that has been truncated toward negative infinity. That is, the quotient represents the largest mathematical integer that is not larger than the mathematical quotient. See Rounding and Truncation above for more details.

Back to top

## Remainder and Modulus

The cl:mod and cl:rem function are generalizations of the modulus and remainder functions. The cl:mod function performs the cl:floor operation on its arguments and returns the remainder of the cl:floor operation. The cl:rem function performs the cl:truncate operation on its arguments and returns the remainder of the cl:truncate operation. The cl:mod and cl:rem functions are the modulus and remainder functions when the 'number' and 'divisor' arguments both are integers.

Back to top

## cl:rem

(cl:rem number divisor)
  number - an integer or floating-point number
  divisor - an integer or floating-point number
  returns - the remainder of a cl:truncate operation

    (defun cl:rem (number divisor)
      (if (= (abs number) (abs divisor))
          (if (and (integerp number) (integerp divisor)) 0 0.0)
          (let ((quotient (truncate (/ (float number) divisor))))
            (- number (* quotient divisor)))))

The 'cl:rem' function performs the cl:truncate operation on its arguments and returns the remainder of the cl:truncate operation. The result is either zero or an integer or floating-point number with the same sign as the 'number' argument. If both arguments are integer numbers, the 'cl:rem' function is equal to the mathematical remainder function.

Back to top

## cl:mod

(cl:mod number divisor)
  number - an integer or floating-point number
  divisor - an integer or floating-point number
  returns - the remainder of a cl:floor operation

    (defun cl:mod (number divisor)
      (if (= (abs number) (abs divisor))
          (if (and (integerp number) (integerp divisor)) 0 0.0)
          (let* ((i-quotient (/ (truncate number) (truncate divisor)))
                 (f-quotient (/ (float number) divisor))
                 (quotient (if (or (= i-quotient f-quotient)  ; integer result
                                   (not (minusp f-quotient)))
                               (truncate f-quotient)
                               (1- (truncate f-quotient)))))
            (- number (* quotient divisor)))))

The 'cl:mod' function performs the cl:floor operation on its arguments and returns the remainder of the cl:floor operation. The result is either zero or an integer or floating-point number with the same sign as the 'divisor' argument. If both arguments are integer numbers, the 'cl:rem' function is equal to the mathematical modulus function.

Back to top

## cl:exp

The 'cl:exp' function does the same as the Nyquist/XLISP exp function, but it also accepts integer numbers as argument:

(cl:exp power)
  power - an integer or floating-point number
  returns - the result of 'e' [2.7128] to the power of power

    (defun cl:exp (x)
      (exp (float x)))

The 'cl:exp' function computes 'e' [2.7128] raised to the specified 'power'. The result is always a floating-point number.

Back to top

## cl:expt

The 'cl:expt' function computes the result of 'x' to the power of 'y':

(cl:expt base power)
  base - the base
  power - the exponent
  returns - the result of base to the power of power

    (defun cl:expt (x y)
      (let ((power (expt (float x) y)))
        (if (and (integerp x) (integerp y))
            (round power)
            power)))

See and, defun, expt, float, if , integerp, let, power, round.

The 'cl:expt' function accepts integer and floating point numbers as arguments. If both arguments are integer numbers, the result will be an integer number, if one or both arguments are floating-point numbers, the result will be a floating-point number. In contrast to the Nyquist/XLISP expt function, the 'cl:expt' function specifies exactly two arguments.

Back to top

## cl:log

The 'cl:log' function does the same as the Nyquist/XLISP log function, but also accepts integer numbers and has an optional 'base' argument:

(cl:log number [base])
  number - an integer or floating-point number
  base - an integer or floating-point number
  returns - the the logarithm of number in base base

    (defun cl:log (number &optional base)
      (if base
          (if (zerop base)
              0.0
              (/ (log (float number)) (log (float base))))
          (log (float number))))

The 'cl:log' function returns the logarithm of 'number' in base 'base'. If 'base' is not supplied its value is 'e', the base of the natural logarithms. If the 'base' argument is zero, then 'cl:log' returns zero. The result is always a floating-point number.

Back to top

## cl:sqrt

The 'cl:sqrt' function does the same as the Nyquist/XLISP sqrt function, but it also accepts integer numbers as argument:

(cl:sqrt number)
  number - an integer or floating-point number
  returns - the square root of number

    (defun cl:sqrt (x)
      (sqrt (float x)))

The result is always a floating-point number.

Back to top

Nyquist / XLISP 2.0 - Contents | Tutorials | Examples | Reference