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

Math


  1. Number Types
  2. Integer Limits
  3. Rounding and Truncation
  4. Remainder and Modulus
  5. Power and Roots

Number Types


Nyquist/XLISP only knows two types of numers:

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