php 浮點數比較方法

2021-08-13 02:20:43 字數 2031 閱讀 3065

首先看乙個例子:

<?php

$a = 0.1;

$b = 0.9;

$c = 1;

var_dump(($a+$b)==$c);

var_dump(($c-$b)==$a);

?>

$a+$b==$c 返回true,正確

$c-$b==$a 返回false,錯誤

為什麼會這樣呢?

運算後,精度為20位時實際返回的內容如下:

<?php

$a = 0.1;

$b = 0.9;

$c = 1;

printf("%.20f", $a+$b); // 1.00000000000000000000

printf("%.20f", $c-$b); // 0.09999999999999997780

?>

$c-$b 為 0.09999999999999997780,因此與0.1比較返回false

出現這個問題是因為浮點數計算涉及精度,當浮點數轉為二進位制時有可能會造成精度丟失。

整數部分採用除以2取餘方法

小數部分採用乘以2取整方法

例如:把數字8.5轉為二進位制

整數部分是8

8/2=4 8%2=0

4/2=2 4%2=0

2/2=1 2%2=0

1比2小,因此不需要計算下去,整數8的二進位制為 1000

小數部分是0.5

0.5x2 = 1.0

因取整後小數部分為0,因此不需要再計算下去

小數0.5的二進位制為 0.1

8.5的二進位制為1000.1

計算數字0.9的二進位制

0.9x2=1.8

0.8x2=1.6

0.6x2=1.2

0.2x2=0.4

0.4x2=0.8

0.8x2=1.6

…. 之後不斷迴圈下去,當擷取精度為n時,n後的數會被捨去,導致精度丟失。

上例中0.9在轉為二進位制時精度丟失,導致比較時出現錯誤。

所以永遠不要相信浮點數已精確到最後一位,也永遠不要比較兩個浮點數是否相等。

1.使用round方法處理後再比較

例子:

<?php

$a = 0.1;

$b = 0.9;

$c = 1;

var_dump(($c-$b)==$a); // false

var_dump(round(($c-$b),1)==round($a,1)); // true

?>

2.使用高精度運算方法

首先進行運算時,使用高精度的運算方法,這樣可以保證精度不丟失。

高精度運算的方法如下:

bcadd 將兩個高精度數字相加

bccomp 比較兩個高精度數字,返回-1,0,1

bcdiv 將兩個高精度數字相除

bcmod 求高精度數字餘數

bcmul 將兩個高精度數字相乘

bcpow 求高精度數字乘方

bcpowmod 求高精度數字乘方求模

bcscale 配置預設小數點位數,相當於linux bc中的」scale=」

bcsqrt 求高精度數字平方根

bcsub 將兩個高精度數字相減

例子:

<?php

$a = 0.1;

$b = 0.9;

$c = 1;

var_dump(($c-$b)==$a); // false

var_dump(bcsub($c, $b, 1)==$a); // true

?>

php比較浮點數

php手冊中有一句話,永遠不要比較兩個浮點數是否相等,但是在實際情況中,有時候還是會涉及到關於浮點數的運算和比較,當出現這種情況下,請使用bc math擴充套件函式或者gmp 函式。我們來看一種常見的情況 a 1.3 b 1.2 c 0.1 d a b if d c else printf 20f ...

php 浮點數比較方法詳解

浮點數運算精度問題 首先看乙個例子 php a 0.1 b 0.9 c 1 var dump a b c var dump c b a a b c 返回true,正確 c b a 返回false,錯誤 為什麼會這樣呢?運算後,精度為20位時實際返回的內容如下 b 0.9 c 1 printf 20f...

PHP浮點數比較不准

首先看一段 a 0.1 b 0.7 var dump a b 0.8 列印出來的值居然為 boolean false 這是為啥?php手冊對於浮點數有以下警告資訊 warning 浮點數精度 顯然簡單的十進位制分數如同 0.1 或 0.7 不能在不丟失一點點精度的情況下轉換為內部二進位制的格式。這就...