[Shootout-list] Tcl : n-body bench
Daniel South
WildCard_25@HotMail.Com
Sun, 20 Mar 2005 05:04:44 +1000
While this program does work, I expect it to timeout in the tests. Takes
about 160secs on my pc at N=100000, so that should translate to about
8mins on the test pc :-)
Daniel South
#!/usr/bin/tclsh
# The Great Computer Language Shootout
# http://shootout.alioth.debian.org/
#
# contributed by Daniel South
set PI 3.141592653589793
set SOLAR_MASS [expr {4 * $PI * $PI}]
set DAYS_PER_YEAR 365.24
array set body "
Sun,x 0 Sun,y 0 Sun,z 0 Sun,vx 0 Sun,vy 0 Sun,vz 0 Sun,mass
$SOLAR_MASS
Jupiter,x 4.84143144246472090e+00
Jupiter,y -1.16032004402742839e+00
Jupiter,z -1.03622044471123109e-01
Jupiter,vx [expr {1.66007664274403694e-03 * $DAYS_PER_YEAR}]
Jupiter,vy [expr {7.69901118419740425e-03 * $DAYS_PER_YEAR}]
Jupiter,vz [expr {-6.90460016972063023e-05 * $DAYS_PER_YEAR}]
Jupiter,mass [expr {9.54791938424326609e-04 * $SOLAR_MASS}]
Saturn,x 8.34336671824457987e+00
Saturn,y 4.12479856412430479e+00
Saturn,z -4.03523417114321381e-01
Saturn,vx [expr {-2.76742510726862411e-03 * $DAYS_PER_YEAR}]
Saturn,vy [expr {4.99852801234917238e-03 * $DAYS_PER_YEAR}]
Saturn,vz [expr {2.30417297573763929e-05 * $DAYS_PER_YEAR}]
Saturn,mass [expr {2.85885980666130812e-04 * $SOLAR_MASS}]
Uranus,x 1.28943695621391310e+01
Uranus,y -1.51111514016986312e+01
Uranus,z -2.23307578892655734e-01
Uranus,vx [expr {2.96460137564761618e-03 * $DAYS_PER_YEAR}]
Uranus,vy [expr {2.37847173959480950e-03 * $DAYS_PER_YEAR}]
Uranus,vz [expr {-2.96589568540237556e-05 * $DAYS_PER_YEAR}]
Uranus,mass [expr {4.36624404335156298e-05 * $SOLAR_MASS}]
Neptune,x 1.53796971148509165e+01
Neptune,y -2.59193146099879641e+01
Neptune,z 1.79258772950371181e-01
Neptune,vx [expr {2.68067772490389322e-03 * $DAYS_PER_YEAR}]
Neptune,vy [expr {1.62824170038242295e-03 * $DAYS_PER_YEAR}]
Neptune,vz [expr {-9.51592254519715870e-05 * $DAYS_PER_YEAR}]
Neptune,mass [expr {5.15138902046611451e-05 * $SOLAR_MASS}]"
proc advance {b dt} {
global body
set n [llength $b]
while {[incr n -1] > -1} {
set b1 [lindex $b $n]
set j $n
while {[incr j -1] > -1} {
set b2 [lindex $b $j]
set dx [expr {$body($b1,x) - $body($b2,x)}]
set dy [expr {$body($b1,y) - $body($b2,y)}]
set dz [expr {$body($b1,z) - $body($b2,z)}]
set d [expr {sqrt($dx * $dx + $dy * $dy + $dz * $dz)}]
set mag [expr {$dt / ($d * $d * $d)}]
set magmult1 [expr {$body($b2,mass) * $mag}]
set magmult2 [expr {$body($b1,mass) * $mag}]
set body($b1,vx) [expr {$body($b1,vx) - ($dx * $magmult1)}]
set body($b1,vy) [expr {$body($b1,vy) - ($dy * $magmult1)}]
set body($b1,vz) [expr {$body($b1,vz) - ($dz * $magmult1)}]
set body($b2,vx) [expr {$body($b2,vx) + ($dx * $magmult2)}]
set body($b2,vy) [expr {$body($b2,vy) + ($dy * $magmult2)}]
set body($b2,vz) [expr {$body($b2,vz) + ($dz * $magmult2)}]
}
set body($b1,x) [expr {$body($b1,x) + ($dt * $body($b1,vx))}]
set body($b1,y) [expr {$body($b1,y) + ($dt * $body($b1,vy))}]
set body($b1,z) [expr {$body($b1,z) + ($dt * $body($b1,vz))}]
}
}
proc energy {b} {
global body
set e 0
set n [llength $b]
while {[incr n -1] > -1} {
set b1 [lindex $b $n]
set e [expr {$e + (0.5 * $body($b1,mass) * ( $body($b1,vx) \
* $body($b1,vx) + $body($b1,vy) * $body($b1,vy) + $body($b1,vz) \
* $body($b1,vz) ))}]
set j $n
while {[incr j -1] > -1} {
set b2 [lindex $b $j]
set dx [expr {$body($b1,x) - $body($b2,x)}]
set dy [expr {$body($b1,y) - $body($b2,y)}]
set dz [expr {$body($b1,z) - $body($b2,z)}]
set d [expr {sqrt($dx * $dx + $dy * $dy + $dz * $dz)}]
set e [expr {$e - (($body($b1,mass) * $body($b2,mass)) / $d)}]
}
}
return $e
}
proc offsetMomentum {b} {
global body SOLAR_MASS
foreach {px py pz} {0 0 0} break
foreach b1 $b {
set px [expr {$px + $body($b1,vx) * $body($b1,mass)}]
set py [expr {$py + $body($b1,vy) * $body($b1,mass)}]
set pz [expr {$pz + $body($b1,vz) * $body($b1,mass)}]
}
set body(Sun,vx) [expr {-$px / $SOLAR_MASS}]
set body(Sun,vy) [expr {-$py / $SOLAR_MASS}]
set body(Sun,vz) [expr {-$pz / $SOLAR_MASS}]
}
proc main {n} {
set bodyNames "Sun Jupiter Saturn Uranus Neptune"
offsetMomentum $bodyNames
puts [format "%0.9f" [energy $bodyNames]]
incr n
while {[incr n -1]} {advance $bodyNames 0.01}
puts [format "%0.9f" [energy $bodyNames]]
}
set N [lindex $argv 0]
if {$N < 1} {set N 1000}
main $N