Skip to content

Commit

Permalink
added benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
uestla committed Oct 12, 2024
1 parent 6ba183f commit 89edac5
Show file tree
Hide file tree
Showing 3 changed files with 395 additions and 0 deletions.
183 changes: 183 additions & 0 deletions tests/benchmarks/fractions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?php

declare(strict_types = 1);

namespace Simplex\Tests\Benchmarks;

use function Simplex\Math\abs;
use function Simplex\Math\add;
use function Simplex\Math\div;
use function Simplex\Math\gcd;
use function Simplex\Math\mul;
use function Simplex\Math\sub;
use function Simplex\Math\isNegative;


trait FractionBase
{
public readonly string $n;
public readonly string $d;


public function add(self $a): self
{
return new self(
add(
mul($this->n, $a->d),
mul($this->d, $a->n),
),
mul($this->d, $a->d),
);
}


public function subtract(self $a): self
{
return new self(
sub(
mul($this->n, $a->d),
mul($this->d, $a->n),
),
mul($this->d, $a->d),
);
}


public function multiply(self|string $a): self
{
if (is_string($a)) {
return new self(
mul($a, $this->n),
$this->d,
);
}

return new self(
mul($this->n, $a->n),
mul($this->d, $a->d),
);
}


public function divide(self $a): self
{
return new self(
mul($this->n, $a->d),
mul($this->d, $a->n),
);
}


public function abs(): self
{
return new self(abs($this->n), $this->d);
}


public function canonicalize(): self
{
$gcd = gcd($this->n, $this->d);
$n = div($this->n, $gcd);
$d = div($this->d, $gcd);

if (isNegative($d)) {
$n = mul($n, '-1');
$d = mul($d, '-1');
}

return new self($n, $d);
}
}


final class FractionCanonicalized
{
use FractionBase;


public function __construct(string $n, string $d = '1')
{
if ($d === '0') {
throw new \RuntimeException('Division by zero.');
}

$gcd = gcd($n, $d);
$n = div($n, $gcd);
$d = div($d, $gcd);

if (isNegative($d)) {
$n = mul($n, '-1');
$d = mul($d, '-1');
}

$this->n = $n;
$this->d = $d;
}


public function isEqualTo(self|string $a): bool
{
if (is_string($a)) {
return $this->d === '1' && $this->n === $a;
}

return $this->n === $a->n && $this->d === $a->d;
}
}


final class FractionIsEqualMultiplication
{
use FractionBase;


public function __construct(string $n, string $d = '1')
{
if ($d === '0') {
throw new \RuntimeException('Division by zero.');
}

$this->n = $n;
$this->d = $d;
}


public function isEqualTo(self|string $a): bool
{
if (is_string($a)) {
return $this->n === mul($a, $this->d);
}

return mul($this->n, $a->d) === mul($a->n, $this->d);
}
}


final class FractionIsEqualCanonicalization
{
use FractionBase;


public function __construct(string $n, string $d = '1')
{
if ($d === '0') {
throw new \RuntimeException('Division by zero.');
}

$this->n = $n;
$this->d = $d;
}


public function isEqualTo(self|string $a): bool
{
$canThis = $this->canonicalize();

if (is_string($a)) {
return $canThis->d === '1' && $canThis->n === $a;
}

$canA = $a->canonicalize();
return $canThis->n === $canA->n && $canThis->d === $canA->d;
}
}
49 changes: 49 additions & 0 deletions tests/benchmarks/negations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types = 1);

namespace Simplex\Tests\Benchmarks;


final class NegateBC
{
public static function negate(string $n): string
{
return bcmul($n, '-1', 0);
}
}


final class NegateString
{
public static function negate(string $n): string
{
if ($n === '0') {
return '0';
}

if (strncmp($n, '-', 1) === 0) {
return substr($n, 1);
}

return '-' . $n;
}
}


function negateBC(string $n): string {
return bcmul($n, '-1', 0);
}


function negateString(string $n): string {
if ($n === '0') {
return '0';
}

if ($n[0] === '-') {
return substr($n, 1);
}

return '-' . $n;
}
163 changes: 163 additions & 0 deletions tests/benchmarks/run.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<?php

declare(strict_types = 1);

namespace Simplex\Tests\Benchmarks;


require_once __DIR__ . '/../../src/Simplex/Math/math.php';
require_once __DIR__ . '/negations.php';
require_once __DIR__ . '/fractions.php';


