ホームページ  >  記事  >  バックエンド開発  >  PHP が浮動小数点数を計算できない場合はどうすればよいですか?

PHP が浮動小数点数を計算できない場合はどうすればよいですか?

藏色散人
藏色散人オリジナル
2021-11-19 09:50:161605ブラウズ

php は、コンピューターの基礎となるバイナリが浮動小数点数を正確に表現できないため、浮動小数点数を計算できません。解決策は、BC 高精度関数ライブラリなど、正確な計算を行うためのクラス ライブラリまたは関数ライブラリを使用することです。 phpで。

PHP が浮動小数点数を計算できない場合はどうすればよいですか?

この記事の動作環境: Windows7 システム、PHP バージョン 7.1、DELL G3 コンピューター

php の場合はどうすればよいですか浮動小数点数を計算できませんか?

php での浮動小数点数計算の問題

php の -*/ を使用して浮動小数点数を計算すると、計算結果が正しくなくなるという問題が発生する可能性があります。 . , たとえば、 echo intval(0.58*100); は、58 ではなく 57 を出力します。これは、実際には、浮動小数点数を正確に表現できない、コンピュータの基礎となるバイナリのバグです。これは、言語を超えたものです。私も、次のコマンドを使用してこの問題に遭遇しました。パイソン。したがって、基本的にほとんどの言語には、精密な計算を行うためのクラス ライブラリまたは関数ライブラリが用意されています。たとえば、PHP には BC 高精度関数ライブラリがあります。ここでは、よく使用される BC 高精度関数をいくつか紹介します。

<?php    
$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 で表し、指数はオフセット コードで表されます。

仮数: データの小数点以下の有効な桁を表します。

ここでのポイント それは、2 進数での小数表現にあります。2 進数での小数表現方法については、Baidu で検索できます。ここでは詳しく説明しません。理解する必要がある重要なことは、バイナリ表現、0.58 は無限に長い値です (暗黙の 1 を省略した以下の数値)..

0.58 のバイナリ表現は基本的に (52 ビット): 00101000111101011100001010001111010111000010100011110.57 は基本的に (52 ビット): 0010 00111101011100 001010001111010111000010100011110 およびバイナリこれらの 52 ビットが計算されると、次のようになります: www.111cn.net

0.58 -> 0.579999999999999960.57 -> 0.5699999999999999 0.58 * 100 の具体的な浮動小数点乗算については、詳しいことは考慮しませんので興味があればご覧ください (浮動小数点) 暗算で漠然と見てみましょう... 0.58 * 100 = 57.999999999

それを積分すれば自然にbe 57...

この問題の鍵は次のとおりです。「一見有限に見える 10 進数が、コンピュータの 2 進表現では実際には無限である」ということです。これは PHP のバグだと思わないでください。これが実際のところです...

PHP の浮動小数点処理に不正確さがあります -*%/

例:

  $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 関数を使用する必要があります。

コードは次のとおりです。

<?php
$a = 0.1;
$b = 0.7;
var_dump(bcadd($a,$b,2) == 0.8);
  bcadd — 将两个高精度数字相加
  bccomp — 比较两个高精度数字,返回-1, 0, 1
  bcp — 将两个高精度数字相除
  bcmod — 求高精度数字余数
  bcmul — 将两个高精度数字相乘
  bcpow — 求高精度数字乘方
  bcpowmod — 求高精度数字乘方求模,数论里非常常用
  bcscale — 配置默认小数点位数,相当于就是Linux bc中的”scale=”
  bcsqrt — 求高精度数字平方根
  bcsub — 将两个高精度数字相减

いくつかの例を完成しました

php BC high-precision関数ライブラリには、加算、比較、除算、減算、剰余、乗算、n 乗、デフォルトの小数点数の設定、および 2 乗が含まれます。これらの関数は、電子商取引の価格計算などの金銭計算の場合にさらに便利です。

注: 設定桁数については、四捨五入されず超過分は切り捨てられます。

推奨学習: 「

PHP ビデオ チュートリアル

以上がPHP が浮動小数点数を計算できない場合はどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。