Dear list,
I was keeping this question in the back of my mind for several years so
taking the occasion to reflect it now:
Here follows the result of a simple benchmark of (exact->inexact n)
and (exact->inexact
(floor n)) where n is a flonum, fixnum or bignum integer, or rational.
The code was executed in compiled form, with both safe and
interrupts-enabled set and without any consideration to C compiler flags
beyond -O1 , to reflect the environment of a typical application (not for
instance a specialized number crunching environment).
I remember a conversation on this topic like ~4y ago but don't remember any
conclusion from it.
Looking at these numbers, I think they're great and all you can ask for,
with two exceptions, being to-integer conversion of a flonum or integer
bignum.
To get a better idea I experimented with heap size and live percent setting
with those two, and got about the same results.
If you are aware of any definition of |->integer| that would perform much
better, please feel free to share!
Result:
On a laptop CPU core, here's how many of the respective operation Gambit
performs per second
->integer of an integer (fixnum) 13,804,449
->integer of a flonum 260,932 (perhaps performs much better with
another definition?)
->integer of a rational 10,130,272
->integer of an integer (bignum) 598,228 (perhaps performs much better with
another definition?)
->flonum of an integer (fixnum) 36,550,882
->flonum of a flonum 47,756,845
->flonum of a rational 334,976
->flonum of an integer (bignum) 51,075,409
Test code:
(declare (block) (standard-bindings) (extended-bindings))
(define (noop) (void))
(define (->integer n)
(lambda ()
(inexact->exact (floor n))))
(define (->flonum n)
(lambda ()
(exact->inexact n)))
(define (test t #!optional (seconds 5))
(let* ((at 0)
(th (thread-start! (make-thread (lambda () (let loop ()
(t)
(set! at (fx+ at 1))
(loop)))))))
(thread-sleep! seconds)
(let ((r at))
(thread-terminate! th)
(exact->inexact (/ r seconds)))))
(define (noop-test) (test noop))
(define (->integer-test1) (test (->integer 5 )))
(define (->integer-test2) (test (->integer 5. )))
(define (->integer-test3) (test (->integer 10/7)))
(define (->integer-test4) (test (->integer 1e25)))
(define (->flonum-test1) (test (->flonum 5 )))
(define (->flonum-test2) (test (->flonum 5. )))
(define (->flonum-test3) (test (->flonum 10/7)))
(define (->flonum-test4) (test (->flonum 1e25)))
Test output:
> (time (noop-test))
(time (noop-test))
5040 ms real time
4932 ms cpu time (4896 user, 36 system)
no collections
2112 bytes allocated
6 minor faults
no major faults
57985446.4
> (time (->integer-test1))
(time (->integer-test1))
5019 ms real time
4884 ms cpu time (4872 user, 12 system)
no collections
1232 bytes allocated
no minor faults
no major faults
13804449.
> (time (->integer-test2))
(time (->integer-test2))
5000 ms real time
4792 ms cpu time (4656 user, 136 system)
81 collections accounting for 187 ms real time (120 user, 52 system)
1607420656 bytes allocated
5110 minor faults
no major faults
260932.6
> (time (->integer-test3))
(time (->integer-test3))
5015 ms real time
4888 ms cpu time (4872 user, 16 system)
no collections
2240 bytes allocated
no minor faults
no major faults
10130272.8
> (time (->integer-test4))
(time (->integer-test4))
5003 ms real time
4680 ms cpu time (4536 user, 144 system)
158 collections accounting for 401 ms real time (304 user, 60 system)
3110877424 bytes allocated
no minor faults
no major faults
598228.8
> (time (->flonum-test1))
(time (->flonum-test1))
5011 ms real time
4740 ms cpu time (4460 user, 280 system)
297 collections accounting for 736 ms real time (524 user, 124 system)
5848140864 bytes allocated
no minor faults
no major faults
36550882.2
> (time (->flonum-test2))
(time (->flonum-test2))
5001 ms real time
4840 ms cpu time (4800 user, 40 system)
no collections
2088 bytes allocated
no minor faults
no major faults
47756845.8
> (time (->flonum-test3))
(time (->flonum-test3))
5005 ms real time
4972 ms cpu time (4920 user, 52 system)
65 collections accounting for 147 ms real time (120 user, 16 system)
1286350504 bytes allocated
no minor faults
no major faults
334976.6
> (time (->flonum-test4))
(time (->flonum-test4))
5002 ms real time
4876 ms cpu time (4848 user, 28 system)
no collections
2080 bytes allocated
no minor faults
no major faults
51075409.8
2013/4/24 Bradley Lucier <lucier(a)math.purdue.edu>
> On 04/24/2013 01:33 PM, Mikael wrote:
>
> Hi Brad!
>
> 2013/4/24 Bradley Lucier <lucier(a)math.purdue.edu>
>
>> On 04/24/2013 12:37 PM, Zhen Shen wrote:
>>
>
> [...]
>
>
>> > Now, doing (declare (flonum)) at the top level, does this stop gambit
>> > from boxing flonums across function calls?
>>
>> No. Gambit keeps flonums unboxed inside a basic block, whenever there's
>> a jump (or the possibility of a jump), Gambit boxes up all the
>> still-needed flonums.
>>
>
> What about fixnums, would they remain unboxed in a loop?
>
>
> Yes. Fixnums are always "immediate" (not boxed) values.
>
>
>
> Also btw, are there any tricks that can be applied to make it keep
> flonums and fixnums unboxed in loops, like, (declare (not
> interrupts-enabled)) or (not safe)?
>
>
> Use (declare (not safe)) and flonum-specific operations to keep flonums
> unboxed in a basic block. There's no way to keep them unboxed across jumps.
> (With generic operations, flonums are boxed even in a basic block.)
>
> Or, you can use an f64vector as an explicit "box" for your flonum and
> write monstrous code like this.
>
> (define (Array-sum a)
> (f64vector-ref (Array-reduce (lambda (result y)
> (f64vector-set! result 0 (fl+
> (f64vector-ref result 0) y))
> result)
> (f64vector 0.)
> a)
> 0))
>
> Brad
>