[racket] Math - factorial.rkt, binomial.rkt and memoization

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Mon Apr 8 15:11:00 EDT 2013

Hi Laurent,

I am curious to see how fast the libgmp versions of factorial

and binomial are on your computer. Om my computer libgmp

is much faster than the Racket one.

Since the libgmp versions converts a Racket bignum into

a mpz, there is some overhead, so a proper solution

would be to use a Racket version for small numbers,

and then call the libgmp for large numbers.

An even better solution would be to have a builtin bignum->mpz.

/Jens Axel

#lang racket
(require math/private/bigfloat/gmp)
(require (for-syntax racket/base)

(define-runtime-path libgmp-so
  (case (system-type)
    [(macosx) '(so "libgmp.10.dylib")]
    [(windows) '(so "libgmp-10.dll")]
    [else '(so "libgmp")]))

(define (get-gmp-fun name type)
  (get-ffi-obj name gmp-lib type (make-not-available name)))

(define mpz-fac-ui
  (get-gmp-fun '__gmpz_fac_ui  (_fun _mpz-pointer _int -> _mpz-pointer)))

(define (fact n)
  (define n! (new-mpz))
  (mpz-fac-ui n! n)
  (mpz->integer n!))

(define mpz-bin-ui
  (get-gmp-fun '__gmpz_bin_ui
               (_fun _mpz-pointer _mpz-pointer _int -> _mpz-pointer)))

(define (bin n k)
  (define b (new-mpz))
  (mpz-bin-ui b (integer->mpz n) k)
  (mpz->integer b))

(require (only-in math factorial))
(time (for ([i (in-range 2000 2100)])
        (factorial i)))

(time (for ([i (in-range 2000 2100)])
        (fact i)))

(require (only-in math binomial))
(time (for ([n 100])
        (bin 10000 4000)))
(time (for ([n 100])
        (binomial 10000 4000)))

2013/4/8 Laurent <laurent.orseau at gmail.com>

> Would it make sense to use memoization more broadly for the definition of
> the factorial in the math lib, maybe with a `provide'd parameter to control
> how many values can be memoized?
> https://github.com/plt/racket/blob/master/collects/math/private/number-theory/factorial.rkt
> While building big numbers (around 800!) I had to redefine my own
> factorial and binomial functions with memoization, otherwise it would take
> too long.
> Also, probably `binomial' could take advantage of this memoization, just
> like `permutations' does.
> https://github.com/plt/racket/blob/master/collects/math/private/number-theory/binomial.rkt
> Currently (in DrRacket, so not entirely accurate, but should be close
> enough):
> > (time
>    (for ([n 100])
>      (binomial 10000 4000)))
> cpu time: 4072 real time: 4075 gc time: 440
> > (time
>    (for ([n 10000])
>      (binomial 800 400)))
> cpu time: 9424 real time: 9430 gc time: 836
> > (time (for ([i 1000])
>           (factorial 10000)))
> cpu time: 11441 real time: 11630 gc time: 276
> which makes it impractical in some cases.
> Laurent
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Jens Axel Søgaard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130408/ae97e9a8/attachment-0001.html>

Posted on the users mailing list.