Hi all,

Those of you interested in numerical computing should take a look at
my implementation of the "nbody" benchmark from the language shootout:

http://gitweb.factorcode.org/gitweb.cgi?p=factor/.git;a=blob;f=extra/benchmark/nbody/nbody.factor;hb=HEAD

Here are implementations in other languages:

http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=all

The Factor version is a lot more elegant because I'm using the words
in the math.vectors vocabulary instead of doing everything with
explicit x/y/z values. The other implementations juggle 12 local
variables in a single function whereas the Factor version just uses
vector objects with at most 1 or 2 values on the stack. This makes the
Factor version clearer and shorter.

Two of the words use locals, one of them is a combinator that
abstracts out a pattern which appears twice:

:: each-pair ( bodies pair-quot: ( other-body body -- ) each-quot: (
body -- ) -- )
    bodies [| body i |
        body each-quot call
        bodies i 1+ tail-slice [
            body pair-quot call
        ] each
    ] each-index ; inline

The other one is the inner loop of the benchmark:

:: update-velocity ( other-body body dt -- )
    dt body other-body mag
    [ [ body ] 2dip '[ other-body mass>> _ * _ n*v v- ] change-velocity drop ]
    [ [ other-body ] 2dip '[ body mass>> _ * _ n*v v+ ]
change-velocity drop ] 2bi ;

I found the combined usage of locals and fry interesting, although
perhaps it would have been better to just use [let, or rewrite it
without locals and only using fry.

The utility of the math.vectors words cannot be underestimated. For
example, look at the following three words; to me, they're the most
beautiful in this entire program:

: inertia ( body -- e )
    [ mass>> ] [ velocity>> norm-sq ] bi * 0.5 * ;

: newton's-law ( other-body body -- e )
    [ [ mass>> ] bi@ * ] [ [ location>> ] bi@ distance ] 2bi / ;

: energy ( system -- x )
    [ 0.0 ] dip bodies>> [ newton's-law - ] [ inertia + ] each-pair ; inline

Compare this with some Scheme code from the shootout which does the same thing:

(define (energy)
  (let loop-o ([o *system*] [e 0.0])
    (if (null? o)
      e
      (let* ([o1 (car o)]
             [e (+ e (* (* 0.5 (body-mass o1))
                        (+ (+ (* (body-vx o1) (body-vx o1))
                              (* (body-vy o1) (body-vy o1)))
                           (* (body-vz o1) (body-vz o1)))))])
        (let loop-i ([i (cdr o)] [e e])
          (if (null? i)
            (loop-o (cdr o) e)
            (let* ([i1   (car i)]
                   [dx   (- (body-x o1) (body-x i1))]
                   [dy   (- (body-y o1) (body-y i1))]
                   [dz   (- (body-z o1) (body-z i1))]
                   [dist (sqrt (+ (+ (* dx dx) (* dy dy)) (* dz dz)))]
                   [e    (- e (/ (* (body-mass o1) (body-mass i1)) dist))])
              (loop-i (cdr i) e))))))))

Gross!

Slava

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Factor-talk mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/factor-talk

Reply via email to