> 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 clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to