floating-point-gui.de
floating-point-gui.de copied to clipboard
For PHP, real unit test scenario - can be added to docs ;)
Unit test file
<?php
declare(strict_types=1);
namespace Tests\Unit;
use App\Traits\FloatComparison;
use PHPUnit\Framework\TestCase;
class FloatComparisonTest extends TestCase
{
use FloatComparison;
public function testV1(): void
{
$toCheck = (float) '1714.23';
$items = [ // sum of that is 1714.23
73.03,
59.74,
90.03,
67.5,
33.07,
87.83,
73.03,
47.15,
66.12,
67.5,
49.56,
92.24,
47.65,
12.14,
50.77,
80.84,
49.56,
45.64,
73.03,
38.36,
97.21,
11.96,
37.86,
87.83,
5.02,
91.97,
90.03,
8.41,
33.07,
46.08,
];
$amount = 0;
foreach ($items as $item) {
$amount += $item;
}
self::assertTrue(self::nearlyEqual($toCheck, $amount));
}
}
Assertion file:
<?php
declare(strict_types=1);
namespace App\Traits;
trait FloatComparison
{
/**
* @link https://floating-point-gui.de/errors/comparison/
*
* @param float $a // 1714.23
* @param float $b // 1714.23
*
* @param float $epsilon // 2.2204460492503E-16
* @param float $floatMin // 2.2250738585072e-308
* @param floatMax // 1.7976931348623157E+308
*
* @return bool
*/
public static function nearlyEqual(float $a, float $b): bool
{
$absA = (float) abs($a); // 1714.23
$absB = (float) abs($b); // 1714.23
$diff = (float) abs($a - $b); // 2.2737367544323E-13
if ($a == $b) { // shortcut, handles infinities
return true;
}
if ($a == 0 || $b == 0 || ($absA + $absB < PHP_FLOAT_MIN)) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return $diff < (PHP_FLOAT_EPSILON * PHP_FLOAT_MIN);
}
// use relative error
return $diff / min(($absA + $absB), PHP_FLOAT_MAX) < PHP_FLOAT_MIN;
}
}