nbody.scm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #|
  2. The Computer Language Benchmarks Game
  3. http://shootout.alioth.debian.org/
  4. Contributed by Per Bothner
  5. Based on Java version contributed by Mark C. Lewis,
  6. modified slightly by Chad Whipkey.
  7. |#
  8. (define-syntax square
  9. (syntax-rules ()
  10. ((square x)
  11. (let ((tmp x)) (* tmp tmp)))))
  12. (define-syntax increment
  13. (syntax-rules ()
  14. ((increment lhs rhs)
  15. (set! lhs (+ lhs rhs)))))
  16. (define-syntax decrement
  17. (syntax-rules ()
  18. ((increment lhs rhs)
  19. (set! lhs (- lhs rhs)))))
  20. (define-constant PI :: double 3.141592653589793)
  21. (define-constant SOLAR_MASS :: double (* 4 PI PI))
  22. (define-constant DAYS_PER_YEAR :: double 365.24)
  23. (define-class Body ()
  24. (x :: double)
  25. (y :: double)
  26. (z :: double)
  27. (vx :: double)
  28. (vy :: double)
  29. (vz :: double)
  30. (mass :: double)
  31. ((offsetMomentum (px :: double) (py :: double) (pz :: double)) :: void
  32. (set! vx (/ (- px) SOLAR_MASS))
  33. (set! vy (/ (- py) SOLAR_MASS))
  34. (set! vz (/ (- pz) SOLAR_MASS))))
  35. (define (nbody-system (n :: int)) :: void
  36. (let* ((bodies (Body[] (sun) (jupiter) (saturn) (uranus) (neptune)))
  37. (px :: double 0)
  38. (py :: double 0)
  39. (pz :: double 0)
  40. (nbodies :: int bodies:length))
  41. (do ((i :: int 0 (+ i 1))) ((>= i nbodies))
  42. (let* ((ibody (bodies i))
  43. (imass ibody:mass))
  44. (increment px (* ibody:vx imass))
  45. (increment py (* ibody:vy imass))
  46. (increment pz (* ibody:vz imass))))
  47. ((bodies 0):offsetMomentum px py pz)
  48. (format #t "~,9f~%" (energy bodies))
  49. (do ((i :: int 0 (+ i 1))) ((>= i n))
  50. (advance bodies 0.01))
  51. (format #t "~,9f~%" (energy bodies))))
  52. (define (advance (bodies ::Body[]) (dt ::double)) :: void
  53. (let ((nbodies bodies:length))
  54. (do ((i ::int 0 (+ i 1))) ((>= i nbodies))
  55. (! ibody (bodies i))
  56. (do ((j ::int (+ i 1) (+ j 1))) ((>= j nbodies))
  57. (! jbody (bodies j))
  58. (! dx (- ibody:x jbody:x))
  59. (! dy (- ibody:y jbody:y))
  60. (! dz (- ibody:z jbody:z))
  61. (! dsquared (+ (square dx) (square dy) (square dz)))
  62. (! distance (java.lang.Math:sqrt dsquared))
  63. (! mag (/ dt (* dsquared distance)))
  64. (decrement ibody:vx (* dx jbody:mass mag))
  65. (decrement ibody:vy (* dy jbody:mass mag))
  66. (decrement ibody:vz (* dz jbody:mass mag))
  67. (increment jbody:vx (* dx ibody:mass mag))
  68. (increment jbody:vy (* dy ibody:mass mag))
  69. (increment jbody:vz (* dz ibody:mass mag))))
  70. (do ((i ::int 0 (+ i 1))) ((>= i nbodies))
  71. (! body (bodies i))
  72. (increment body:x (* dt body:vx))
  73. (increment body:y (* dt body:vy))
  74. (increment body:z (* dt body:vz)))))
  75. (define (energy (bodies ::Body[])) :: double
  76. ;; should be something like 'defvar'
  77. ;; Maybe: (! e ::double init: 0)
  78. (define e ::double 0)
  79. (! nbodies bodies:length)
  80. (do ((i ::int 0 (+ i 1))) ((>= i nbodies))
  81. (! ibody (bodies i))
  82. (increment e (* 0.5 ibody:mass
  83. (+ (square ibody:vx)
  84. (square ibody:vy)
  85. (square ibody:vz))))
  86. (do ((j ::int (+ i 1) (+ j 1))) ((>= j nbodies))
  87. (! jbody (bodies j))
  88. (! dx (- ibody:x jbody:x))
  89. (! dy (- ibody:y jbody:y))
  90. (! dz (- ibody:z jbody:z))
  91. (! distance (java.lang.Math:sqrt (+ (square dx) (square dy) (square dz))))
  92. (decrement e (/ (* ibody:mass jbody:mass) distance))))
  93. e)
  94. (define (jupiter) :: Body
  95. (Body x: 4.84143144246472090e+00
  96. y: -1.16032004402742839e+00
  97. z: -1.03622044471123109e-01
  98. vx: (* 1.66007664274403694e-03 DAYS_PER_YEAR)
  99. vy: (* 7.69901118419740425e-03 DAYS_PER_YEAR)
  100. vz: (* -6.90460016972063023e-05 DAYS_PER_YEAR)
  101. mass: (* 9.54791938424326609e-04 SOLAR_MASS)))
  102. (define (saturn) :: Body
  103. (Body x: 8.34336671824457987e+00
  104. y: 4.12479856412430479e+00
  105. z: -4.03523417114321381e-01
  106. vx: (* -2.76742510726862411e-03 DAYS_PER_YEAR)
  107. vy: (* 4.99852801234917238e-03 DAYS_PER_YEAR)
  108. vz: (* 2.30417297573763929e-05 DAYS_PER_YEAR)
  109. mass: (* 2.85885980666130812e-04 SOLAR_MASS)))
  110. (define (uranus) :: Body
  111. (Body x: 1.28943695621391310e+01
  112. y: -1.51111514016986312e+01
  113. z: -2.23307578892655734e-01
  114. vx: (* 2.96460137564761618e-03 DAYS_PER_YEAR)
  115. vy: (* 2.37847173959480950e-03 DAYS_PER_YEAR)
  116. vz: (* -2.96589568540237556e-05 DAYS_PER_YEAR)
  117. mass: (* 4.36624404335156298e-05 SOLAR_MASS)))
  118. (define (neptune) :: Body
  119. (Body x: 1.53796971148509165e+01
  120. y: -2.59193146099879641e+01
  121. z: 1.79258772950371181e-01
  122. vx: (* 2.68067772490389322e-03 DAYS_PER_YEAR)
  123. vy: (* 1.62824170038242295e-03 DAYS_PER_YEAR)
  124. vz: (* -9.51592254519715870e-05 DAYS_PER_YEAR)
  125. mass: (* 5.15138902046611451e-05 SOLAR_MASS)))
  126. (define (sun) :: Body
  127. (Body mass: SOLAR_MASS))
  128. (nbody-system (string->number (cadr (command-line))))