170 lines
6.5 KiB
Scheme
170 lines
6.5 KiB
Scheme
#!/usr/bin/mzscheme -qu
|
|
;; The Computer Language Benchmarks Game
|
|
;; http://shootout.alioth.debian.org/
|
|
;;
|
|
;; Imperative-style implementation based on the SBCL implementation by
|
|
;; Patrick Frankenberger and Juho Snellman, but using only native Scheme
|
|
;; idioms like 'named let' and 'do' special form.
|
|
;;
|
|
;; Contributed by Anthony Borla, then converted for mzscheme
|
|
;; by Matthew Flatt and Brent Fulgham
|
|
;; Made unsafe and optimized by Sam TH
|
|
#|
|
|
Correct output N = 1000 is
|
|
|
|
-0.169075164
|
|
-0.169087605
|
|
|#
|
|
|
|
#lang scheme/base
|
|
(require scheme/cmdline scheme/require
|
|
(only-in scheme/flonum flvector)
|
|
(for-syntax scheme/base)
|
|
(filtered-in
|
|
(lambda (name)
|
|
(regexp-replace
|
|
#rx"unsafe-fl" name "fl"))
|
|
scheme/unsafe/ops))
|
|
|
|
;; ------------------------------
|
|
;; define planetary masses, initial positions & velocity
|
|
|
|
(define +pi+ 3.141592653589793) ;; define locally to enable inlining
|
|
(define +days-per-year+ 365.24)
|
|
|
|
(define +solar-mass+ (* 4 +pi+ +pi+))
|
|
|
|
(define +dt+ 0.01)
|
|
|
|
(define make-body flvector)
|
|
(define-syntax-rule (deffield n getter setter)
|
|
(begin (define-syntax-rule (getter b) (flvector-ref b n))
|
|
(define-syntax-rule (setter b x) (flvector-set! b n x))))
|
|
(deffield 0 body-x set-body-x!)
|
|
(deffield 1 body-y set-body-y!)
|
|
(deffield 2 body-z set-body-z!)
|
|
(deffield 3 body-vx set-body-vx!)
|
|
(deffield 4 body-vy set-body-vy!)
|
|
(deffield 5 body-vz set-body-vz!)
|
|
(deffield 6 body-mass set-body-mass!)
|
|
|
|
(define *sun*
|
|
(make-body 0.0 0.0 0.0 0.0 0.0 0.0 +solar-mass+))
|
|
|
|
(define *jupiter*
|
|
(make-body 4.84143144246472090
|
|
-1.16032004402742839
|
|
-1.03622044471123109e-1
|
|
(fl* 1.66007664274403694e-3 +days-per-year+)
|
|
(fl* 7.69901118419740425e-3 +days-per-year+)
|
|
(fl* -6.90460016972063023e-5 +days-per-year+)
|
|
(fl* 9.54791938424326609e-4 +solar-mass+)))
|
|
|
|
(define *saturn*
|
|
(make-body 8.34336671824457987
|
|
4.12479856412430479
|
|
-4.03523417114321381e-1
|
|
(fl* -2.76742510726862411e-3 +days-per-year+)
|
|
(fl* 4.99852801234917238e-3 +days-per-year+)
|
|
(fl* 2.30417297573763929e-5 +days-per-year+)
|
|
(fl* 2.85885980666130812e-4 +solar-mass+)))
|
|
|
|
(define *uranus*
|
|
(make-body 1.28943695621391310e1
|
|
-1.51111514016986312e1
|
|
-2.23307578892655734e-1
|
|
(fl* 2.96460137564761618e-03 +days-per-year+)
|
|
(fl* 2.37847173959480950e-03 +days-per-year+)
|
|
(fl* -2.96589568540237556e-05 +days-per-year+)
|
|
(fl* 4.36624404335156298e-05 +solar-mass+)))
|
|
|
|
(define *neptune*
|
|
(make-body 1.53796971148509165e+01
|
|
-2.59193146099879641e+01
|
|
1.79258772950371181e-01
|
|
(fl* 2.68067772490389322e-03 +days-per-year+)
|
|
(fl* 1.62824170038242295e-03 +days-per-year+)
|
|
(fl* -9.51592254519715870e-05 +days-per-year+)
|
|
(fl* 5.15138902046611451e-05 +solar-mass+)))
|
|
|
|
(define *system* (vector *sun* *jupiter* *saturn* *uranus* *neptune*))
|
|
(define *system-size* 5)
|
|
;; -------------------------------
|
|
(define (offset-momentum)
|
|
(let loop-i ([i 0] [px 0.0] [py 0.0] [pz 0.0])
|
|
(if (unsafe-fx= i *system-size*)
|
|
(begin
|
|
(set-body-vx! (unsafe-vector-ref *system* 0) (fl/ (fl- 0.0 px) +solar-mass+))
|
|
(set-body-vy! (unsafe-vector-ref *system* 0) (fl/ (fl- 0.0 py) +solar-mass+))
|
|
(set-body-vz! (unsafe-vector-ref *system* 0) (fl/ (fl- 0.0 pz) +solar-mass+)))
|
|
(let ([i1 (unsafe-vector-ref *system* i)])
|
|
(loop-i (unsafe-fx+ i 1)
|
|
(fl+ px (fl* (body-vx i1) (body-mass i1)))
|
|
(fl+ py (fl* (body-vy i1) (body-mass i1)))
|
|
(fl+ pz (fl* (body-vz i1) (body-mass i1))))))))
|
|
|
|
;; -------------------------------
|
|
(define (energy)
|
|
(let loop-o ([o 0] [e 0.0])
|
|
(if (unsafe-fx= o *system-size*)
|
|
e
|
|
(let* ([o1 (unsafe-vector-ref *system* o)]
|
|
[e (fl+ e (fl* (fl* 0.5 (body-mass o1))
|
|
(fl+ (fl+ (fl* (body-vx o1) (body-vx o1))
|
|
(fl* (body-vy o1) (body-vy o1)))
|
|
(fl* (body-vz o1) (body-vz o1)))))])
|
|
(let loop-i ([i (unsafe-fx+ o 1)] [e e])
|
|
(if (unsafe-fx= i *system-size*)
|
|
(loop-o (unsafe-fx+ o 1) e)
|
|
(let* ([i1 (unsafe-vector-ref *system* i)]
|
|
[dx (fl- (body-x o1) (body-x i1))]
|
|
[dy (fl- (body-y o1) (body-y i1))]
|
|
[dz (fl- (body-z o1) (body-z i1))]
|
|
[dist (flsqrt (fl+ (fl+ (fl* dx dx) (fl* dy dy)) (fl* dz dz)))]
|
|
[e (fl- e (fl/ (fl* (body-mass o1) (body-mass i1)) dist))])
|
|
(loop-i (unsafe-fx+ i 1) e))))))))
|
|
|
|
;; -------------------------------
|
|
(define (advance)
|
|
(let loop-o ([o 0])
|
|
(unless (unsafe-fx= o *system-size*)
|
|
(let* ([o1 (unsafe-vector-ref *system* o)])
|
|
(let loop-i ([i (unsafe-fx+ o 1)]
|
|
[vx (body-vx o1)]
|
|
[vy (body-vy o1)]
|
|
[vz (body-vz o1)])
|
|
(if (unsafe-fx< i *system-size*)
|
|
(let* ([i1 (unsafe-vector-ref *system* i)]
|
|
[dx (fl- (body-x o1) (body-x i1))]
|
|
[dy (fl- (body-y o1) (body-y i1))]
|
|
[dz (fl- (body-z o1) (body-z i1))]
|
|
[dist2 (fl+ (fl+ (fl* dx dx) (fl* dy dy)) (fl* dz dz))]
|
|
[mag (fl/ +dt+ (fl* dist2 (flsqrt dist2)))]
|
|
[dxmag (fl* dx mag)]
|
|
[dymag (fl* dy mag)]
|
|
[dzmag (fl* dz mag)]
|
|
[om (body-mass o1)]
|
|
[im (body-mass i1)])
|
|
(set-body-vx! i1 (fl+ (body-vx i1) (fl* dxmag om)))
|
|
(set-body-vy! i1 (fl+ (body-vy i1) (fl* dymag om)))
|
|
(set-body-vz! i1 (fl+ (body-vz i1) (fl* dzmag om)))
|
|
(loop-i (unsafe-fx+ i 1)
|
|
(fl- vx (fl* dxmag im))
|
|
(fl- vy (fl* dymag im))
|
|
(fl- vz (fl* dzmag im))))
|
|
(begin (set-body-vx! o1 vx)
|
|
(set-body-vy! o1 vy)
|
|
(set-body-vz! o1 vz)
|
|
(set-body-x! o1 (fl+ (body-x o1) (fl* +dt+ vx)))
|
|
(set-body-y! o1 (fl+ (body-y o1) (fl* +dt+ vy)))
|
|
(set-body-z! o1 (fl+ (body-z o1) (fl* +dt+ vz)))))))
|
|
(loop-o (unsafe-fx+ o 1)))))
|
|
|
|
;; -------------------------------
|
|
|
|
(let ([n (command-line #:args (n) (string->number n))])
|
|
(offset-momentum)
|
|
(printf "~a\n" (real->decimal-string (energy) 9))
|
|
(for ([i (in-range n)]) (advance))
|
|
(printf "~a\n" (real->decimal-string (energy) 9)))
|