なんだこれは

はてなダイアリーから移転しました。

マイナーな? rem を推してみる。

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

NIL

 (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

NIL

結果は、こうなった。

implement mod rem Winner
ClozureCL 4.511372 3.887415 rem
SBCL 0.051 0.052 mod

sbclは僅差だが、ClozureCLはmod と remの間の差が大きい。なぜなのかは知らない。