【PHP8.x】PHP_FLOAT_EPSILON定数の使い方
PHP_FLOAT_EPSILON定数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
PHP_FLOAT_EPSILON定数は、浮動小数点数同士の比較において、2つの値が『ほぼ等しい』と見なせる最小の差を表す定数です。
コンピュータは浮動小数点数を厳密に表現できないため、計算には微小な誤差が伴うことがあります。このため、float型を==演算子で比較すると、見た目上同じ値でも誤差により異なるものと判断され、誤った結果を生むことがあります。
この定数は、浮動小数点数演算の誤差を考慮した等価性判定の基準として使用されます。具体的には、2つの浮動小数点数aとbを比較する際、abs(a - b) < PHP_FLOAT_EPSILONという条件式を用いることで、誤差を許容し、信頼性の高い判定が可能です。
PHP 8で導入されたこの定数は、システムが扱う浮動小数点数の精度に基づいて自動的に設定されます。数値計算の信頼性を高める上で、この定数の理解と活用はシステムエンジニアにとって非常に重要であり、アプリケーションの堅牢性向上に寄与します。
構文(syntax)
1<?php 2echo PHP_FLOAT_EPSILON; 3?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
float
PHP_FLOAT_EPSILONは、浮動小数点数の比較において、実質的に等しいとみなせる最小の差を表す定数です。その値はfloat型です。
サンプルコード
PHP_FLOAT_EPSILON で浮動小数点数を比較する
1<?php 2 3/** 4 * PHP_FLOAT_EPSILON 定数の値と、それを使った浮動小数点数の比較方法を示します。 5 * 6 * PHP_FLOAT_EPSILON は、浮動小数点数の比較において誤差を考慮するために使用される 7 * 非常に小さい正の数です。浮動小数点数は内部的な表現の制約により、 8 * `0.1 + 0.2 == 0.3` のような単純な比較が期待通りに動作しない場合があります。 9 * この定数を利用して、2つの浮動小数点数が「ほぼ等しい」かを判断します。 10 */ 11function demonstrateFloatComparisonWithEpsilon(): void 12{ 13 // PHP_FLOAT_EPSILON の値を表示 14 echo "PHP_FLOAT_EPSILON の値: " . PHP_FLOAT_EPSILON . "\n\n"; 15 16 // 浮動小数点数の計算例 17 $a = 0.1 + 0.2; 18 $b = 0.3; 19 20 echo "変数 \$a (0.1 + 0.2 の結果): " . $a . "\n"; 21 echo "変数 \$b (0.3 の値): " . $b . "\n\n"; 22 23 // 直接比較の試み (多くの場合、期待通りの結果にならない) 24 if ($a == $b) { 25 echo "直接比較: \$a と \$b は等しいと判断されました。\n"; 26 } else { 27 echo "直接比較: \$a と \$b は等しくないと判断されました。(浮動小数点数の誤差が原因)\n"; 28 } 29 echo "\n"; 30 31 // PHP_FLOAT_EPSILON を使った近似比較 32 // 2つの数の差の絶対値が PHP_FLOAT_EPSILON より小さければ、それらは近似的に等しいとみなします。 33 // 必要に応じて、PHP_FLOAT_EPSILON よりも大きな許容誤差 (tolerance) を設定することもできます。 34 $tolerance = PHP_FLOAT_EPSILON; 35 36 if (abs($a - $b) < $tolerance) { 37 echo "近似比較: \$a と \$b は PHP_FLOAT_EPSILON を使って、近似的に等しいと判断されました。\n"; 38 } else { 39 echo "近似比較: \$a と \$b は PHP_FLOAT_EPSILON を使っても、等しくないと判断されました。\n"; 40 } 41} 42 43// 関数を実行して結果を確認 44demonstrateFloatComparisonWithEpsilon();
PHPの定数PHP_FLOAT_EPSILONは、非常に小さい正の浮動小数点数を表します。この定数は、主に浮動小数点数の比較において発生する誤差を考慮するために使用されます。浮動小数点数は、コンピュータ内部での表現の制約上、例えば0.1 + 0.2が厳密に0.3と等しくならないことがあります。そのため、==演算子を使った直接比較では、期待通りに「等しい」と判断されない場合があります。
PHP_FLOAT_EPSILONの型はfloatです。この定数自体は引数を取りません。サンプルコードでは、まずPHP_FLOAT_EPSILONの具体的な値を出力しています。次に、0.1 + 0.2の結果と0.3を直接比較した場合と、PHP_FLOAT_EPSILONを用いた近似比較の場合を比較しています。近似比較では、2つの浮動小数点数の差の絶対値がPHP_FLOAT_EPSILONよりも小さい場合に、それらを「ほぼ等しい」と判断します。これにより、浮動小数点数の誤差による比較の問題を適切に扱えるようになります。
浮動小数点数を==演算子で直接比較すると、内部的な誤差により意図しない結果となる場合があります。PHP_FLOAT_EPSILONは、この誤差を考慮して二つの浮動小数点数が「ほぼ等しい」かを判断するための、非常に小さな正の定数です。サンプルコードのように、二つの値の差の絶対値がPHP_FLOAT_EPSILONより小さいかどうかで比較することが重要です。ただし、この定数は最小限の許容誤差であるため、より大きな計算誤差が予想される場合は、用途に応じて独自の許容誤差(tolerance)を設定して比較する方が安全な場合があります。
PHP_FLOAT_EPSILON で浮動小数点比較する
1<?php 2 3/** 4 * 2つの浮動小数点数が実質的に等しいかどうかを判断します。 5 * 6 * 浮動小数点数の比較では、丸め誤差のために直接 == 演算子を使用すると 7 * 予期せぬ結果になることがあります。この関数は、2つの数値の絶対差が 8 * PHP_FLOAT_EPSILON または指定された許容誤差よりも小さい場合に、 9 * それらが等しいと判断します。 10 * 11 * @param float $floatA 比較する最初の浮動小数点数。 12 * @param float $floatB 比較する2番目の浮動小数点数。 13 * @param float $epsilon 許容する最大誤差。デフォルトは PHP_FLOAT_EPSILON。 14 * @return bool 2つの数値が実質的に等しい場合は true、それ以外の場合は false。 15 */ 16function areFloatsEffectivelyEqual(float $floatA, float $floatB, float $epsilon = PHP_FLOAT_EPSILON): bool 17{ 18 return abs($floatA - $floatB) < $epsilon; 19} 20 21// PHP_FLOAT_EPSILON の値を出力して確認 22echo "PHP_FLOAT_EPSILON の値: " . PHP_FLOAT_EPSILON . "\n\n"; 23 24// 浮動小数点数の計算による誤差の典型的な例 25$valueA = 0.1 + 0.2; // 実際の値は 0.30000000000000004 のようになる場合がある 26$valueB = 0.3; 27 28echo "--- 浮動小数点数の比較例 --- \n"; 29echo "計算結果 (\$valueA): " . sprintf('%.20F', $valueA) . "\n"; // 高精度で表示 30echo "期待値 (\$valueB): " . sprintf('%.20F', $valueB) . "\n\n"; // 高精度で表示 31 32// 直接 == 演算子で比較する危険性を示す 33echo "== 演算子での比較:\n"; 34if ($valueA == $valueB) { 35 echo " \$valueA と \$valueB は等しいと判断されました。\n"; 36} else { 37 echo " \$valueA と \$valueB は等しくないと判断されました。(丸め誤差による)\n"; 38} 39 40// PHP_FLOAT_EPSILON を用いた安全な比較を示す 41echo "\nareFloatsEffectivelyEqual() 関数での比較 (PHP_FLOAT_EPSILON を使用):\n"; 42if (areFloatsEffectivelyEqual($valueA, $valueB)) { 43 echo " \$valueA と \$valueB は実質的に等しいと判断されました。\n"; 44} else { 45 echo " \$valueA と \$valueB は実質的に等しくないと判断されました。\n"; 46} 47 48// 異なる許容誤差での比較例 49$floatX = 1.0; 50// $floatY は $floatX から PHP_FLOAT_EPSILON の半分だけ離れている 51$floatY = 1.0 + PHP_FLOAT_EPSILON / 2; 52// $floatZ は $floatX から PHP_FLOAT_EPSILON の2倍だけ離れている 53$floatZ = 1.0 + PHP_FLOAT_EPSILON * 2; 54 55echo "\n--- 異なる許容誤差での比較 --- \n"; 56echo "変数 \$floatX: " . sprintf('%.20F', $floatX) . "\n"; 57echo "変数 \$floatY: " . sprintf('%.20F', $floatY) . "\n"; 58echo "変数 \$floatZ: " . sprintf('%.20F', $floatZ) . "\n\n"; 59 60echo "areFloatsEffectivelyEqual(\$floatX, \$floatY) (デフォルトの PHP_FLOAT_EPSILON):\n"; 61if (areFloatsEffectivelyEqual($floatX, $floatY)) { 62 echo " \$floatX と \$floatY は実質的に等しい。(差が PHP_FLOAT_EPSILON より小さい)\n"; 63} else { 64 echo " \$floatX と \$floatY は実質的に等しくない。\n"; 65} 66 67echo "\nareFloatsEffectivelyEqual(\$floatX, \$floatZ) (デフォルトの PHP_FLOAT_EPSILON):\n"; 68if (areFloatsEffectivelyEqual($floatX, $floatZ)) { 69 echo " \$floatX と \$floatZ は実質的に等しい。\n"; 70} else { 71 echo " \$floatX と \$floatZ は実質的に等しくない。(差が PHP_FLOAT_EPSILON より大きい)\n"; 72} 73 74echo "\nareFloatsEffectivelyEqual(\$floatX, \$floatZ, PHP_FLOAT_EPSILON * 3) (より大きな許容誤差):\n"; 75if (areFloatsEffectivelyEqual($floatX, $floatZ, PHP_FLOAT_EPSILON * 3)) { // 許容誤差を明示的に指定 76 echo " \$floatX と \$floatZ は実質的に等しい。(差が指定された許容誤差より小さい)\n"; 77} else { 78 echo " \$floatX と \$floatZ は実質的に等しくない。\n"; 79}
PHPの定数PHP_FLOAT_EPSILONは、浮動小数点数の比較において非常に重要な値です。これは、1.0と、それより大きい次に表現可能な浮動小数点数との差を定義しており、コンピュータでの浮動小数点数計算に伴うごくわずかな「丸め誤差」を考慮するために利用されます。
サンプルコードでは、このPHP_FLOAT_EPSILONを使用して、2つの浮動小数点数が実質的に等しいかを判断するareFloatsEffectivelyEqual関数が定義されています。この関数は、比較する最初の浮動小数点数$floatAと2番目の$floatBを受け取ります。また、許容する最大誤差として$epsilonを指定でき、省略した場合はPHP_FLOAT_EPSILONがデフォルト値として使用されます。二つの数値の絶対差が$epsilonよりも小さい場合、関数はtrue(等しい)を返し、それ以外はfalse(等しくない)を返します。
一般的な==演算子で浮動小数点数を比較すると、例えば0.1 + 0.2の結果と0.3が、丸め誤差のために等しくないと判断されることがあります。サンプルコードは、この==演算子の限界を示しつつ、areFloatsEffectivelyEqual関数とPHP_FLOAT_EPSILONを用いることで、これらの数値が実質的に等しいと正しく判断できることを具体的に示しています。これにより、誤差を考慮した安全な浮動小数点数の比較が可能になります。
浮動小数点数の計算では、ごくわずかな丸め誤差が発生し、厳密には異なる値となりえます。そのため、浮動小数点数を直接 == 演算子で比較すると、意図せず「等しくない」と判定されることがあります。PHP_FLOAT_EPSILON は、このような丸め誤差を考慮し「実質的に等しい」と判断するための最小許容誤差です。サンプルコードのように、2つの数値の差の絶対値が PHP_FLOAT_EPSILON、または状況に応じたより大きな許容誤差よりも小さい場合に、それらを「実質的に等しい」と判断する方法が安全で推奨されます。