nbody-php-3 算法

pull/1/head
韩天峰 8 months ago
parent 5f1fe2e2a4
commit ec836bcb31
  1. 4
      bin/compiler.php
  2. 122
      examples/nbody.php-3.php
  3. 63
      src/Php/Translator.php

@ -44,6 +44,10 @@ foreach ($list as $file) {
}
}
if (empty($sourceFiles)) {
$translator->stop("No valid source file found");
}
// 生成所有函数声明
$translator->genFunctionDeclaration("./php_func_decl.h");

@ -0,0 +1,122 @@
<?php
/* The Computer Language Benchmarks Game
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
contributed by anon
modified by Sergey Khripunov
*/
function energy(&$b)
{
$e = 0.0;
for ($i = 0, $m = sizeof($b); $i < $m; $i++) {
$b1 = $b[$i];
$e += 0.5 * $b1[6] * ($b1[3] * $b1[3] + $b1[4] * $b1[4] + $b1[5] * $b1[5]);
for ($j = $i + 1; $j < $m; $j++) {
$b2 = $b[$j];
$dx = $b1[0] - $b2[0];
$dy = $b1[1] - $b2[1];
$dz = $b1[2] - $b2[2];
$e -= ($b1[6] * $b2[6]) / sqrt($dx * $dx + $dy * $dy + $dz * $dz);
}
}
return $e;
}
function main()
{
$begin = microtime(true);
$pi = 3.141592653589793;
$solar_mass = 4 * $pi * $pi;
$days_per_year = 365.24;
$bodies = array(array(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, $solar_mass), //Sun
array(4.84143144246472090E+00, // Jupiter
-1.16032004402742839E+00,
-1.03622044471123109E-01,
1.66007664274403694E-03 * $days_per_year,
7.69901118419740425E-03 * $days_per_year,
-6.90460016972063023E-05 * $days_per_year,
9.54791938424326609E-04 * $solar_mass),
array(8.34336671824457987E+00, // Saturn
4.12479856412430479E+00,
-4.03523417114321381E-01,
-2.76742510726862411E-03 * $days_per_year,
4.99852801234917238E-03 * $days_per_year,
2.30417297573763929E-05 * $days_per_year,
2.85885980666130812E-04 * $solar_mass),
array(1.28943695621391310E+01, // Uranus
-1.51111514016986312E+01,
-2.23307578892655734E-01,
2.96460137564761618E-03 * $days_per_year,
2.37847173959480950E-03 * $days_per_year,
-2.96589568540237556E-05 * $days_per_year,
4.36624404335156298E-05 * $solar_mass),
array(1.53796971148509165E+01, // Neptune
-2.59193146099879641E+01,
1.79258772950371181E-01,
2.68067772490389322E-03 * $days_per_year,
1.62824170038242295E-03 * $days_per_year,
-9.51592254519715870E-05 * $days_per_year,
5.15138902046611451E-05 * $solar_mass));
// offset_momentum
$px = $py = $pz = 0.0;
foreach ($bodies as $e) {
$px += $e[3] * $e[6];
$py += $e[4] * $e[6];
$pz += $e[5] * $e[6];
}
$bodies[0][3] = -$px / $solar_mass;
$bodies[0][4] = -$py / $solar_mass;
$bodies[0][5] = -$pz / $solar_mass;
$pairs = array();
for ($i = 0, $m = count($bodies); $i < $m; $i++)
for ($j = $i + 1; $j < $m; $j++)
$pairs[] = array(&$bodies[$i], &$bodies[$j]);
global $argc, $argv;
$n = $argc > 2 ? $argv[2] : 100;
printf("%0.9f\n", energy($bodies));
$i = 0;
do {
foreach ($pairs as $k => $p) {
$a = $p[0];
$b = $p[1];
$dx = $a[0] - $b[0];
$dy = $a[1] - $b[1];
$dz = $a[2] - $b[2];
$dist = sqrt($dx * $dx + $dy * $dy + $dz * $dz);
$mag = 0.01 / ($dist * $dist * $dist);
$mag_a = $a[6] * $mag;
$mag_b = $b[6] * $mag;
$a[3] -= $dx * $mag_b;
$a[4] -= $dy * $mag_b;
$a[5] -= $dz * $mag_b;
$b[3] += $dx * $mag_a;
$b[4] += $dy * $mag_a;
$b[5] += $dz * $mag_a;
$pairs[$k][0] = $a;
$pairs[$k][1] = $b;
}
foreach ($bodies as $k => $b) {
$b[0] += 0.01 * $b[3];
$b[1] += 0.01 * $b[4];
$b[2] += 0.01 * $b[5];
$bodies[$k] = $b;
}
} while (++$i < $n);
printf("%0.9f\n", energy($bodies));
printf("count=%d, %0.9f\n", $n, microtime(true) - $begin);
}

