[racket] (Math) Computing the mean is slow in Typed Racket

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Fri Feb 8 04:56:03 EST 2013

Hi Laurent,

2013/2/8 Laurent <laurent.orseau at gmail.com>:
> (Just a little testing of the exciting new math lib.)
> Is it currently normal that computing the mean of a big list is 10x slower
> compared to the (/ (apply + l) (length l)) method?
> The math lib is very recent so I'm not entirely surprised, anyway. Most of
> the time seems to be due to GC.
> E.g. (on command line Racket) :
> #lang typed/racket
> (require math)
> (: n Integer)
> (define n 10000000)
> (: l (Listof Integer))
> (define l (build-list n (λ(x)(random 100))))
> (: my-mean ((Listof Integer) -> Number))
> (define (my-mean l)
>   (/ (apply + l) (length l)))
> (time (mean l))
> (time (my-mean l))

Nice catch. Here is the code for mean from:

The function handles general sequences and optional weights.

(: mean (case-> ((Sequenceof Real) -> Real)
                ((Sequenceof Real) (Option (Sequenceof Real)) -> Real)))
(define (mean xs [ws #f])
  (cond [ws  (let-values ([(xs ws)  (sequences->weighted-samples 'mean xs ws)])
               (define n (sum ws))
               (cond [(zero? n)  +nan.0]
                     [else  (/ (sum (map * xs ws)) n)]))]
        [else  (let ([xs  (sequence->list xs)])
                 (define n (length xs))
                 (cond [(zero? n)  +nan.0]
                       [else  (/ (sum xs) n)]))]))

In this case ws is #f, so we can ignore the first cond-clause,
and concentrate on:

  (let ([xs  (sequence->list xs)])
                 (define n (length xs))
                 (cond [(zero? n)  +nan.0]
                            [else  (/ (sum xs) n)]))]))

Here we see why the mean was slow:
     [xs (sequence->list xs)]
This copies the list even though xs is a list already.

           [xs  (if (list? xs) xs (sequence->list xs))])
and see what the new timings are.

Jens Axel Søgaard

Posted on the users mailing list.