Common Lispの剰余計算は二種類ある。
mod と remだ。common lispで剰余というと、多くは mod があげられる。マイナーな remがかわいそうです。
計算結果を比べてみる。
HyperSpec の計算例を引用すると、
引数の符号が異なる場合に返り値が異なるが、両方符号が同じ場合は同じになる。
(rem -1 5) ;=> -1 (mod -1 5) ;=> 4 (mod 13 4) ;=> 1 (rem 13 4) ;=> 1 (mod -13 4) ;=> 3 (rem -13 4) ;=> -1 (mod 13 -4) ;=> -3 (rem 13 -4) ;=> 1 (mod -13 -4) ;=> -1 (rem -13 -4) ;=> -1 (mod 13.4 1) ;=> 0.4 (rem 13.4 1) ;=> 0.4 (mod -13.4 1) ;=> 0.6 (rem -13.4 1) ;=> -0.4
計算速度を比べてみる
それで、Clozure CL 1.10/Mac で正整数での剰余計算の速度をはかってみると、マイナーなremの方が早い。おおー。
(time (dotimes (x 100000000) (mod x 18)))
(DOTIMES (X 100000000) (MOD X 18))
took 4,511,372 microseconds (4.511372 seconds) to run.
During that period, and with 2 available CPU cores,
4,501,012 microseconds (4.501012 seconds) were spent in user mode
4,094 microseconds (0.004094 seconds) were spent in system mode
NIL
(time (dotimes (x 100000000) (rem x 18)))
(DOTIMES (X 100000000) (REM X 18))
took 3,887,415 microseconds (3.887415 seconds) to run.
During that period, and with 2 available CPU cores,
3,871,720 microseconds (3.871720 seconds) were spent in user mode
4,434 microseconds (0.004434 seconds) were spent in system mode
NIL
次に SBCL 1.2.7 /Mac で同様に計算してみる。sbcl早い。
(time (dotimes (x 100000000) (mod x 18)))
Evaluation took:
0.051 seconds of real time
0.050307 seconds of total run time (0.050264 user, 0.000043 system)
98.04% CPU
100,143,397 processor cycles
0 bytes consed
(time (dotimes (x 100000000) (rem x 18)))
Evaluation took:
0.052 seconds of real time
0.050583 seconds of total run time (0.050326 user, 0.000257 system)
98.08% CPU
103,276,343 processor cycles
0 bytes consed
結果は、こうなった。
implement | mod | rem | Winner |
ClozureCL | 4.511372 | 3.887415 | rem |
SBCL | 0.051 | 0.052 | mod |
sbclは僅差だが、ClozureCLはmod と remの間の差が大きい。なぜなのかは知らない。