> The real hit would come with bignums, no? But as far as the routine
> use of MOD goes we're probably talking about fixnums > 99% of the time.
Good point,
I tried some more timings on various configurations:
; Currently submitted (soon to be dethroned) patch
(defn mod1
"Modulus of num and div. Truncates toward negative infinity."
[num div]
(let [m (rem num div)]
(if (or (zero? m) (pos? (* num div)))
m
(+ m div))))
; verbatim from SBCL
(defn mod2
"Modulus of num and div. Truncates toward negative infinity."
[num div]
(let [rem (rem num div)]
(if (and (not (zero? rem))
(if (neg? div)
(pos? num)
(neg? num)))
(+ rem div)
rem)))
; comparing the signs, inverse logic to SBCL for slightly less
function calls and common case first
(defn mod3
"Modulus of num and div. Truncates toward negative infinity."
[num div]
(let [r (rem num div)]
(if (or (= (pos? num) (pos? div)) (zero? r))
r
(+ r div))))
; use SBCL style if trick instead of comparing signs
(defn mod4
"Modulus of num and div. Truncates toward negative infinity."
[num div]
(let [r (rem num div)]
(if (or (if (pos? num)
(pos? div)
(neg? div))
(zero? r))
r
(+ r div))))
user=> (time (dorun (map #(mod4 % 3) (range -9 9000000)) ))
"Elapsed time: 13119.193251 msecs"
user=> (time (dorun (map #(mod4 % 3) (range -9000000 9)) ))
"Elapsed time: 14771.158608 msecs"
user=> (time (dotimes [i 10000] (mod4 (bigint 1e1000M) (inc i))))
"Elapsed time: 3809.305116 msecs"
user=> (time (dorun (map #(mod3 % 3) (range -9 9000000)) ))
"Elapsed time: 13109.544278 msecs"
user=> (time (dorun (map #(mod3 % 3) (range -9000000 9)) ))
"Elapsed time: 15408.188226 msecs"
user=> (time (dotimes [i 10000] (mod3 (bigint 1e1000M) (inc i))))
"Elapsed time: 3801.648725 msecs"
user=> (time (dorun (map #(mod2 % 3) (range -9 9000000)) ))
"Elapsed time: 14642.528284 msecs"
user=> (time (dorun (map #(mod2 % 3) (range -9000000 9)) ))
"Elapsed time: 16286.011241 msecs"
user=> (time (dotimes [i 10000] (mod2 (bigint 1e1000M) (inc i))))
"Elapsed time: 3826.870597 msecs"
user=> (time (dorun (map #(mod1 % 3) (range -9 9000000)) ))
"Elapsed time: 14151.776571 msecs"
user=> (time (dorun (map #(mod1 % 3) (range -9000000 9)) ))
"Elapsed time: 14975.93798 msecs"
user=> (time (dotimes [i 10000] (mod1 (bigint 1e1000M) (inc i))))
"Elapsed time: 3840.114813 msecs"
Obviously these numbers are subject to variance etc... but the upshot
seemed to be that there wasn't a substantial difference between any of
the forms (I was especially surprised by bigint not playing a factor,
perhaps my tests were flawed. In terms of style I think checking that
the signs are equal is in some ways more obvious than multiplying,
however = pos? pos? is arguably confusing also. The SBCL if nesting is
neat too, so I really don't know which is best.
Regards,
Tim.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---