PHP の +-*/ を使用して浮動小数点数を計算すると、不正確な計算結果による問題が発生する可能性があります。たとえば、echo intval(0.58*100); は 58 ではなく 57 を出力します。これは実際には基礎となるバイナリです。浮動小数点数を正確に表現できないバグは、Python を使用してもこの問題に遭遇しました。したがって、基本的にほとんどの言語は、正確な計算を行うためのクラス ライブラリまたは関数ライブラリを提供しています。たとえば、PHP には BC 高精度関数ライブラリがあります。以下では、PHP トレーニング教師のデーンが、よく使用されるいくつかの BC 高精度関数の使用方法を紹介します。 。
例
コードは次のとおりです | |
出力が 57 なのはなぜですか?
bugs.php.net でよく質問されることは言うまでもなく、同様の質問をする人がたくさんいるので、多くの学生がこの質問を抱いたことがあると思います...
この理由を理解するには、まず浮動小数点数の表現 (IEEE 754) を知る必要があります:
浮動小数点数は、64 ビット長 (倍精度) を例として、1 つの符号ビット (E)、11 の指数ビット (Q)、および 52 ビットの仮数ビット (M) (合計 64 ビット) で表されます。 )。
符号ビット:最上位ビットはデータの符号を表し、0は正の数、1は負の数を表します。指数ビット:データを基数2で累乗し、指数をオフセットコードで表すことを示します
仮数部:データの小数点以下の有効数字を示します。
ここで重要なのは、小数を二進数で表現することです。小数点が二進数でどのように表現されるかについては、ここでは詳しく説明しません。理解する必要があるのは、0.58 が無限に長いということです。バイナリ表現の場合 (以下の数字は暗黙の 1 を省略します)。
0.58 (52 ビット) のバイナリ表現は基本的に: 00101000111101011100001010001111010111000010100011110.57 バイナリ表現 (52 ビット) は基本的に: 0010001111010111000010100 011 11010111000010100011110 そして、これら 52 ビットだけで計算すると、この 2 つの 2 進数は次のようになります: www.111cn.net0.58 -> 0.579999999999999960.57 -> 0.5699999999999999 0.58 * 100 の具体的な浮動小数点の乗算については、詳しくは考えませんので、興味のある方は見てください(浮動小数点)。暗算でなんとなく… 0.58 * 100 = 57.999999999
そうすると、計算すると自然に57になります…
この問題の重要なポイントは、「有限の小数を持っているように見えますが、コンピューターの 2 進表現では無限です」であることがわかります。
だから、これはもう PHP のバグだと思わないでください、これがそういうものなのです…
PHP 浮動小数点型 +-*%/
には不正確さの問題があります例:
1.
$a = 0.1;
$b = 0.7;
var_dump(($a + $b) == 0.8);
出力される値はブール値 false です
これはなぜですか? PHP マニュアルには、浮動小数点数に関する次の警告メッセージがあります。
警告浮動小数点精度
0.1 や 0.7 などの一見単純な小数は、精度を少し損なうことなく内部バイナリ形式に変換できません。これにより、結果が混乱する可能性があります。たとえば、floor((0.1+0.7)*10) は、結果の内部表現が 7.9999999999… のようなものになるため、通常、期待される 8 ではなく 7 を返します。
これは、有限の桁数で特定の小数を正確に表現することが不可能であるという事実に関係しています。たとえば、10 進数の 1/3 は 0.3333333 になります。
したがって、浮動小数点数の結果が最後の桁まで正確であるとは決して信じないでください。また、2 つの浮動小数点数が等しいかどうかを比較しないでください。本当により高い精度が必要な場合は、任意精度の数学関数または gmp 関数を使用する必要があります
コードは次のとおりです
var_dump(bcadd($a,$b,2) == 0.8);
bcadd — 2 つの高精度数値を加算します bccomp — 2 つの高精度数値を比較し、-1、0、1 を返します bcdiv — 2 つの高精度数値の除算 bcmod — 高精度の数値の余りを求める bcmul — 2 つの高精度数値の乗算 bcpow — 高精度の数値の累乗を求めます bcpowmod — 数論で非常に一般的に使用される、高精度の数値べき乗と係数を求めます bcscale — デフォルトの小数点数を設定します。これは、Linux bc の "scale=" に相当します。bcsqrt — 高精度の数値の平方根を求めます bcsub — 2 つの高精度数値を減算します いくつかの例をまとめました php BC 高精度関数ライブラリには、加算、比較、除算、減算、剰余、乗算、n 乗、デフォルトの小数点数の設定、および 2 乗が含まれます。これらの関数は、電子商取引の価格計算などの金銭計算の場合にさらに便利です。
|