浮動小数点数の扱い
*********
.[perex]
[api:Nette\Utils\Floats] は、浮動小数点数を比較するための便利な関数を集めた静的クラスです。
インストール:
```shell
composer require nette/utils
```
以下の例では、次のクラスの別名が定義されているものとします。
```php
use Nette\Utils\Floats;
```
なぜ必要か
=====
浮動小数点数を比較するのになぜクラスが必要なのか、と思うかもしれません。`<`、`>`、`===` の演算子を使えば済むのでは、と。ところが、そう単純ではありません。次のコードは何を出力すると思いますか。
```php
$a = 0.1 + 0.2;
$b = 0.3;
echo $a === $b ? 'same' : 'not same';
```
実行してみると、プログラムが `not same` を出力することに驚く方もいるでしょう。
浮動小数点数の計算では、10 進表現と 2 進表現の変換のせいで精度の誤差が生じることがあります。たとえば `0.1 + 0.2` の結果は `0.300000000000000044…` のようになります。ですから浮動小数点数を比較するときは、わずかな差、すなわちイプシロンを許容する必要があります。
`Floats` クラスがまさにそれを行います。次の比較は期待どおりに働きます。
```php
echo Floats::areEqual($a, $b) ? 'same' : 'not same'; // same
```
`NAN` を比較しようとすると `\LogicException` を投げます。
.[tip]
`Floats` クラスはおよそ `1e-10` の相対精度で比較します。より高い精度が必要なら、代わりに BCMath ライブラリを検討してください。
浮動小数点数の比較
=========
areEqual(float $a, float $b): bool .[method]
--------------------------------------------
`$a` = `$b` なら `true` を返します。
```php
Floats::areEqual(10, 10.0); // true
```
isLessThan(float $a, float $b): bool .[method]
----------------------------------------------
`$a` < `$b` なら `true` を返します。
```php
Floats::isLessThan(9.5, 10.2); // true
Floats::isLessThan(INF, 10.2); // false
```
isLessThanOrEqualTo(float $a, float $b): bool .[method]
-------------------------------------------------------
`$a` <= `$b` なら `true` を返します。
```php
Floats::isLessThanOrEqualTo(9.5, 10.2); // true
Floats::isLessThanOrEqualTo(10.25, 10.25); // true
```
isGreaterThan(float $a, float $b): bool .[method]
-------------------------------------------------
`$a` > `$b` なら `true` を返します。
```php
Floats::isGreaterThan(9.5, -10.2); // true
Floats::isGreaterThan(9.5, 10.2); // false
```
isGreaterThanOrEqualTo(float $a, float $b): bool .[method]
----------------------------------------------------------
`$a` >= `$b` なら `true` を返します。
```php
Floats::isGreaterThanOrEqualTo(9.5, 10.2); // false
Floats::isGreaterThanOrEqualTo(10.2, 10.2); // true
```
compare(float $a, float $b): int .[method]
------------------------------------------
`$a` < `$b` なら `-1`、等しければ `0`、`$a` > `$b` なら `1` を返します。
たとえば `usort()` 関数と組み合わせて使えます。
```php
$arr = [1, 5, 2, -3.5];
usort($arr, [Floats::class, 'compare']);
// $arr は [-3.5, 1, 2, 5] になります
```
ヘルパー関数
======
isZero(float $value): bool .[method]
------------------------------------
値がゼロなら `true` を返します。
```php
Floats::isZero(0.0); // true
Floats::isZero(0); // true
```
isInteger(float $value): bool .[method]
---------------------------------------
値が整数なら `true` を返します。
```php
Floats::isInteger(0); // true
Floats::isInteger(0.0); // true
Floats::isInteger(-5.0); // true
Floats::isInteger(-5.1); // false
Floats::isInteger(INF); // false
Floats::isInteger(NAN); // false
```
浮動小数点数の扱い
Nette\Utils\Floats
は、浮動小数点数を比較するための便利な関数を集めた静的クラスです。
インストール:
composer require nette/utils
以下の例では、次のクラスの別名が定義されているものとします。
use Nette\Utils\Floats;
なぜ必要か
浮動小数点数を比較するのになぜクラスが必要なのか、と思うかもしれません。<、>、===
の演算子を使えば済むのでは、と。ところが、そう単純ではありません。次のコードは何を出力すると思いますか。
$a = 0.1 + 0.2;
$b = 0.3;
echo $a === $b ? 'same' : 'not same';
実行してみると、プログラムが not same を出力することに驚く方もいるでしょう。
浮動小数点数の計算では、10 進表現と 2
進表現の変換のせいで精度の誤差が生じることがあります。たとえば 0.1 + 0.2 の結果は
0.300000000000000044…
のようになります。ですから浮動小数点数を比較するときは、わずかな差、すなわちイプシロンを許容する必要があります。
Floats クラスがまさにそれを行います。次の比較は期待どおりに働きます。
echo Floats::areEqual($a, $b) ? 'same' : 'not same'; // same
NAN を比較しようとすると \LogicException を投げます。
Floats クラスはおよそ 1e-10
の相対精度で比較します。より高い精度が必要なら、代わりに BCMath
ライブラリを検討してください。
浮動小数点数の比較
areEqual (float $a, float $b): bool
$a = $b なら true を返します。
Floats::areEqual(10, 10.0); // true
isLessThan (float $a, float $b): bool
$a < $b なら true を返します。
Floats::isLessThan(9.5, 10.2); // true
Floats::isLessThan(INF, 10.2); // false
isLessThanOrEqualTo (float $a,
float $b): bool
$a <= $b なら true を返します。
Floats::isLessThanOrEqualTo(9.5, 10.2); // true
Floats::isLessThanOrEqualTo(10.25, 10.25); // true
isGreaterThan (float $a, float
$b): bool
$a > $b なら true を返します。
Floats::isGreaterThan(9.5, -10.2); // true
Floats::isGreaterThan(9.5, 10.2); // false
isGreaterThanOrEqualTo (float $a,
float $b): bool
$a >= $b なら true を返します。
Floats::isGreaterThanOrEqualTo(9.5, 10.2); // false
Floats::isGreaterThanOrEqualTo(10.2, 10.2); // true
compare (float $a, float $b): int
$a < $b なら -1、等しければ 0、$a >
$b なら 1 を返します。
たとえば usort() 関数と組み合わせて使えます。
$arr = [1, 5, 2, -3.5];
usort($arr, [Floats::class, 'compare']);
// $arr は [-3.5, 1, 2, 5] になります
ヘルパー関数
isZero (float $value): bool
値がゼロなら true を返します。
Floats::isZero(0.0); // true
Floats::isZero(0); // true
isInteger (float $value): bool
値が整数なら true を返します。
Floats::isInteger(0); // true
Floats::isInteger(0.0); // true
Floats::isInteger(-5.0); // true
Floats::isInteger(-5.1); // false
Floats::isInteger(INF); // false
Floats::isInteger(NAN); // false