ホームページ  >  記事  >  バックエンド開発  >  PHP 浮動小数点精度の問題の概要、PHP 浮動小数点精度_PHP チュートリアル

PHP 浮動小数点精度の問題の概要、PHP 浮動小数点精度_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 09:53:53948ブラウズ

PHP浮動小数点数の精度問題のまとめ、PHP浮動小数点数の精度

1. PHP浮動小数点数の精度損失問題

まず次のコードを見てください:
コードをコピーします コードは次のとおりです:
$f = 0.57;
エコー間隔($f * 100); //56

結果は少し驚くかもしれませんが、PHP は IEEE 754 倍精度に従います。

浮動小数点数は、1 つの符号ビット (E)、11 の指数ビット (Q)、および 52 ビットの仮数ビット (M) (合計 64 ビット) を使用して、64 ビットの倍精度で表されます。
符号ビット: 最上位ビットはデータの符号を表し、0 は正の数を表し、1 は負の数を表します。
指数ビット: データが基数 2 乗されていることを示し、指数はオフセット コードで表されます
仮数部: データの小数点以下の有効数字を示します。

10 進数が 2 進数でどのように表現されるかを見てみましょう:

2を掛けて切り上げ、順番に並べます。つまり、小数部を2倍し、整数部を取り、残りの小数部を2倍し、整数部を取り、残りの小数部を2を計算して小数部の部分を取りますが、このように0.57のような小数を掛けると、小数部が0になることはありません。有効数字の10進表現は2進数では無限大です。

0.57 のバイナリ表現は基本的に (52 ビット): 0010001111010111000010100011110101110000101000111101

52 ビットしかない場合、0.57 => 0.56999999999999995

上記の予期せぬ結果を確認するのは難しくありません。

2. PHP浮動小数点数の精度の問題

まず質問を見てみましょう:

コードをコピーします コードは次のとおりです:
$f = 0.58;
var_dump(intval($f * 100)); //なぜ 57 が出力されるのですか

このような疑問を持ったことのある学生さんも多いと思います。

具体的な原理については、「Brother Bird」の記事で詳しい説明があります: PHP 浮動小数点数に関するよくある質問への回答

それでは、この問題を回避するにはどうすればよいでしょうか?
方法はたくさんありますが、ここでは 2 つ紹介します:
1.スプリント
コードをコピーします コードは次のとおりです:
substr(sprintf("%.10f", ($a/ $b)), 0, -7);

2.round(丸くなるので注意)
コードをコピーします コードは次のとおりです:
ラウンド($a/$b, 3);

または、より良い方法がある場合は、メッセージを残して教えてください。

3. PHP 浮動小数点数に関するよくある質問への回答

PHP の浮動小数点数については、以前に次の記事を書きました: PHP の float についてのすべての「偽り」 (PHP の float についてのすべての「偽り」)

しかし、私は次のよくある質問に対する答えを 1 つ見逃していました:
コードをコピーします コードは次のとおりです:
$f = 0.58;
var_dump(intval($f * 100)); //なぜ 57 が出力されるのですか
?>

出力が 57 になるのはなぜですか? PHP のバグですか?

bugs.php.net でよく質問されることは言うまでもなく、同様の質問をする人がたくさんいるので、多くの学生がそのような質問をしたことがあると思います...

この理由を理解するには、まず浮動小数点数の表現 (IEEE 754) を知る必要があります。

浮動小数点数は、64 ビット長 (倍精度) を例として、1 つの符号ビット (E)、11 の指数ビット (Q)、および 52 ビットの仮数ビット (M) で表されます (合計 64 ビット)。 .

符号ビット: 最上位ビットはデータの符号を表し、0 は正の数を表し、1 は負の数を表します。

指数ビット: データの累乗を基数 2 で表し、指数はオフセット コードで表されます

仮数: データの小数点以下の有効数字を示します。

ここで重要なのは、バイナリでの小数を表現する方法については、ここでは詳しく説明しません。0.58 は無限に長いということです。バイナリ表現 (以下の数字は暗黙の 1 を省略します)..

0.58 のバイナリ表現は基本的に (52 ビット): 0010100011110101110000101000111101011100001010001111
0.57 のバイナリ表現は基本的に (52 ビット): 0010001111010111000010100011110101110000101000111101
これら 52 ビットのみを使用して 2 つの 2 進数を計算すると、次のようになります。
コードをコピーします コードは次のとおりです:
0.58 -> 0.57999999999999996
0.57 -> 0.56999999999999995

具体的な浮動小数点の乗算0.58 * 100については、詳しくは考えませんので、興味のある方は暗算で見てみてください... 0.58 * 100 = 57.999999999

それでは、計算してみると、当然57になります…

この問題の重要なポイントは、「一見有限に見える 10 進数は、コンピューターの 2 進数表現では実際には無限である」ということです。

だから、これはもう PHP のバグだと思わないでください。これが実際のバグです…

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/998816.html技術記事 PHP 浮動小数点数の精度の問題の概要、PHP 浮動小数点数の精度 1. PHP 浮動小数点数の精度損失の問題については、まず次のコードを確認してください。 次のようにコードをコピーします。 //...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。