Skip to content

Instantly share code, notes, and snippets.

@Girgias
Last active August 12, 2020 20:30
Show Gist options
  • Save Girgias/e21b57cff72b8d05be06883d98552ee6 to your computer and use it in GitHub Desktop.
Save Girgias/e21b57cff72b8d05be06883d98552ee6 to your computer and use it in GitHub Desktop.
Attempt at a better version of n-body for PHP
<?php
/* The Computer Language Benchmarks Game
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
Contributed by George Peter Banyard
*/
final class Body {
private const SOLAR_MASS = 4 * M_PI * M_PI;
private const DAYS_PER_YEAR = 365.24;
public float $x;
public float $y;
public float $z;
public float $vx;
public float $vy;
public float $vz;
public float $mass;
public function __construct(
float $x,
float $y,
float $z,
float $vx,
float $vy,
float $vz,
float $mass
) {
$this->x = $x;
$this->y = $y;
$this->z = $z;
$this->vx = $vx;
$this->vy = $vy;
$this->vz = $vz;
$this->mass = $mass;
}
public function offsetMomentum(float $px, float $py, float $pz): self
{
$this->vx = -$px / self::SOLAR_MASS;
$this->vy = -$py / self::SOLAR_MASS;
$this->vz = -$pz / self::SOLAR_MASS;
return $this;
}
public static function jupiter(): self
{
return new self(
4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01,
1.66007664274403694e-03 * self::DAYS_PER_YEAR,
7.69901118419740425e-03 * self::DAYS_PER_YEAR,
-6.90460016972063023e-05 * self::DAYS_PER_YEAR,
9.54791938424326609e-04 * self::SOLAR_MASS,
);
}
public static function saturn(): self
{
return new self(
8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01,
-2.76742510726862411e-03 * self::DAYS_PER_YEAR,
4.99852801234917238e-03 * self::DAYS_PER_YEAR,
2.30417297573763929e-05 * self::DAYS_PER_YEAR,
2.85885980666130812e-04 * self::SOLAR_MASS,
);
}
public static function uranus(): self
{
return new self(
1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01,
2.96460137564761618e-03 * self::DAYS_PER_YEAR,
2.37847173959480950e-03 * self::DAYS_PER_YEAR,
-2.96589568540237556e-05 * self::DAYS_PER_YEAR,
4.36624404335156298e-05 * self::SOLAR_MASS
);
}
public static function neptune(): self
{
return new self(
1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01,
2.68067772490389322e-03 * self::DAYS_PER_YEAR,
1.62824170038242295e-03 * self::DAYS_PER_YEAR,
-9.51592254519715870e-05 * self::DAYS_PER_YEAR,
5.15138902046611451e-05 * self::SOLAR_MASS
);
}
public static function sun(): self
{
return new self(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, self::SOLAR_MASS);
}
}
final class NBodySystem {
private array $bodies;
public function __construct(Body ...$bodies)
{
$px = 0.0;
$py = 0.0;
$pz = 0.0;
foreach ($bodies as $body) {
$px += $body->vx * $body->mass;
$py += $body->vy * $body->mass;
$pz += $body->vz * $body->mass;
}
$bodies[0]->offsetMomentum($px, $py, $pz);
$this->bodies = $bodies;
}
public function advance(float $dt): void
{
foreach ($this->bodies as $index => $referenceBody) {
$nbBodies = count($this->bodies);
for ($i = $index + 1; $i < $nbBodies; ++$i) {
$body = $this->bodies[$i];
$dx = $referenceBody->x - $body->x;
$dy = $referenceBody->y - $body->y;
$dz = $referenceBody->z - $body->z;
$distance² = $dx**2 + $dy**2 + $dz**2;
$distance = sqrt($distance²);
$magnitude = $dt / ($distance² * $distance);
$referenceBody->vx -= $dx * $body->mass * $magnitude;
$referenceBody->vy -= $dy * $body->mass * $magnitude;
$referenceBody->vz -= $dz * $body->mass * $magnitude;
$body->vx += $dx * $referenceBody->mass * $magnitude;
$body->vy += $dy * $referenceBody->mass * $magnitude;
$body->vz += $dz * $referenceBody->mass * $magnitude;
}
}
foreach ($this->bodies as $body) {
$body->x += $dt * $body->vx;
$body->y += $dt * $body->vy;
$body->z += $dt * $body->vz;
}
}
public function energy(): float
{
$e = 0.0;
foreach ($this->bodies as $index => $referenceBody) {
$e += 0.5 * $referenceBody->mass * (
$referenceBody->vx * $referenceBody->vx
+ $referenceBody->vy * $referenceBody->vy
+ $referenceBody->vz * $referenceBody->vz
);
$nbBodies = count($this->bodies);
for ($i = $index + 1; $i < $nbBodies; ++$i) {
$body = $this->bodies[$i];
$dx = $referenceBody->x - $body->x;
$dy = $referenceBody->y - $body->y;
$dz = $referenceBody->z - $body->z;
$distance = sqrt($dx**2 + $dy**2 + $dz**2);
$e -= ($referenceBody->mass * $body->mass) / $distance;
}
}
return $e;
}
}
$n = $argv[1];
$system = new NBodySystem(Body::sun(), Body::jupiter(), Body::saturn(), Body::uranus(), Body::neptune());
printf("%0.9f\n", $system->energy());
$start = hrtime(true);
for ($i = 0; $i < $n; ++$i) {
$system->advance(0.01);
}
printf("%0.9f\n", $system->energy());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment