[racket] Style and Performance question

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Tue May 10 15:40:14 EDT 2011

At Tue, 10 May 2011 10:05:35 -0400, Matthias Felleisen wrote:
> 2. The addition in lieu of the multiplication is consistently the fastest 
> version of the three I mentioned last night: 
> 
>   (: the-sqrt : Real -> Real)
>   (define (the-sqrt y)
>     (let loop [(x (/ y 2.0))]
>       (let [(error (- y (* x x)))]
>         (if (< (abs error) epsilon) 
>             x
>             (loop (+ x (/ error (+ x x))))))))
> 
> Our compiler should probably implement reduction of strength optimizations 
> based on this one experiment alone. The savings here are over 10%. 

In the variant where you divide by 2, are you using `2' or `2.0'?

I'd expect `(/ error 2.0 x)' to be faster than `(/ error (+ x x))' in
the case that `x' and `error' are flonums, because it avoids a boxing
step. But `(/ error 2 x)' would be slower, because it mixes a fixnum
with floats.

Of course, if you want the code to go fast, either use flonum
operations or make the type `Float':

 (: my-sqrt : Natural -> Float)
 (define (my-sqrt y)
   (let loop [(x (/ (exact->inexact y) 2.0))]
     (let [(error (- y (* x x)))]
       (if (< (abs error) epsilon) 
           x
           (loop (+ x (/ error (+ x x))))))))

Then it's unlikely to matter whether you use `(/ error (+ x x))' or `(/
error 2 x)' because there's no representation mixing and flonums are
unboxed.



Posted on the users mailing list.