Lispにおいて、剰余を計算する関数は % です。
この関数は、第1引数を第2引数で割ったときの剰余を返します。 たまたま、% は Emacs
Lisp の関数であり、apropos を使って見つけることはできません。M-x apropos RET remainder RET と入力しても、何も見つからないからです。 % の存在を知る唯一の方法は、このような書籍や Emacs Lisp のソースコードでそれについて読むことです。
以下の2つの式を評価することで、%関数を試すことができます。
(% 7 5) (% 10 5)
1つ目の式は2を返し、2つ目の式は0を返します。
戻り値が0かそれ以外の数値かを判定するには、zerop関数を使用できます。この関数は、数値である必要がある引数が0の場合、tを返します。
(zerop (% 7 5))
⇒ nil
(zerop (% 10 5))
⇒ t
したがって、グラフの高さが5で割り切れる場合、次の式はtを返します。
(zerop (% height 5))
(heightの値は、もちろん(apply 'max
numbers-list)から求めることができます。)
一方で、height
の値が5の倍数でない場合は、値を次の大きい5の倍数にリセットしたいと考えます。これは、すでに馴染みのある関数を用いた単純な算術処理です。まず、height
の値を5で割り、その数に5が何回入るかを算出します。したがって、12を5で割ると2になります。この商に1を足して5を掛ければ、高さよりも大きい次の5の倍数が得られます。12を5で割ると2になります。2に1を足して5を掛けると、結果は15となり、これが12より大きい次の5の倍数となります。これを表すLispの式は以下の通りです:
(* (1+ (/ height 5)) 5)
例えば、以下を評価すると、結果は15になります:
(* (1+ (/ 12 5)) 5)
これまでの議論では、Y軸の間隔ラベルの値として5を使用してきましたが、別の値を使いたい場合もあるでしょう。汎用性を持たせるため、5を値を代入できる変数に置き換えるべきです。この変数に付ける名前として考えられる最善のものは、Y-axis-label-spacingです。
この用語とif式を用いて、以下を生成します。
(if (zerop (% height Y-axis-label-spacing))
height
;; else
(* (1+ (/ height Y-axis-label-spacing))
Y-axis-label-spacing))
この式は、高さがY-axis-label-spacingの値の偶数倍である場合はheightの値そのものを返し、そうでない場合はY-axis-label-spacingの値の次の上位倍数に等しいheightの値を計算して返します。
これで、この式を(まずY-axis-label-spacingの値を設定した後で)print-graph関数のlet式に組み込むことができます:
(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))))
...
(let* 関数の使用に注意してください。height の初期値は (apply 'max numbers-list) 式によって一度計算され、その後、height の計算結果を用いて最終的な値が算出されます。let* の詳細については、let* 式を参照してください。)