iT邦幫忙

0

PHP round()詭異現象~(不求解)

問題是這樣的~
我要用PHP做一個統計並輸出至EXCEL~
統計資料中有百分比的計算..
所有的統計程式都一樣~
輸出也都正常~
但唯獨其中一個值出現異常....
如下:

round((1/1435)*100,2)

上面這段..理論上結果應該是0.07
但是實際卻跑出0.07000000000000001

且已經故意另外嘗試其上下100的值(1535~1335)
結果是一樣的..
過了這個範圍就正常了

這問題已在聊天室發問過~
本想說沒解決也沒關係
所以才在聊天室當作聊天發問~/images/emoticon/emoticon37.gif
沒想到異常熱烈討論...= =
(有熱烈嗎?0.0)

已有神人回答~
嘗試修改php.ini內的precision值為14
但我查過已經是14~
也試過故意改別的值再phpinfo()出來
所以確定是那個php.ini檔案~

不過當我把設定的值已程式碼的方式執行在PHP中

ini_set('precision', '14');

結果成功了...

round((1/1435)*100,2)

輸出結果為0.07

賽門 大大~
不求解~ㄎㄎ~XDD

看更多先前的討論...收起先前的討論...
忘了貼圖= =
![http://ithelp.ithome.com.tw/upload/images/20170224/20103968SsVsMdzIhb.png](http://ithelp.ithome.com.tw/upload/images/20170224/20103968SsVsMdzIhb.png)
複製網址看圖~
我可以問一下你最近的一次修改php.ini後有沒有重啟apache?
當然~
再說...那個值一直都是14~
因為根本不會動他= =
我的serialize_precision這個值是100耶!(xampp安裝時就預設這個長度了。)
100喔~~~
更早之前fillano大說嘗試修改precision時
我除了修改precision也有修改serialize_precision....
只是沒改過那麼大的(100)
剛剛改完...
..
..
..
..
看不出變化...= =
你的php是那個版本?然後作業系統是?
fillano iT邦超人 1 級 ‧ 2017-02-25 01:07:35 檢舉
還有幾個可能性:
1. 你有使用其他的php library例如從composer引用進來的東西,會在runtime改掉這個的嗎?
2. 你用的伺服器?例如在apache使用php module,也有可能透過apache的設定改php的設定。
TO 可樂 ..
WIN 10 PHP5
TO fillano ..
1.PHP 一直都是預設~ 從安裝到現在 ~系統就安裝GIT、NODEJS ~ 沒動過PHP~ PHP我都拿來跑後端SQL輸出json給前端javascript執行~
2.我用apache~ 這個伺服器從安裝到現在也都沒動過他~ (只又最近遇到這個問題才開始動php.ini 和重啟apache)
對了!!!突然想到..我php有多安裝一個Zend Engine的PHP加密~
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

2
bizpro
iT邦大師 1 級 ‧ 2017-02-25 14:53:03
最佳解答

php的浮點運算的精確度有限: https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
我們看到的十進位浮點, 內部事實上是二進位浮點.

php.ini的precision內定是14, 足夠"商業"運算. 如果要求精密, 當您設定precision超過15, 就不能信任其精確度, 如以下的測試:

$ cat phpround.php

<?php
for ( $i=0 ; $i<24 ; $i++ ) {
  ini_set('precision', $i);
  echo "precision $i: ".round((1/1435)*100,2)."\n";
}
?>

我的環境是Ubuntu 16.04 64-bit, 分別用我自己編譯的php 5.6和php 7.0測試:
$ /path-to-my-php/php5.6/bin/php phpround.php
precision 0: 0.07
precision 1: 0.07
precision 2: 0.07
precision 3: 0.07
precision 4: 0.07
precision 5: 0.07
precision 6: 0.07
precision 7: 0.07
precision 8: 0.07
precision 9: 0.07
precision 10: 0.07
precision 11: 0.07
precision 12: 0.07
precision 13: 0.07
precision 14: 0.07
precision 15: 0.07
precision 16: 0.07000000000000001
precision 17: 0.070000000000000007
precision 18: 0.0700000000000000067
precision 19: 0.07000000000000000666
precision 20: 0.070000000000000006661
precision 21: 0.0700000000000000066613
precision 22: 0.07000000000000000666134
precision 23: 0.070000000000000006661338

$ /path-to-my-php/php7.0/bin/php phpround.php
precision 0: 0.07
precision 1: 0.07
precision 2: 0.07
precision 3: 0.07
precision 4: 0.07
precision 5: 0.07
precision 6: 0.07
precision 7: 0.07
precision 8: 0.07
precision 9: 0.07
precision 10: 0.07
precision 11: 0.07
precision 12: 0.07
precision 13: 0.07
precision 14: 0.07
precision 15: 0.07
precision 16: 0.07000000000000001
precision 17: 0.070000000000000007
precision 18: 0.0700000000000000067
precision 19: 0.07000000000000000666
precision 20: 0.070000000000000006661
precision 21: 0.0700000000000000066613
precision 22: 0.07000000000000000666134
precision 23: 0.070000000000000006661338

修改php.ini和在php腳本中使用ini_set來修改是一樣的, 我寫了一個腳本來模擬手動修改php.ini:

$ cat sedphpini.sh

#!/bin/bash
PHPINI=/path-to-my-php-conf-dir/php.ini
PHP=/path-to-my-php-dir/bin/php
for i in {1..24}
do
  sed -i "s/^precision =.*/precision = $i/g" $PHPINI
  $PHP phpround2.php
done

$ cat phpround2.php

<?php
$i=ini_get('precision');
echo "precision $i: ".round((1/1435)*100,2)."\n";
?>

執行結果:
$ ./sedphpini.sh
precision 1: 0.07
precision 2: 0.07
precision 3: 0.07
precision 4: 0.07
precision 5: 0.07
precision 6: 0.07
precision 7: 0.07
precision 8: 0.07
precision 9: 0.07
precision 10: 0.07
precision 11: 0.07
precision 12: 0.07
precision 13: 0.07
precision 14: 0.07
precision 15: 0.07
precision 16: 0.07000000000000001
precision 17: 0.070000000000000007
precision 18: 0.0700000000000000067
precision 19: 0.07000000000000000666
precision 20: 0.070000000000000006661
precision 21: 0.0700000000000000066613
precision 22: 0.07000000000000000666134
precision 23: 0.070000000000000006661338
precision 24: 0.0700000000000000066613381

至於您在php.ini的改變不能生效, 就要看您的php使用的是不是您所修改的php.ini, 可調出php -i的輸出結果來查看.

看更多先前的回應...收起先前的回應...
fillano iT邦超人 1 級 ‧ 2017-02-25 19:29:52 檢舉

php -a測試了一下:

php > ini_set('precision', 14);
php > $n = floatval((0.7+0.1)*10);
php > echo $n;
8
php > ini_set('precision', 17);
php > echo $n;
7.9999999999999991

precision設定影響的是「顯示」出來的結果。zval內部應該單純就是用一個double在做計算,方法就是依照IEEE-754。不過浮點數計算本來就會有精度問題。所以http://php.net/manual/en/language.types.float.php 裡面有警告...

bizpro iT邦大師 1 級 ‧ 2017-02-25 22:03:57 檢舉

是的, 只是"顯示"結果. 只是當precision>15時, 連顯示都跑出尾巴了.

TO bizpro ...
我可以確認~我的php.ini改的是一樣的~
不過後來我試著用幾個月前用VM安裝的Ubuntu跑一次..
(版本跟你一樣)
確實跟你說的一樣...
這樣..是不是就要來檢討我WIN10系統環境問題了~~
/images/emoticon/emoticon13.gif

bizpro iT邦大師 1 級 ‧ 2017-02-27 11:45:12 檢舉

您可以使用ini_get('precision')來檢查php.ini的值.

0
賽門
iT邦超人 1 級 ‧ 2017-02-24 18:07:41

純聊天.....海綿寶要來趕人了。

還是要說, 沒圖沒真相。

請你貼完整Code及執行結果圖及Phpindo().輸出結果圖...

啊,已經有答案了。算了,看版大高興來貼吧。
/images/emoticon/emoticon05.gif

要聊天去聊天室啦~~~~
引用海綿寶說的!!!
『技術問答拿來聊天
聊天室拿來技術問答
這個年......
頭都亂了』
/images/emoticon/emoticon09.gif

我是看這陣子聊天室氣氛這麼緊張
出來說說笑話
大家不是這麼介意吧
/images/emoticon/emoticon25.gif

我要發表回答

立即登入回答