On Oct 30, 2008, at 9:33 AM, David Rush wrote:
On Thu, Oct 30, 2008 at 2:32 AM, Marc Feeley feeley@iro.umontreal.ca wrote:
(define (f0 x) ;; 4600 ns per call (declare (standard-bindings)) (inexact->exact (truncate x)))
(define (f1 x) ;; 4000 ns per call (declare (standard-bindings)) (truncate (inexact->exact x)))
This is *really* interesting w/rt the implementation model of floats. I would guess that this means that inexact->exact just flips an exactness bit in Gambit's float representation, no? I would have thought that truncating an exact rational would be rather expensive in comparison to normalizing a floating integer. I'd think that truncating a float would be relatively cheap.
What's really going on here?
I don't quite get Marc's timings; let's look at the expansion:
[descartes:~/Desktop] lucier% cat fix.scm (define (f0 x) ;; 4600 ns per call (declare (standard-bindings)) (inexact->exact (truncate x)))
(define (f1 x) ;; 4000 ns per call (declare (standard-bindings)) (truncate (inexact->exact x)))
(define (test0 n x) (declare (standard-bindings) (extended-bindings) (fixnum) (not safe)) (do ((i 0 (+ i 1))) ((= i n)) (f0 x)))
(define (test1 n x) (declare (standard-bindings) (extended-bindings) (fixnum) (not safe)) (do ((i 0 (+ i 1))) ((= i n)) (f1 x)))
[descartes:~/Desktop] lucier% gsc -keep-c -expansion -cc-options "- save-temps" fix.scm Expansion:
(define f0 (lambda (x) (let ((temp.5 (if (and ('#<procedure #2 ##flonum?> x) ('#<procedure #3 ##flfinite?> x)) ('#<procedure #4 ##fltruncate> x) (truncate x)))) (if ('#<procedure #5 ##fixnum?> temp.5) temp.5 (inexact->exact temp.5)))))
(define f1 (lambda (x) (let ((temp.7 (if ('#<procedure #5 ##fixnum?> x) x (inexact-
exact x))))
(if (and ('#<procedure #2 ##flonum?> temp.7) ('#<procedure #3 ##flfinite?> temp.7)) ('#<procedure #4 ##fltruncate> temp.7) (truncate temp.7)))))
(define test0 (lambda (n x) (letrec ((do-temp.0 (lambda (n x i) (if ('#<procedure #6 ##fx=> i n) #!void (let ((begin-temp.1 (f0 x))) (let ((i ('#<procedure #7 ##fx+> i 1))) (if ('#<procedure #6 ##fx=> i n) #!void (let ((begin-temp.1 (f0 x))) (do-temp.0 n x ('#<procedure #7 ##fx+> i 1)))))))))) (do-temp.0 n x 0))))
(define test1 (lambda (n x) (letrec ((do-temp.2 (lambda (n x i) (if ('#<procedure #6 ##fx=> i n) #!void (let ((begin-temp.3 (f1 x))) (let ((i ('#<procedure #7 ##fx+> i 1))) (if ('#<procedure #6 ##fx=> i n) #!void (let ((begin-temp.3 (f1 x))) (do-temp.2 n x ('#<procedure #7 ##fx+> i 1)))))))))) (do-temp.2 n x 0))))
[descartes:~/Desktop] lucier% gsi Gambit v4.3.0
(load "fix")
"/Users/lucier/Desktop/fix.o2"
(time (test1 1000000 0.2))
(time (test1 1000000 .2)) 2237 ms real time 2218 ms cpu time (2164 user, 54 system) 1265 collections accounting for 1027 ms real time (986 user, 21 system) 400000000 bytes allocated no minor faults no major faults
(time (test0 1000000 0.2))
(time (test0 1000000 .2)) 4523 ms real time 4490 ms cpu time (4359 user, 131 system) 3907 collections accounting for 3122 ms real time (3007 user, 56 system) 1232000000 bytes allocated no minor faults no major faults
*** EOF again to exit [descartes:~/Desktop] lucier% gsi -:m100000 Gambit v4.3.0
(load "fix")
"/Users/lucier/Desktop/fix.o2"
(time (test1 1000000 0.2))
(time (test1 1000000 .2)) 1453 ms real time 1437 ms cpu time (1237 user, 200 system) 3 collections accounting for 3 ms real time (3 user, 0 system) 400000000 bytes allocated no minor faults no major faults
(time (test0 1000000 0.2))
(time (test0 1000000 .2)) 1372 ms real time 1363 ms cpu time (1346 user, 17 system) 12 collections accounting for 11 ms real time (11 user, 0 system) 1232138320 bytes allocated no minor faults no major faults
It appears that once one defines a large enough minimum heap size to basically remove gc time, the largest time hog is the intermodule calls and returns for inexact->exact and truncate. You can see that working with rational numbers adds a lot to the heap allocation.
Brad