The Computer Language
Benchmarks Game

n-body Hack #5 program

source code

<?hh

/* The Computer Language Benchmarks Game
   http://benchmarksgame.alioth.debian.org/

   contributed by Stuart Carnie
   converted from C++ version by Branimir Maksimovic
*/

define('PI', 3.141592653589793);
define('SOLAR_MASS', 4.0 * PI * PI);
define('DAYS_PER_YEAR', 365.24);

class Body {
    public float $x, $y, $z, $vx, $vy, $vz, $mass;

    public static function jupiter():Body {
        static $p;
        if (!isset($p)) {
            $p = new Body;
            $p->x = 4.84143144246472090e+00;
            $p->y = -1.16032004402742839e+00;
            $p->z = -1.03622044471123109e-01;
            $p->vx = 1.66007664274403694e-03 * DAYS_PER_YEAR;
            $p->vy = 7.69901118419740425e-03 * DAYS_PER_YEAR;
            $p->vz = -6.90460016972063023e-05 * DAYS_PER_YEAR;
            $p->mass = 9.54791938424326609e-04 * SOLAR_MASS; 
        }
        return $p;
    }

    public static function saturn():Body {
        static $p;
        if (!isset($p)) {
            $p = new Body;
            $p->x = 8.34336671824457987e+00;
            $p->y = 4.12479856412430479e+00;
            $p->z = -4.03523417114321381e-01;
            $p->vx = -2.76742510726862411e-03 * DAYS_PER_YEAR;
            $p->vy = 4.99852801234917238e-03 * DAYS_PER_YEAR;
            $p->vz = 2.30417297573763929e-05 * DAYS_PER_YEAR;
            $p->mass = 2.85885980666130812e-04 * SOLAR_MASS;
        }
        return $p;
    }

    public static function uranus():Body {
        static $p;
        if (!isset($p)) {
            $p = new Body;
            $p->x = 1.28943695621391310e+01;
            $p->y = -1.51111514016986312e+01;
            $p->z = -2.23307578892655734e-01;
            $p->vx = 2.96460137564761618e-03 * DAYS_PER_YEAR;
            $p->vy = 2.37847173959480950e-03 * DAYS_PER_YEAR;
            $p->vz = -2.96589568540237556e-05 * DAYS_PER_YEAR;
            $p->mass = 4.36624404335156298e-05 * SOLAR_MASS;
        }
        return $p;
    }

    public static function neptune():Body {
        static $p;
        if (!isset($p)) {
            $p = new Body;
            $p->x = 1.53796971148509165e+01;
            $p->y = -2.59193146099879641e+01;
            $p->z = 1.79258772950371181e-01;
            $p->vx = 2.68067772490389322e-03 * DAYS_PER_YEAR;
            $p->vy = 1.62824170038242295e-03 * DAYS_PER_YEAR;
            $p->vz = -9.51592254519715870e-05 * DAYS_PER_YEAR;
            $p->mass = 5.15138902046611451e-05 * SOLAR_MASS;
        }
        return $p;
    }

    public static function sun():Body {
        static $p;
        if (!isset($p)) {
            $p = new Body;
            $p->x = 0.0;
            $p->y = 0.0;
            $p->z = 0.0;
            $p->vx = 0.0;
            $p->vy = 0.0;
            $p->vz =0.0;
            $p->mass = SOLAR_MASS;
        }
        return $p;
    }


    public function offsetMomentum(float $px, float $py, float $pz):void {
        $this->vx = -$px / SOLAR_MASS;
        $this->vy = -$py / SOLAR_MASS;
        $this->vz = -$pz / SOLAR_MASS;
    }
}

class NBodySystem {

    private Vector<Body> $bodies;

    function __construct() {
        $this->bodies = Vector<Body> {
            Body::sun(),
            Body::jupiter(),
            Body::saturn(),
            Body::uranus(),
            Body::neptune()
        };

        $px = 0.0; $py = 0.0; $pz = 0.0;
        foreach ($this->bodies as $body) {
            $px += $body->vx * $body->mass;
            $py += $body->vy * $body->mass;
            $pz += $body->vz * $body->mass;
        }
        $this->bodies[0]->offsetMomentum($px, $py, $pz);
    }

    public function advance(float $dt):void {
        $bodies = $this->bodies->count();
        
        for ($i=0; $i<$bodies; ++$i) {
            $iBody = $this->bodies[$i];
            for ($j=$i+1; $j<$bodies; ++$j) {
                $jBody = $this->bodies[$j];

                $dx = $iBody->x - $jBody->x;
                $dy = $iBody->y - $jBody->y;
                $dz = $iBody->z - $jBody->z;
                $distance = \sqrt($dx*$dx + $dy*$dy + $dz*$dz);
                $mag = $dt / ($distance * $distance * $distance);
                $iBody->vx -= $dx * $jBody->mass * $mag;
                $iBody->vy -= $dy * $jBody->mass * $mag;
                $iBody->vz -= $dz * $jBody->mass * $mag;

                $jBody->vx += $dx * $iBody->mass * $mag;
                $jBody->vy += $dy * $iBody->mass * $mag;
                $jBody->vz += $dz * $iBody->mass * $mag;
            }
        }
        for ($i=0; $i<$bodies; ++$i) {
            $body = $this->bodies[$i];
            $body->x += $dt * $body->vx;
            $body->y += $dt * $body->vy;
            $body->z += $dt * $body->vz;
        }
    }

    public function energy():float {
        $e = 0.0;

        $bodies = $this->bodies->count();
        for ($i=0; $i<$bodies; ++$i) {
            $body = $this->bodies[$i];

            $e += 0.5 * $body->mass *
                ($body->vx * $body->vx
                 + $body->vy * $body->vy
                 + $body->vz * $body->vz);

            for ($j=$i+1; $j<$bodies; ++$j) {
                $jBody = $this->bodies[$j];
                
                $dx = $body->x - $jBody->x;
                $dy = $body->y - $jBody->y;
                $dz = $body->z - $jBody->z;

                $distance = \sqrt($dx*$dx + $dy*$dy + $dz*$dz);
                $e -= ($body->mass * $jBody->mass) / $distance;
            }
        }
        return $e;
    }
}

$n = $argv[1] + 1;

$bodies = new NBodySystem;

printf("%.9f\n", $bodies->energy());

while (--$n) {
    $bodies->advance(0.01);
}

printf("%.9f\n", $bodies->energy());
    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
HipHop VM 3.21.0 (rel)
Compiler: 3.21.0+dfsg-2
Repo schema: 1c159cf2047dca5f4a3363b2138a33e14a1e99fa


Wed, 15 Nov 2017 23:57:07 GMT

MAKE:
/usr/bin/hh_client
No errors!

0.08s to complete and log all make actions

COMMAND LINE:
/usr/bin/hhvm  -d hhvm.hack.lang.look_for_typechecker=0 nbody.hack-5.hack 50000000

PROGRAM OUTPUT:
-0.169075164
-0.169059907