Go to the previous, next section.

Side Trip: Compute a Remainder

In Lisp, the function for computing a remainder is  % . The function returns the remainder of its first argument divided by its second argument. As it happens,  % is a function in Emacs Lisp that you cannot discover using  apropos : you find nothing if you type M-x apropos RET remainder RET. The only way to learn of the existence of  % is to read about it in a book such as this or in the Emacs Lisp sources. The  % function is used in the code for  rotate-yank-pointer , which is described in an appendix. (See section The Body of  rotate-yank-pointer }.)

You can try the  % function by evaluating the following two expressions:

(% 7 5)

(% 10 5)

The first expression returns 2 and the second expression returns 0.

To test whether the returned value is zero or some other number, we can use the  zerop function. This function returns  t if its argument, which must be a number, is zero.

(zerop (% 7 5))
     @result{} nil

(zerop (% 10 5))
     @result{} t

Thus, the following expression will return  t if the height of the graph is evenly divisible by five:

(zerop (% height 5))

(The value of  height , of course, can be found from  (apply 'max numbers-list) .)

On the other hand, if the value of  height is not a multiple of five, we want to reset the value to the next higher multiple of five. This is straightforward arithmetic using functions with which we are already familiar. First, we divide the value of  height by five to determine how many times five goes into the number. Thus, five goes into twelve twice. If we add one to this quotient and multiply by five, we will obtain the value of the next multiple of five that is larger than the height. Five goes into twelve twice. Add one to two, and multiply by five; the result is fifteen, with is the next multiple of five that is higher than twelve. The Lisp expression for this is:

(* (1+ (/ height 5)) 5)

For example, if you evaluate the following, the result is 15:

(* (1+ (/ 12 5)) 5)

All through this discussion, we have been using `five' as the value for spacing labels on the Y axis; but we may want to use some other value. For generality, we should replace `five' with a variable to which we can assign a value. The best name I can think of for this variable is  Y-axis-label-spacing . Using this term, and an  if expression, we produce the following:

(if (zerop (% height Y-axis-label-spacing))
    height
  ;; else
  (* (1+ (/ height Y-axis-label-spacing))
     Y-axis-label-spacing))

This expression returns the value of  height itself if the height is an even multiple of the value of the  Y-axis-label-spacing or else it computes and returns a value of  height that is equal to the next higher multiple of the value of the  Y-axis-label-spacing .

We can now include this expression in the  let expression of the  print-graph function (after first setting the value of  Y-axis-label-spacing ):

(defvar Y-axis-label-spacing 5
  "Number of lines from one Y axis label to next.")

@dots{}
(let* ((height (apply 'max numbers-list))
       (height-of-top-line
        (if (zerop (% height Y-axis-label-spacing))
            height
          ;; else
          (* (1+ (/ height Y-axis-label-spacing))
             Y-axis-label-spacing)))
       (symbol-width (length graph-blank))))
@dots{}

(Note use of the  let* function: the initial value of height is computed once by the  (apply 'max numbers-list) expression and then the resulting value of  height is used to compute its final value. See section The  let* expression.)

Go to the previous, next section.