Node:Compute a Remainder, Next:Y Axis Element, Previous:Height of label, Up:print-Y-axis
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 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)) => nil (zerop (% 10 5)) => 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, which 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.") ... (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)))) ...
(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 The let*
expression, for
more about let*
.)