// =============================================================================
// === STRING MANIPULATION =====================================================
// =============================================================================

(static function (): void {

echo "\n";

echo '> String Manipulation Benchmarks', "\n\n";

$cases = [
'Remove "." - str_replace()' => static fn(string $n, int $dotPos): string => str_replace('.', '', $n),
'Remove "." - substr()' => static fn(string $n, int $dotPos): string => str_replace('.', '', $n),
];

$caseNo = 0;
$steps = 1e8;

foreach ($cases as $title => $callback) {
echo ' ', ++$caseNo, '. ', $title, '...';

$t = hrtime(true);

$n = '1234567890.0987654321';
for ($i = 0; $i < $steps; $i++) {
$res = $callback($n, 10);
}

assert(($res ?? '') === '12345678900987654321');

$t = hrtime(true) - $t;
echo ' ', $t / 1e9, 's', "\n";
}

})();


// =============================================================================
// === NEGATION ================================================================
// =============================================================================

(static function (): void {

echo "\n";

echo '> Negation Benchmarks', "\n\n";

$cases = [
'BCMath - class' => static fn(string $n): string => NegateBC::negate($n),
'BCMath - function' => static fn(string $n): string => negateBC($n),
'String manipulation - class' => static fn(string $n): string => NegateString::negate($n),
'String manipulation - function' => static fn(string $n): string => negateString($n),
'Manual negation' => static function (string $n): string {
if ($n === '0') {
return '0';

} elseif (strncmp($n, '-', 1) === 0) {
return substr($n, 1);
}

return '-' . $n;
},
];

$caseNo = 0;
$steps = 1e6 - 1;

foreach ($cases as $title => $callback) {
echo ' ', ++$caseNo, '. ', $title, '...';

$t = hrtime(true);

$n = '123456789';
for ($i = 0; $i < $steps; $i++) {
$n = $callback($n);
}

assert($n === '-123456789');

$t = hrtime(true) - $t;
echo ' ', $t / 1e9, 's', "\n";
}

echo "\n";

})();


// =============================================================================
// === FRACTION - IS EQUAL TO ==================================================
// =============================================================================

(static function (): void {

echo '> Fraction isEqualTo Benchmarks', "\n\n";

$cases = [
'Automatic canonicalization' => [
static fn(string $n, string $d = '1'): FractionCanonicalized => new FractionCanonicalized($n, $d),
static function (FractionCanonicalized $f): FractionCanonicalized { return $f; },
],

'Denominator multiplication' => [
static fn(string $n, string $d = '1'): FractionIsEqualMultiplication => new FractionIsEqualMultiplication($n, $d),
static function (FractionIsEqualMultiplication $f): FractionIsEqualMultiplication { return $f->canonicalize(); },
],

'Canonicalization inside isEqualTo()' => [
static fn(string $n, string $d = '1'): FractionIsEqualCanonicalization => new FractionIsEqualCanonicalization($n, $d),
static function (FractionIsEqualCanonicalization $f): FractionIsEqualCanonicalization { return $f->canonicalize(); },
],
];

$caseNo = 0;
$steps = 1e4;

foreach ($cases as $title => $case) {
echo ' ', ++$caseNo, '. ', $title, '...';

$t = hrtime(true);
[$factory, $canonicalization] = $case;

$f = $factory('9223372036854775807');

for ($i = 0; $i < $steps; $i++) {
$f = $f->multiply($factory('9223372036854775806', '2'))
->divide($factory('9223372036854775806', '2'))
->add($factory('9223372036854775806', '2'))
->subtract($factory('9223372036854775806', '2'));
}

$f = $f->subtract($factory('9223372036854775806'));

assert($f->isEqualTo($factory('9223372036854775807', '9223372036854775807')));
assert(!$f->isEqualTo($factory('9223372036854775808', '9223372036854775807')));

assert($f->isEqualTo($factory('1')));
assert(!$f->isEqualTo($factory('2')));

assert($f->isEqualTo('1'));
assert(!$f->isEqualTo('2'));

$f = $canonicalization($f);
assert($f->n === '1');
assert($f->d === '1');

$t = hrtime(true) - $t;
echo ' ', $t / 1e9, 's', "\n";
}

})();

0 comments on commit 89edac5

Please sign in to comment.