数値の差を表示する elisp 書いてみた
ある数値(まぁ為替レートなんだけど)の差分を計算してよしなに表示できたらいいなーという思いが頭をもたげてきたので elisp を書いてみた。
113.750 と 113.855 の差分は普通に引き算すると 0.105 なんだけど諸般の事情により 10.5 と表示したい。同様に 1.09321 と 1.09301 の差分は 0.00020 ではなく 2.0 と表示したい。小数点以下の桁数が 3 桁か 5 桁かによって何倍するかが異なる、ということ。
最初に書いたのはこんな感じ。
;; 小数点以下が 5 桁かどうか判定する (defun fivedigits (x) (if (< (* x 1000) 10000) t nil)) (defun my-round (value) ;; 指定した桁数以下を捨てる (defun my-slice (value digit) (setq str_value (substring (number-to-string value) 0 digit) ) (string-to-number str_value)) (cond ((> -99.9 value) (my-slice value 6)) ((> -9.9 value) (my-slice value 5)) ((> 0 value) (my-slice value 4)) ((< 99.9 value) (my-slice value 5)) ((< 9.9 value) (my-slice value 4)) ((< 0 value) (my-slice value 3)) ) ) (defun long (x y) (setq value (if (fivedigits x) (* 10000 (- y x)) (* 100 (- y x)))) (my-round value)) (defun short (x y) (setq value (if (fivedigits x) (* 10000 (- x y)) (* 100 (- x y)))) (my-round value))
この長さの lisp を書いたのは初めて。cond とか初めて使った。久しぶりに基礎文法最速マスターシリーズのエントリを読んだな。
で使ってみると、
(long 123.342 124.642) ; => 129.9 (long 123.343 123.393) ; => 4.9 (short 1.11023 1.11011) ; => 1.2 (short 1.11023 1.11411) ; => -38.7
あれ、誤差が。
そうか、最初に整数にしてから引き算していけばいいのだと気づく。
;; 小数点以下が 5 桁かどうか判定する(上と同じ) (defun fivedigits (x) (if (< (* x 1000) 10000) t nil)) (defun long1 (x y) (if (fivedigits x) (/ (- (* 100000 y) (* 100000 x)) 10) (/ (- (* 1000 y) (* 1000 x)) 10))) (defun short1 (x y) (if (fivedigits x) (/ (- (* 100000 x) (* 100000 y)) 10) (/ (- (* 1000 x) (* 1000 y)) 10)))
cond とか使わなくても事足りた。
(long1 123.342 124.642) ; => 130.0 (long1 123.343 123.393) ; => 5.0 (short1 1.11023 1.11011) ; => 1.2 (short1 1.11023 1.11411) ; => -38.8
見たところ合ってるっぽいので、たぶんこれでいいのではないかと思う。
最初の誤差が出るバージョンを書くのにすごく時間がかかったし、直した方はただの四則演算だけですぐに書けたし、何だか複雑な気持ち。