source code
/* The Computer Language Benchmarks Game
http://benchmarksgame.alioth.debian.org/
contributed by Isaac Gouy
Transliterated from Smalltalk program
*/
/// <reference path="./Include/node/index.d.ts" />
class PlanetarySystem {
private bodies: Body[]
constructor(){
this.bodies = [
Body.Sun(),
Body.Jupiter(),
Body.Saturn(),
Body.Uranus(),
Body.Neptune()
]
// How to use reduce?
let total : [number,number,number] = [0.0,0.0,0.0]
this.bodies.forEach(each => {
total = each.addMomentumTo(total)
})
this.bodies[0].offsetMomentum(total)
}
after(dt: number) {
const size = this.bodies.length
this.bodies.forEach((each,i) => {
for (let j=i+1; j < size; j++) {
each.setVelocitiesAfter(dt,this.bodies[j])
}
})
this.bodies.forEach(each => {
each.setPositionAfter(dt)
})
}
energy(): number {
let e = 0.0
const size = this.bodies.length
this.bodies.forEach((each,i) => {
e += each.kineticEnergy()
for (let j=i+1; j < size; j++) {
e -= each.potentialEnergyWith(this.bodies[j])
}
})
return e
}
}
class Body {
private static PI = 3.141592653589793
private static SOLAR_MASS = 4 * Body.PI * Body.PI
private static DAYS_PER_YEAR = 365.24
constructor(
private x: number,
private y: number,
private z: number,
private vx: number,
private vy: number,
private vz: number,
private m: number
) { }
mass(): number {
return this.m
}
static Jupiter(){
return new Body(
4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01,
1.66007664274403694e-03 * Body.DAYS_PER_YEAR,
7.69901118419740425e-03 * Body.DAYS_PER_YEAR,
-6.90460016972063023e-05 * Body.DAYS_PER_YEAR,
9.54791938424326609e-04 * Body.SOLAR_MASS
)
}
static Saturn(){
return new Body(
8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01,
-2.76742510726862411e-03 * Body.DAYS_PER_YEAR,
4.99852801234917238e-03 * Body.DAYS_PER_YEAR,
2.30417297573763929e-05 * Body.DAYS_PER_YEAR,
2.85885980666130812e-04 * Body.SOLAR_MASS
)
}
static Uranus(){
return new Body(
1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01,
2.96460137564761618e-03 * Body.DAYS_PER_YEAR,
2.37847173959480950e-03 * Body.DAYS_PER_YEAR,
-2.96589568540237556e-05 * Body.DAYS_PER_YEAR,
4.36624404335156298e-05 * Body.SOLAR_MASS
)
}
static Neptune(){
return new Body(
1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01,
2.68067772490389322e-03 * Body.DAYS_PER_YEAR,
1.62824170038242295e-03 * Body.DAYS_PER_YEAR,
-9.51592254519715870e-05 * Body.DAYS_PER_YEAR,
5.15138902046611451e-05 * Body.SOLAR_MASS
)
}
static Sun(){
return new Body(
0,
0,
0,
0,
0,
0,
Body.SOLAR_MASS
)
}
addMomentumTo([x,y,z]: [number,number,number]): [number,number,number] {
return [
x + this.vx * this.m,
y + this.vy * this.m,
z + this.vz * this.m
]
}
private decreaseVelocity(dx, dy, dz, m: number) {
this.vx -= dx * m
this.vy -= dy * m
this.vz -= dz * m
}
private increaseVelocity(dx, dy, dz, m : number) {
this.vx += dx * m
this.vy += dy * m
this.vz += dz * m
}
kineticEnergy(): number {
return 0.5 * this.m * (this.vx**2 + this.vy**2 + this.vz**2)
}
offsetMomentum([px,py,pz]: [number,number,number]) {
this.vx = -px / Body.SOLAR_MASS
this.vy = -py / Body.SOLAR_MASS
this.vz = -pz / Body.SOLAR_MASS
}
potentialEnergyWith(b: Body) {
const [dx,dy,dz] = b.vectorTo(this.x,this.y,this.z)
const distance = Math.sqrt(dx**2 + dy**2 + dz**2)
return this.m * b.mass() / distance
}
setPositionAfter(dt: number) {
this.x += dt * this.vx
this.y += dt * this.vy
this.z += dt * this.vz
}
setVelocitiesAfter(dt: number, b: Body) {
const [dx,dy,dz] = b.vectorTo(this.x,this.y,this.z)
const distance = Math.sqrt(dx**2 + dy**2 + dz**2)
const mag = dt / distance**3
this.decreaseVelocity(dx,dy,dz,b.mass()*mag)
b.increaseVelocity(dx,dy,dz,this.m*mag)
}
private vectorTo(x,y,z : number) {
return [x-this.x, y-this.y, z-this.z]
}
}
const n = +process.argv[2]
const system = new PlanetarySystem()
console.log(system.energy().toFixed(9))
for (let i=0; i<n; i++){ system.after(0.01) }
console.log(system.energy().toFixed(9))