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

WBOY
リリース: 2016-07-13 09:53:51
オリジナル
865 人が閲覧しました

PHP浮動小数点精度の問題の概要

この記事では主にPHP浮動小数点精度問題の概要を紹介します この記事では、PHP浮動小数点精度損失の問題に焦点を当ててその原因を説明します。さまざまな方法でこの問題を解決する方法、困っている友達がそれを参考にすることができます

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

まず次のコードを見てください:

コードは以下の通りです:

$f = 0.57;

エコー間隔($f * 100) //56

;

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

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

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

指数ビット:データを基数2で累乗し、指数をオフセットコードで表すことを示します

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

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(四捨五入されるので注意)

コードは以下の通りです:

round($a/$b, 3);

あるいはもっと良い方法があればメッセージを残して教えてください。

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

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

しかし、私はその時、次のよくある質問に対する答えを 1 つ見逃していました:

コードは以下の通りです:

$f = 0.58;

var_dump(intval($f * 100)) //なぜ57が出力されるのか

?>

出力が 57 なのはなぜですか?

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.579999999999999996

0.57 -> 0.569999999999999995

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

そうすると、計算すると自然に57になります…

この問題の重要なポイントは、「有限の小数を持っているように見えますが、コンピューターの 2 進表現では無限です」であることがわかります。

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

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/1000080.html技術記事 PHP 浮動小数点数の精度の問題の概要 この記事では、PHP 浮動小数点数の精度の問題の概要を主に紹介します。この記事では、PHP 浮動小数点数の精度の損失の問題に焦点を当て、これをさまざまな方法で 3 つの段落に分けて説明します...
関連ラベル:
php
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート