Support the TailBench9000 benchmark in run-jsc-benchmarks
[WebKit-https.git] / PerformanceTests / TailBench9000 / n-body.js
1 "use strict";
2
3 function TEST_nBody()
4 {
5     /* The Great Computer Language Shootout
6        http://shootout.alioth.debian.org/
7        contributed by Isaac Gouy */
8
9     var PI = 3.141592653589793;
10     var SOLAR_MASS = 4 * PI * PI;
11     var DAYS_PER_YEAR = 365.24;
12
13     function Body(x,y,z,vx,vy,vz,mass){
14         this.x = x;
15         this.y = y;
16         this.z = z;
17         this.vx = vx;
18         this.vy = vy;
19         this.vz = vz;
20         this.mass = mass;
21     }
22
23     Body.prototype.offsetMomentum = function(px,py,pz) {
24         this.vx = -px / SOLAR_MASS;
25         this.vy = -py / SOLAR_MASS;
26         this.vz = -pz / SOLAR_MASS;
27         return this;
28     }
29
30     function Jupiter(){
31         return new Body(
32             4.84143144246472090e+00,
33                 -1.16032004402742839e+00,
34                 -1.03622044471123109e-01,
35             1.66007664274403694e-03 * DAYS_PER_YEAR,
36             7.69901118419740425e-03 * DAYS_PER_YEAR,
37                 -6.90460016972063023e-05 * DAYS_PER_YEAR,
38             9.54791938424326609e-04 * SOLAR_MASS
39         );
40     }
41
42     function Saturn(){
43         return new Body(
44             8.34336671824457987e+00,
45             4.12479856412430479e+00,
46                 -4.03523417114321381e-01,
47                 -2.76742510726862411e-03 * DAYS_PER_YEAR,
48             4.99852801234917238e-03 * DAYS_PER_YEAR,
49             2.30417297573763929e-05 * DAYS_PER_YEAR,
50             2.85885980666130812e-04 * SOLAR_MASS
51         );
52     }
53
54     function Uranus(){
55         return new Body(
56             1.28943695621391310e+01,
57                 -1.51111514016986312e+01,
58                 -2.23307578892655734e-01,
59             2.96460137564761618e-03 * DAYS_PER_YEAR,
60             2.37847173959480950e-03 * DAYS_PER_YEAR,
61                 -2.96589568540237556e-05 * DAYS_PER_YEAR,
62             4.36624404335156298e-05 * SOLAR_MASS
63         );
64     }
65
66     function Neptune(){
67         return new Body(
68             1.53796971148509165e+01,
69                 -2.59193146099879641e+01,
70             1.79258772950371181e-01,
71             2.68067772490389322e-03 * DAYS_PER_YEAR,
72             1.62824170038242295e-03 * DAYS_PER_YEAR,
73                 -9.51592254519715870e-05 * DAYS_PER_YEAR,
74             5.15138902046611451e-05 * SOLAR_MASS
75         );
76     }
77
78     function Sun(){
79         return new Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS);
80     }
81
82
83     function NBodySystem(bodies){
84         this.bodies = bodies;
85         var px = 0.0;
86         var py = 0.0;
87         var pz = 0.0;
88         var size = this.bodies.length;
89         
90         let iterate = i => {
91             if (i >= size)
92                 return;
93             var b = this.bodies[i];
94             var m = b.mass;
95             px += b.vx * m;
96             py += b.vy * m;
97             pz += b.vz * m;
98             return iterate(i + 1);
99         }
100         
101         iterate(0);
102
103         this.bodies[0].offsetMomentum(px,py,pz);
104     }
105
106     NBodySystem.prototype.advance = function(dt){
107         var dx, dy, dz, distance, mag;
108         var size = this.bodies.length;
109         
110         let outerIterate = i => {
111             if (i >= size)
112                 return;
113             
114             var bodyi = this.bodies[i];
115             
116             let innerIterate = j => {
117                 if (j >= size)
118                     return;
119                 
120                 var bodyj = this.bodies[j];
121                 dx = bodyi.x - bodyj.x;
122                 dy = bodyi.y - bodyj.y;
123                 dz = bodyi.z - bodyj.z;
124
125                 distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
126                 mag = dt / (distance * distance * distance);
127
128                 bodyi.vx -= dx * bodyj.mass * mag;
129                 bodyi.vy -= dy * bodyj.mass * mag;
130                 bodyi.vz -= dz * bodyj.mass * mag;
131
132                 bodyj.vx += dx * bodyi.mass * mag;
133                 bodyj.vy += dy * bodyi.mass * mag;
134                 bodyj.vz += dz * bodyi.mass * mag;
135
136                 return innerIterate(j + 1);
137             }
138             
139             innerIterate(i + 1);
140
141             return outerIterate(i + 1);
142         }
143         
144         outerIterate(0);
145
146         let iterate = i => {
147             if (i >= size)
148                 return;
149
150             var body = this.bodies[i];
151             body.x += dt * body.vx;
152             body.y += dt * body.vy;
153             body.z += dt * body.vz;
154             
155             return iterate(i + 1);
156         }
157
158         iterate(0);
159     }
160
161     NBodySystem.prototype.energy = function(){
162         var dx, dy, dz, distance;
163         var e = 0.0;
164         var size = this.bodies.length;
165
166         let outerIterate = i => {
167             if (i >= size)
168                 return;
169             
170             var bodyi = this.bodies[i];
171
172             e += 0.5 * bodyi.mass *
173                 ( bodyi.vx * bodyi.vx
174                   + bodyi.vy * bodyi.vy
175                   + bodyi.vz * bodyi.vz );
176             
177             let innerIterate = j => {
178                 if (j >= size)
179                     return;
180                 
181                 var bodyj = this.bodies[j];
182                 dx = bodyi.x - bodyj.x;
183                 dy = bodyi.y - bodyj.y;
184                 dz = bodyi.z - bodyj.z;
185
186                 distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
187                 e -= (bodyi.mass * bodyj.mass) / distance;
188
189                 return innerIterate(j + 1);
190             }
191             
192             innerIterate(i + 1);
193             
194             return outerIterate(i + 1);
195         }
196         
197         outerIterate(0);
198         
199         return e;
200     }
201
202     var ret = 0;
203
204     let problem = n => {
205         if (n > 24)
206             return;
207         
208         (function(){
209             var bodies = new NBodySystem( Array(
210                 Sun(),Jupiter(),Saturn(),Uranus(),Neptune()
211             ));
212             var max = n * 100;
213             
214             ret += bodies.energy();
215             
216             let iterate = i => {
217                 if (i >= max)
218                     return;
219                 
220                 bodies.advance(0.01);
221
222                 return iterate(i + 1);
223             };
224             iterate(0);
225
226             ret += bodies.energy();
227         })();
228
229         return problem(n * 2);
230     }
231
232     problem(3);
233
234     var expected = -1.3524862408537381;
235     if (ret != expected)
236         throw "ERROR: bad result: expected " + expected + " but got " + ret;
237 }
238
239 for (var i = 0; i < 300; ++i)
240     TEST_nBody();