Skip to content

Instantly share code, notes, and snippets.

@olleharstedt
Created January 22, 2023 23:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olleharstedt/07f0172423d167d97d813c954507ac22 to your computer and use it in GitHub Desktop.
Save olleharstedt/07f0172423d167d97d813c954507ac22 to your computer and use it in GitHub Desktop.
PHP+C polyglot nbody benchmark
//<?php echo "\x08\x08"; ob_start(); ?>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <glib.h>
#include <math.h>
#include <phollylib.c>
#if __PHP__//<?php
class GString { public $str; public function __construct($str) { $this->str = $str; } }
function g_string_new(string $str) { return new GString($str); }
function g_string_append(GString $s1, string $s2) { return new GString($s1->str . $s2); }
define("int", "int");
define("float", "float");
define("string", "string");
function array_get($type, $arr, $i) { return $arr[$i]; }
function array_make($type, $length, ...$values) { return $values; }
function pprintf($format, ...$args) { fwrite( STDOUT, sprintf( $format, ...$args)); }
#endif//?>
//<?php
#__C__ typedef struct Body* Body;
class Body {
#define public float
#define __prop_x $__prop_x
public $__prop_x;
#undef public
#define public float
#define __prop_y $__prop_y
public $__prop_y;
#undef public
#define public float
#define __prop_z $__prop_z
public $__prop_z;
#undef public
#define public float
#define __prop_vx $__prop_vx
public $__prop_vx;
#undef public
#define public float
#define __prop_vy $__prop_vy
public $__prop_vy;
#undef public
#define public float
#define __prop_vz $__prop_vz
public $__prop_vz;
#undef public
#define public float
#define __prop_mass $__prop_mass
public $__prop_mass;
#undef public
#__C__ void (*offsetMomentum) (Body $__self, float $px, float $py, float $pz);
// End of C struct def. Class methods are outside the struct.
#__C__ };
#__C__ void Body__offsetMomentum (Body $__self, float $px, float $py, float $pz)
#if __PHP__
public function offsetMomentum(Body $__self, float $px, float $py, float $pz): void
#endif
{
#__C__ float
$pi = 3.1415926535897931;
#__C__ float
$solarmass = 4. * $pi * $pi;
$__self->__prop_vx = (0. - $px) / $solarmass;
$__self->__prop_vy = (0. - $py) / $solarmass;
$__self->__prop_vz = (0. - $pz) / $solarmass;
}
#if __PHP__
// End of PHP class def.
};
#endif
#if __PHP__
define("Body", "Body");
#endif
//?>
// Function pointer init
Body Body__constructor(Body $p)
{
$p->offsetMomentum = &Body__offsetMomentum;
return $p;
}
//<?php
#__C__ void advance(array $bodies, float $dt)
#if __PHP__
function advance(array &$bodies, float $dt): void
#endif
{
#__C__ int
$i = 0;
for (; $i < count($bodies); $i = $i + 1) {
#__C__ Body
$body = array_get(Body, $bodies, $i);
#__C__ array
$slice = array_slice($bodies, $i + 1);
#__C__ int
$__i = 0;
for (; $__i < count($slice); $__i = $__i + 1) {
#__C__ Body
$body2 = array_get(Body, $slice, $__i);
#__C__ float
$dx = $body->__prop_x - $body2->__prop_x;
#__C__ float
$dy = $body->__prop_y - $body2->__prop_y;
#__C__ float
$dz = $body->__prop_z - $body2->__prop_z;
#__C__ float
$distance = sqrt($dx * $dx + $dy * $dy + $dz * $dz);
#__C__ float
$mag = $dt / ($distance * $distance * $distance);
$body->__prop_vx = $body->__prop_vx - $dx * $body2->__prop_mass * $mag;
$body->__prop_vy = $body->__prop_vy - $dy * $body2->__prop_mass * $mag;
$body->__prop_vz = $body->__prop_vz - $dz * $body2->__prop_mass * $mag;
$body2->__prop_vx = $body2->__prop_vx + $dx * $body->__prop_mass * $mag;
$body2->__prop_vy = $body2->__prop_vy + $dy * $body->__prop_mass * $mag;
$body2->__prop_vz = $body2->__prop_vz + $dz * $body->__prop_mass * $mag;
}
}
#__C__ int
$__i = 0;
for (; $__i < count($bodies); $__i = $__i + 1) {
#__C__ Body
$body3 = array_get(Body, $bodies, $__i);
$body3->__prop_x = $body3->__prop_x + $dt * $body3->__prop_vx;
$body3->__prop_y = $body3->__prop_y + $dt * $body3->__prop_vy;
$body3->__prop_z = $body3->__prop_z + $dt * $body3->__prop_vz;
}
}
#__C__ float energy(array $bodies)
#if __PHP__
function energy(array &$bodies): float
#endif
{
#__C__ float
$e = 0.;
#__C__ int
$i = 0;
for (; $i < count($bodies); $i = $i + 1) {
#__C__ Body
$body = array_get(Body, $bodies, $i);
#__C__ float
$tmp2 = $body->__prop_vx * $body->__prop_vx + $body->__prop_vy * $body->__prop_vy + $body->__prop_vz * $body->__prop_vz;
$e += 0.5 * $body->__prop_mass * $tmp2;
#__C__ array
$slice = array_slice($bodies, $i + 1);
#__C__ int
$__i = 0;
for (; $__i < count($slice); $__i = $__i + 1) {
#__C__ Body
$body2 = array_get(Body, $slice, $__i);
#__C__ float
$dx = $body->__prop_x - $body2->__prop_x;
#__C__ float
$dy = $body->__prop_y - $body2->__prop_y;
#__C__ float
$dz = $body->__prop_z - $body2->__prop_z;
#__C__ float
$distance = sqrt($dx * $dx + $dy * $dy + $dz * $dz);
$e -= ($body->__prop_mass * $body2->__prop_mass) / $distance;
}
}
return $e;
}
#define function int
function main()
#undef function
{
#__C__ float
$daysperyear = 365.24;
#__C__ float
$pi = 3.1415926535897931;
#__C__ float
$solarmass = 4. * $pi * $pi;
#__C__ Body
$jupiter = new(Body);
$jupiter->__prop_x = 4.8414314424647209;
$jupiter->__prop_y = -1.1603200440274284;
$jupiter->__prop_z = -0.10362204447112311;
$jupiter->__prop_vx = 0.0016600766427440369 * $daysperyear;
$jupiter->__prop_vy = 0.0076990111841974043 * $daysperyear;
$jupiter->__prop_vz = -6.90460016972063e-05 * $daysperyear;
$jupiter->__prop_mass = 0.00095479193842432661 * $solarmass;
#__C__ Body
$saturn = new(Body);
$saturn->__prop_x = 8.34336671824458;
$saturn->__prop_y = 4.1247985641243048;
$saturn->__prop_z = -0.40352341711432138;
$saturn->__prop_vx = -0.0027674251072686241 * $daysperyear;
$saturn->__prop_vy = 0.0049985280123491724 * $daysperyear;
$saturn->__prop_vz = 2.3041729757376393e-05 * $daysperyear;
$saturn->__prop_mass = 0.00028588598066613081 * $solarmass;
#__C__ Body
$uranus = new(Body);
$uranus->__prop_x = 12.894369562139131;
$uranus->__prop_y = -15.111151401698631;
$uranus->__prop_z = -0.22330757889265573;
$uranus->__prop_vx = 0.0029646013756476162 * $daysperyear;
$uranus->__prop_vy = 0.0023784717395948095 * $daysperyear;
$uranus->__prop_vz = -2.9658956854023756e-05 * $daysperyear;
$uranus->__prop_mass = 4.366244043351563e-05 * $solarmass;
#__C__ Body
$neptune = new(Body);
$neptune->__prop_x = 15.379697114850917;
$neptune->__prop_y = -25.919314609987964;
$neptune->__prop_z = 0.17925877295037118;
$neptune->__prop_vx = 0.0026806777249038932 * $daysperyear;
$neptune->__prop_vy = 0.001628241700382423 * $daysperyear;
$neptune->__prop_vz = -9.5159225451971587e-05 * $daysperyear;
$neptune->__prop_mass = 5.1513890204661145e-05 * $solarmass;
#__C__ Body
$sun = new(Body);
$sun->__prop_x = 0.;
$sun->__prop_y = 0.;
$sun->__prop_z = 0.;
$sun->__prop_vx = 0.;
$sun->__prop_vy = 0.;
$sun->__prop_vz = 0.;
$sun->__prop_mass = $solarmass;
#__C__ array
$bodies = array_make(Body, 5, $sun, $jupiter, $saturn, $uranus, $neptune);
#__C__ float
$px = 0.;
#__C__ float
$py = 0.;
#__C__ float
$pz = 0.;
#__C__ int
$__i = 0;
for (; $__i < count($bodies); $__i = $__i + 1) {
#__C__ Body
$body2 = array_get(Body, $bodies, $__i);
$px += $body2->__prop_vx * $body2->__prop_mass;
$py += $body2->__prop_vy * $body2->__prop_mass;
$pz += $body2->__prop_vz * $body2->__prop_mass;
}
#__C__ Body
$b = array_get(Body, $bodies, 0);
$b->offsetMomentum($b, $px, $py, $pz);
#__C__ float
$e = energy($bodies);
printf("%f\n", $e);
#__C__ int
$k = 0;
do {
advance($bodies, 0.01);
$k++;
} while ($k < 500000);
#__C__ float
$e2 = energy($bodies);
printf("%f\n", $e2);
return 0;
}
// ?>
// <?php ob_end_clean(); main();
@olleharstedt
Copy link
Author

I use the following commands in my Makefile:

  sed -e "s/#__C__ //g" noby.c > _nbody.c
  gcc -O3 -Wno-incompatible-pointer-types _nbody.c -I. -lm

But you'd also need the phollylib.c from here: https://github.com/olleharstedt/pholyglot/blob/main/pholly/phollylib.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment