Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Nette\Utils\Floats class for comparing floats (#221)
- Loading branch information
Showing
9 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of the Nette Framework (https://nette.org) | ||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com) | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Nette\Utils; | ||
|
||
use Nette; | ||
|
||
|
||
/** | ||
* Floats compare tools library. | ||
*/ | ||
class Floats | ||
{ | ||
use Nette\StaticClass; | ||
|
||
/** @var float */ | ||
private const EPSILON = 1e-10; | ||
|
||
|
||
public static function isZero(float $value): bool | ||
{ | ||
return abs($value) < self::EPSILON; | ||
} | ||
|
||
|
||
public static function isInteger(float $value): bool | ||
{ | ||
return abs(round($value) - $value) < self::EPSILON; | ||
} | ||
|
||
|
||
/** | ||
* Compare two floats. If $a < $b it returns -1, if they are equal it returns 0 and if $a > $b it returns 1 | ||
* @throws \LogicException if one of parameters is NAN | ||
*/ | ||
public static function compare(float $a, float $b): int | ||
{ | ||
if (is_nan($a) || is_nan($b)) { | ||
throw new \LogicException('Trying to compare NAN'); | ||
|
||
} elseif (!is_finite($a) && !is_finite($b) && $a === $b) { | ||
return 0; | ||
|
||
} else { | ||
$diff = abs($a - $b); | ||
if (($diff < self::EPSILON || ($diff / max(abs($a), abs($b)) < self::EPSILON))) { | ||
return 0; | ||
} | ||
} | ||
|
||
return $a < $b ? -1 : 1; | ||
} | ||
|
||
|
||
/** | ||
* Returns true if $a = $b | ||
* @throws \LogicException if one or both parameters are NAN | ||
*/ | ||
public static function areEqual(float $a, float $b): bool | ||
{ | ||
return self::compare($a, $b) === 0; | ||
} | ||
|
||
|
||
/** | ||
* Returns true if $a < $b | ||
* @throws \LogicException if one or both parameters are NAN | ||
*/ | ||
public static function isLessThan(float $a, float $b): bool | ||
{ | ||
return self::compare($a, $b) < 0; | ||
} | ||
|
||
|
||
/** | ||
* Returns true if $a <= $b | ||
* @throws \LogicException if one or both parameters are NAN | ||
*/ | ||
public static function isLessThanOrEqualTo(float $a, float $b): bool | ||
{ | ||
return self::compare($a, $b) <= 0; | ||
} | ||
|
||
|
||
/** | ||
* Returns true if $a > $b | ||
* @throws \LogicException if one or both parameters are NAN | ||
*/ | ||
public static function isGreaterThan(float $a, float $b): bool | ||
{ | ||
return self::compare($a, $b) > 0; | ||
} | ||
|
||
|
||
/** | ||
* Returns true if $a >= $b | ||
* @throws \LogicException if one or both parameters are NAN | ||
*/ | ||
public static function isGreaterThanOrEqualTo(float $a, float $b): bool | ||
{ | ||
return self::compare($a, $b) >= 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::areEqual() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::true(Floats::areEqual(9, 9)); | ||
Assert::true(Floats::areEqual(9, 9.0)); | ||
Assert::true(Floats::areEqual(3.0, 3)); | ||
Assert::true(Floats::areEqual(0.0, 0)); | ||
Assert::true(Floats::areEqual(0.0, 0.0)); | ||
Assert::true(Floats::areEqual(0.1 + 0.2, 0.3)); | ||
Assert::true(Floats::areEqual(0.1 - 0.5, -0.4)); | ||
Assert::false(Floats::areEqual(0.0, 5)); | ||
Assert::false(Floats::areEqual(-5, 5)); | ||
Assert::false(Floats::areEqual(0.001, 0.01)); | ||
|
||
$float1 = 1 / 3; | ||
$float2 = 1 - 2 / 3; | ||
Assert::true(Floats::areEqual($float1, $float2)); | ||
Assert::true(Floats::areEqual($float1 * 1e9, $float2 * 1e9)); | ||
Assert::true(Floats::areEqual($float1 - $float2, 0.0)); | ||
Assert::true(Floats::areEqual($float1 - $float2 + 123, $float2 - $float1 + 123)); | ||
Assert::true(Floats::areEqual($float1 - $float2, $float2 - $float1)); | ||
|
||
Assert::true(Floats::areEqual(INF, INF)); | ||
Assert::false(Floats::areEqual(INF, -INF)); | ||
Assert::false(Floats::areEqual(-INF, INF)); | ||
|
||
Assert::exception(function () { | ||
Floats::areEqual(NAN, NAN); | ||
}, \LogicException::class); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::compare() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::same(0, Floats::compare(0, 0)); | ||
Assert::same(0, Floats::compare(0.0, 0)); | ||
Assert::same(0, Floats::compare(0, 0x0)); | ||
Assert::same(1, Floats::compare(0, -25.7)); | ||
Assert::same(-1, Floats::compare(-2, 30.7)); | ||
Assert::same(1, Floats::compare(0.0, -5)); | ||
Assert::same(1, Floats::compare(20, 10)); | ||
Assert::same(-1, Floats::compare(20, 30)); | ||
Assert::same(1, Floats::compare(-20, -30)); | ||
Assert::same(-1, Floats::compare(-50, -30)); | ||
|
||
Assert::exception(function () { | ||
Floats::compare(NAN, -30); | ||
}, \LogicException::class); | ||
|
||
Assert::exception(function () { | ||
Floats::compare(6, NAN); | ||
}, \LogicException::class); | ||
|
||
Assert::exception(function () { | ||
Floats::compare(NAN, NAN); | ||
}, \LogicException::class); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::isGreaterThan() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::false(Floats::isGreaterThan(-9, 9)); | ||
Assert::false(Floats::isGreaterThan(-9.7, 0.0)); | ||
Assert::false(Floats::isGreaterThan(10, 150)); | ||
Assert::false(Floats::isGreaterThan(0, 0.0)); | ||
Assert::false(Floats::isGreaterThan(10, 10)); | ||
Assert::false(Floats::isGreaterThan(-50, -50)); | ||
Assert::true(Floats::isGreaterThan(170, 150)); | ||
Assert::true(Floats::isGreaterThan(170.879, -20)); | ||
Assert::true(Floats::isGreaterThan(11.879, 0.0)); | ||
|
||
Assert::true(Floats::isGreaterThan(INF, -INF)); | ||
Assert::false(Floats::isGreaterThan(INF, INF)); | ||
Assert::false(Floats::isGreaterThan(-INF, INF)); | ||
|
||
Assert::exception(function () { | ||
Floats::isGreaterThan(NAN, NAN); | ||
}, \LogicException::class); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::isGreaterOrEqualThan() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::false(Floats::isGreaterThanOrEqualTo(-9, 9)); | ||
Assert::false(Floats::isGreaterThanOrEqualTo(-9.7, 0.0)); | ||
Assert::false(Floats::isGreaterThanOrEqualTo(10, 150)); | ||
Assert::true(Floats::isGreaterThanOrEqualTo(0, 0.0)); | ||
Assert::true(Floats::isGreaterThanOrEqualTo(10, 10)); | ||
Assert::true(Floats::isGreaterThanOrEqualTo(-50, -50)); | ||
Assert::true(Floats::isGreaterThanOrEqualTo(170, 150)); | ||
Assert::true(Floats::isGreaterThanOrEqualTo(170.879, -20)); | ||
Assert::true(Floats::isGreaterThanOrEqualTo(11.879, 0.0)); | ||
|
||
Assert::true(Floats::isGreaterThanOrEqualTo(INF, INF)); | ||
Assert::true(Floats::isGreaterThanOrEqualTo(INF, -INF)); | ||
Assert::false(Floats::isGreaterThanOrEqualTo(-INF, INF)); | ||
|
||
Assert::exception(function () { | ||
Floats::isGreaterThanOrEqualTo(NAN, NAN); | ||
}, \LogicException::class); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::isInteger() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::true(Floats::isInteger(0)); | ||
Assert::true(Floats::isInteger(0.0)); | ||
Assert::true(Floats::isInteger(5.0)); | ||
Assert::true(Floats::isInteger(-5.0)); | ||
Assert::true(Floats::isInteger(-5)); | ||
Assert::true(Floats::isInteger((1 - (0.1 + 0.2)) * 10)); | ||
Assert::false(Floats::isInteger(-5.1)); | ||
Assert::false(Floats::isInteger(0.000001)); | ||
Assert::false(Floats::isInteger(NAN)); | ||
Assert::false(Floats::isInteger(INF)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::isLowerThan() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::true(Floats::isLessThan(-9, 9)); | ||
Assert::true(Floats::isLessThan(-9.7, 0.0)); | ||
Assert::true(Floats::isLessThan(10, 150)); | ||
Assert::false(Floats::isLessThan(0, 0.0)); | ||
Assert::false(Floats::isLessThan(10, 10)); | ||
Assert::false(Floats::isLessThan(-50, -50)); | ||
Assert::false(Floats::isLessThan(170, 150)); | ||
Assert::false(Floats::isLessThan(170.879, -20)); | ||
Assert::false(Floats::isLessThan(11.879, 0.0)); | ||
|
||
Assert::true(Floats::isLessThan(-INF, INF)); | ||
Assert::false(Floats::isLessThan(INF, INF)); | ||
Assert::false(Floats::isLessThan(INF, -INF)); | ||
|
||
Assert::exception(function () { | ||
Floats::isLessThan(NAN, NAN); | ||
}, \LogicException::class); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::isLowerOrEqualThan() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::true(Floats::isLessThanOrEqualTo(-9, 9)); | ||
Assert::true(Floats::isLessThanOrEqualTo(-9.7, 0.0)); | ||
Assert::true(Floats::isLessThanOrEqualTo(10, 150)); | ||
Assert::true(Floats::isLessThanOrEqualTo(0, 0.0)); | ||
Assert::true(Floats::isLessThanOrEqualTo(10, 10)); | ||
Assert::true(Floats::isLessThanOrEqualTo(-50, -50)); | ||
Assert::false(Floats::isLessThanOrEqualTo(170, 150)); | ||
Assert::false(Floats::isLessThanOrEqualTo(170.879, -20)); | ||
Assert::false(Floats::isLessThanOrEqualTo(11.879, 0.0)); | ||
|
||
Assert::true(Floats::isLessThanOrEqualTo(-INF, INF)); | ||
Assert::true(Floats::isLessThanOrEqualTo(INF, INF)); | ||
Assert::false(Floats::isLessThanOrEqualTo(INF, -INF)); | ||
|
||
Assert::exception(function () { | ||
Floats::isLessThanOrEqualTo(NAN, NAN); | ||
}, \LogicException::class); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
/** | ||
* Test: Nette\Utils\Floats::isZero() | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Nette\Utils\Floats; | ||
use Tester\Assert; | ||
|
||
|
||
require __DIR__ . '/../bootstrap.php'; | ||
|
||
|
||
Assert::true(Floats::isZero(0)); | ||
Assert::true(Floats::isZero(0.0)); | ||
Assert::true(Floats::isZero(0x0)); | ||
Assert::false(Floats::isZero(-12.5)); | ||
Assert::false(Floats::isZero(0.2)); | ||
Assert::false(Floats::isZero(20)); | ||
Assert::false(Floats::isZero(-2)); | ||
Assert::false(Floats::isZero(0x5)); | ||
Assert::false(Floats::isZero(INF)); | ||
Assert::false(Floats::isZero(NAN)); |