在Lisp中,用于计算余数的函数是%
。该函数返回其第一个参数除以第二个参数的余数。正巧,%
在Emacs Lisp中是一个无法通过apropos
发现的函数:如果输入M-x apropos RET remainder RET,你将找不到任何结果。了解%
存在的唯一方式是通过阅读本书或Emacs Lisp源代码。
你可以通过评估以下两个表达式来尝试%
函数:
(% 7 5) (% 10 5)
第一个表达式返回2,第二个表达式返回0。
为了测试返回值是否为零或其他数字,我们可以使用zerop
函数。该函数在其参数(必须是数字)为零时返回t
。
(zerop (% 7 5)) ⇒ nil (zerop (% 10 5)) ⇒ t
因此,以下表达式将在图的高度能够被五整除时返回t
:
(zerop (% height 5))
(当然,height
的值可以通过(apply 'max numbers-list)
获得。)
另一方面,如果height
的值不是五的倍数,我们希望将其重置为下一个更高的五的倍数。这是使用我们已经熟悉的函数进行的简单算术。首先,我们将height
的值除以五,以确定五可以整除该数多少次。因此,五可以整除十二两次。如果我们将这个商加一并乘以五,就会得到大于该高度的下一个五的倍数的值。五可以整除十二两次。将二加一,并乘以五;结果是十五,这是大于十二的下一个五的倍数。这个Lisp表达式是:
(* (1+ (/ height 5)) 5)
例如,如果你评估以下表达式,结果将是15:
(* (1+ (/ 12 5)) 5)
在整个讨论中,我们一直使用5作为Y轴标签间隔的值;但我们可能想要使用其他值。为了通用性,我们应该用一个变量替换5,以便我们可以为其赋值。我能想到的这个变量的最佳名称是Y-axis-label-spacing
。
使用这个术语和一个if
表达式,我们可以得到以下结果:
(if (zerop (% height Y-axis-label-spacing))
height
;; 否则
(* (1+ (/ height Y-axis-label-spacing))
Y-axis-label-spacing))
如果高度是Y-axis-label-spacing
的偶数倍,此表达式将返回height
本身,否则它计算并返回一个等于Y-axis-label-spacing
的下一个更高倍数的height
值。
现在,我们可以将此表达式包含在print-graph
函数的let
表达式中(首先设置Y-axis-label-spacing
的值):
(defvar Y-axis-label-spacing 5 "从一个Y轴标签到下一个的行数。")
… (let* ((height (apply 'max numbers-list)) (height-of-top-line (if (zerop (% height Y-axis-label-spacing)) height
;; 否则
(* (1+ (/ height Y-axis-label-spacing))
Y-axis-label-spacing)))
(symbol-width (length graph-blank))))
…
(注意使用let*
函数:通过(apply 'max numbers-list)
表达式计算一次height
的初始值,然后使用height
的结果值计算其最终值。有关let*
的更多信息,请参阅See The let*
expression.)