[plt-dev] range mini benchmark

From: namekuseijin (namekuseijin at gmail.com)
Date: Sat May 2 18:37:20 EDT 2009

Seems to me you're measuring consing.  I'm not really a fan of
creating intermediary lists, I enjoy iterators more.  I have my own
version of range, here simplified:

; returns an iterator for given range
;  given an initial result and a reducer function, will apply it each iteration
(define (range from to)
  (let ((> (if (> from to) < >))
        (+ (if (> from to) - +)))
    (lambda (res reducer)
      (let loop ((i from) (r res))
        (if (> i to) r
            (loop (+ i 1) (reducer i r)))))))

So, I can:
((range 10 1) '() cons)
to create a list from 1 to 10 (cons builds a reverse list)

or simply
((range 1 10) 0 +)
to sum it up, without creating intermediary lists.

or even
((range 1 10) 0 (lambda (i o) (if (odd? i) (+ i o) o)))
to sum only the odds.  Of course, I have a version of filter to work
with iterators. :)

I added it to the benchmark by adding a little twist:  it now builds a
list by consing too.

(define (range-nmk from to)
  (let ((> (if (> from to) < >))
        (+ (if (> from to) - +)))
    ((lambda (res reducer)
      (let loop ((i from) (r res))
        (if (> i to) r
            (loop (+ i 1) (reducer i r))))) '() cons)))


(define ranges (list range-rbl range-ibl range-seq range-nmk))

on DrScheme:
(for ((j (in-range 5))) (range 0 1000000))
range-rbl: cpu time: 852 real time: 851 gc time: 332
range-ibl: cpu time: 1332 real time: 1334 gc time: 88
range-seq: cpu time: 1052 real time: 1055 gc time: 212
range-nmk: cpu time: 704 real time: 706 gc time: 80

(for ((j (in-range 50))) (range 0 100000))
range-rbl: cpu time: 588 real time: 585 gc time: 68
range-ibl: cpu time: 1300 real time: 1301 gc time: 20
range-seq: cpu time: 908 real time: 908 gc time: 72
range-nmk: cpu time: 652 real time: 653 gc time: 20

(for ((j (in-range 500))) (range 0 10000))
range-rbl: cpu time: 544 real time: 544 gc time: 28
range-ibl: cpu time: 1300 real time: 1297 gc time: 12
range-seq: cpu time: 864 real time: 863 gc time: 24
range-nmk: cpu time: 644 real time: 644 gc time: 12

(for ((j (in-range 5000))) (range 0 1000))
range-rbl: cpu time: 544 real time: 543 gc time: 20
range-ibl: cpu time: 1300 real time: 1300 gc time: 8
range-seq: cpu time: 864 real time: 864 gc time: 20
range-nmk: cpu time: 648 real time: 645 gc time: 8

(for ((j (in-range 50000))) (range 0 100))
range-rbl: cpu time: 568 real time: 565 gc time: 20
range-ibl: cpu time: 1328 real time: 1328 gc time: 12
range-seq: cpu time: 900 real time: 902 gc time: 20
range-nmk: cpu time: 664 real time: 664 gc time: 12

The pure recursive way beats it, except for a fairly high range.  I
wonder why...


Posted on the dev mailing list.