@ -1299,7 +1299,7 @@ class Translator extends \PhpAot\Core\Translator
} else {
$fn = '"' . $name . '"';
}
if ($name === 'strlen') {
if ($name === 'strlen' or $name === 'sizeof' or $name === 'count') {
return 'php::len(' . $this->parseIdentifier($expr->args[0]->value) . ')';
}
if (count($expr->args) == 1) {
@ -1506,9 +1506,40 @@ class Translator extends \PhpAot\Core\Translator
return $code;
}
function isClosedCall($expr, $call): bool
{
if ($call === '') {
if (!str_starts_with($expr, '(')) {
return false;
}
$startPos = 0;
} else {
if (!str_starts_with($expr, $call . '(')) {
return false;
}
$startPos = strlen($call);
}
$bracketCount = 0;
$length = strlen($expr);
for ($i = $startPos; $i < $length; $i++) {
$char = $expr[$i];
if ($char === '(') {
$bracketCount++;
} elseif ($char === ')') {
$bracketCount--;
if ($bracketCount === 0) {
return $i === $length - 1;
}
}
}
return false;
}
private function trimBrackets(string $str): string
{
if (str_starts_with($str, '(') and str_ends_with($str, ')')) {
if ($this->isClosedCall($str, '')) {
return substr($str, 1, -1);
}
return $str;
@ -1516,7 +1547,7 @@ class Translator extends \PhpAot\Core\Translator
private function convertIntExpr(string $expr): string
{
if (!str_starts_with($expr, 'php::to_int(')) {
if (!$this->isClosedCall($expr, 'php::to_int')) {
return 'php::to_int(' . $this->trimBrackets($expr) . ')';
}
return $expr;
@ -1524,15 +1555,21 @@ class Translator extends \PhpAot\Core\Translator
private function convertFloatExpr(string $expr): string
{
if (!str_starts_with($expr, 'php::to_float(')) {
if (!$this->isClosedCall($expr, 'php::to_float')) {
return 'php::to_float(' . $this->trimBrackets($expr) . ')';
}
return $expr;
}
public function stop(string $string): void
{
$this->climate->red($string . "\n");
exit(1);
}
private function convertStringExpr(string $expr): string
{
if (!str_starts_with($expr, 'php::to_string(')) {
if (!$this->isClosedCall($expr, 'php::to_string')) {
return 'php::to_string(' . $this->trimBrackets($expr) . ')';
}
return $expr;
@ -1540,7 +1577,7 @@ class Translator extends \PhpAot\Core\Translator
private function convertArrayExpr(string $expr): string
{
if (!str_starts_with($expr, 'php::to_array(')) {
if (!$this->isClosedCall($expr, 'php::to_array')) {
return 'php::to_array(' . $this->trimBrackets($expr) . ')';
}
return $expr;
@ -1548,7 +1585,7 @@ class Translator extends \PhpAot\Core\Translator
private function convertBoolExpr(string $expr): string
{
if (!str_starts_with($expr, 'php::to_bool(')) {
if (!$this->isClosedCall($expr, 'php::to_bool')) {
return 'php::to_bool(' . $this->trimBrackets($expr) . ')';
}
return $expr;
@ -1837,6 +1874,9 @@ class Translator extends \PhpAot\Core\Translator
private function parseForeach(Node $node): string
{
if ($node->byRef) {
$this->fatalError($node, 'Cannot use & with foreach');
}
if ($node->keyVar) {
$keyVar = $this->parseIdentifier($node->keyVar);
}
@ -2169,10 +2209,13 @@ class Translator extends \PhpAot\Core\Translator
private function parseAssignRef(mixed $expr)
{
if ($expr->var->getType() === self::EXPR_VARIABLE && $expr->expr->getType() === self::EXPR_VARIABLE) {
return $this->parseIdentifier($expr->var) . ' = &' . $this->parseIdentifier($expr->expr);
if ($expr->var->getType() === self::EXPR_VARIABLE) {
if ($expr->expr->getType() === self::EXPR_VARIABLE) {
return $this->parseIdentifier($expr->var) . ' = &' . $this->parseIdentifier($expr->expr);
} elseif ($expr->expr->getType() === self::EXPR_ARRAY_DIM_FETCH) {
return $this->parseIdentifier($expr->var) . ' = ' . $this->parseIdentifier($expr->expr);
}
}
abort($expr);
}
private function parseMethodCall(mixed $expr): string

Loading…
Cancel
Save