Any wisdom in the math speed of different clojure libraries?

30 views
Skip to first unread message

bOR_

unread,
May 3, 2011, 3:38:12 AM5/3/11
to clo...@googlegroups.com
user> (time (dotimes [i 100000] (contribmath-ceil (rand))))                                                                                                                                
"Elapsed time: 4500.530303 msecs"                                                                                                                                                   
nil                                                                                                                                                                                 
user> (time (dotimes [i 100000] (contribgenericmath-ceil (rand))))                                                                                                                             
"Elapsed time: 44.707193 msecs"                                                                                                                                                     
nil                                                                                                                                                                                 
user> (time (dotimes [i 100000] (incanterprocessing-ceil (rand))))                                                                                                                                     
"Elapsed time: 38.322599 msecs"                                                                                                                                                     
nil                                                                                                                                                                                 
user> (time (dotimes [i 100000] (inc (int (rand)))))                                                                                                                                
"Elapsed time: 28.939557 msecs"     

Observing the huge differences in speed of certain math functions in different clojure libraries, I was wondering if anyone knows which clojure math library is fastest in general? Is there any wisdom in this, or is it just up to users to check for each function where to get an efficient implementation.

Alan

unread,
May 3, 2011, 3:47:59 AM5/3/11
to Clojure
On May 3, 12:38 am, bOR_ <boris.sch...@gmail.com> wrote:
> user> (time (dotimes [i 100000] (contribmath-ceil (rand))))                
>
> "Elapsed time: 4500.530303 msecs"                                          
>
> nil                                                                        
>
> user> (time (dotimes [i 100000] (contribgenericmath-ceil (rand))))          
>
> "Elapsed time: 44.707193 msecs"                                            
>
> nil                                                                        
>
> user> (time (dotimes [i 100000] (incanterprocessing-ceil (rand))))          
>
> "Elapsed time: 38.322599 msecs"                                            
>
> nil                                                                        
>
> user> (time (dotimes [i 100000] (inc (int (rand)))))                


That's a terrible ceil method: (inc (int 0)) is 1. The reason it's
fast is that (int x) is a java primitive. It acts like the *floor*
function, making it not useful to you.

David Nolen

unread,
May 3, 2011, 8:03:11 AM5/3/11
to clo...@googlegroups.com
Why not?

user> (time (dotimes [_ 1000000000] (Math/ceil 0.1)))
"Elapsed time: 626.867 msecs"

David

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

bOR_

unread,
May 3, 2011, 9:50:11 AM5/3/11
to clo...@googlegroups.com
Because I did not remember Math/ceil :-).

Point is, is there any consensus on what math library to use? Is (Math/... in general the fastest?

David Nolen

unread,
May 3, 2011, 10:04:13 AM5/3/11
to clo...@googlegroups.com
On Tue, May 3, 2011 at 9:50 AM, bOR_ <boris....@gmail.com> wrote:
Because I did not remember Math/ceil :-).

Point is, is there any consensus on what math library to use? Is (Math/... in general the fastest?

For basic math, I'm not sure what could be faster than Java primitive operators and methods. For more sophisticated things you'll probably have to look at the various Java libs which I'm not all that familiar with.

David

Ken Wesson

unread,
May 3, 2011, 2:51:02 PM5/3/11
to clo...@googlegroups.com
On Tue, May 3, 2011 at 8:03 AM, David Nolen <dnolen...@gmail.com> wrote:
> Why not?
> user> (time (dotimes [_ 1000000000] (Math/ceil 0.1)))
> "Elapsed time: 626.867 msecs"
> David

It's optimizing your loop away, or else you're using ridiculously
powerful hardware.

user=> (time (dotimes [_ 1000000] (Math/ceil (rand))))
"Elapsed time: 142.86748 msecs"
nil

Making it a local of type "double" seems slightly faster:

user=> (time (dotimes [_ 1000000] (let [x (double (rand))] (Math/ceil x))))
"Elapsed time: 136.96752 msecs"
nil

But to really time a "ceil" function we should have premade random
numbers and avoid including their generation in the time. We'll also
get rid of some boxing and function call overheads:

user=> (let [nums (double-array (repeatedly 1000000 rand))]
(time
(dotimes [i 1000000] (Math/ceil (aget nums i)))))
"Elapsed time: 47.99892 msecs"
nil

Now the only things in the timing loop are: counting to 1 million,
aget from a primitive array, and Math/ceil itself. That's about as
good as it's gonna get.

Substitute calls to other ceil implementations as appropriate.

Oh, and by the way, (int x) is not quite floor either:

user=> (int -2.1)
-2

It truncates towards 0 rather than -infinity.

#(quot % 1) does the same thing (and is slower by nearly a factor of 10).

David Nolen

unread,
May 3, 2011, 3:20:25 PM5/3/11
to clo...@googlegroups.com
On Tue, May 3, 2011 at 2:51 PM, Ken Wesson <kwes...@gmail.com> wrote:
It's optimizing your loop away, or else you're using ridiculously
powerful hardware.

user=> (time (dotimes [_ 1000000] (Math/ceil (rand))))
"Elapsed time: 142.86748 msecs"
nil

Maybe, maybe not:

(do
  (set! *unchecked-math* true)
  (let [nums (double-array (repeatedly 1e3 rand))]
    (dotimes [_ 10]
      (time
       (dotimes [i 1e8] (Math/ceil (double (aget nums (rem i 1e3)))))))))
"Elapsed time: 1405.835 msecs"

(do
  (set! *unchecked-math* true)
  (let [nums (double-array (repeatedly 1e3 rand))]
    (dotimes [_ 10]
      (time
       (dotimes [i 1e8] (double (aget nums (rem i 1e3))))))))
"Elapsed time: 1409.305 msecs"

Given that the i7 is far into the gigaflops territory, I don't find this particularly surprising. But I'm not a hardware architecture expert by any means nor an expert of what kind of magic the JVM can do.

David

Jeffrey Schwab

unread,
May 3, 2011, 3:29:57 PM5/3/11
to clo...@googlegroups.com


On Tuesday, May 3, 2011 3:20:25 PM UTC-4, David Nolen wrote:
On Tue, May 3, 2011 at 2:51 PM, Ken Wesson <kwes...@gmail.com> wrote:
It's optimizing your loop away, or else you're using ridiculously
powerful hardware.

user=> (time (dotimes [_ 1000000] (Math/ceil (rand))))
"Elapsed time: 142.86748 msecs"
nil

Maybe, maybe not: 

Either way, it's got a weird profile (increasing, but not monotonically):

user=> (doseq [n (map #(Math/pow 10 %) (range 10))] (time (dotimes [_ n] (Math/ceil 0.1))))
"Elapsed time: 0.238077 msecs"
"Elapsed time: 0.007346 msecs"
"Elapsed time: 0.030386 msecs"
"Elapsed time: 0.255107 msecs"
"Elapsed time: 10.399609 msecs"
"Elapsed time: 5.677462 msecs"
"Elapsed time: 1.423789 msecs"
"Elapsed time: 9.779539 msecs"
"Elapsed time: 65.505686 msecs"
"Elapsed time: 651.333768 msecs"
nil

Stuart Sierra

unread,
May 3, 2011, 6:17:27 PM5/3/11
to clo...@googlegroups.com
Anything implemented with multimethods (contrib.generic) will be slow compared to primitives and Java methods invoked on primitives.  Also try out the better primitive math ops in the 1.3.0-alphas.

-Stuart
clojure.com

Reply all
Reply to author
Forward
0 new messages