作者: Laruence( ) 本文地址: http://www.laruence.com/2013/03/26/2884.html 转载请注明出处 关于PHP的浮点数, 我之前写过一篇文章: 关于PHP浮点数你应该知道的(All ‘bogus’ about the float in PHP) 不过, 我当时遗漏了一点, 也就是对于如下的这个常见问
- 作者: Laruence( )
- 本文地址: http://www.laruence.com/2013/03/26/2884.html
- 转载请注明出处
关于PHP的浮点数, 我之前写过一篇文章: 关于PHP浮点数你应该知道的(All ‘bogus’ about the float in PHP)
不过, 我当时遗漏了一点, 也就是对于如下的这个常见问题的回答:
<?php $f = 0.58;
var_dump(intval($f * 100)); //为啥输出57
?>
登入後複製
为啥输出是57啊? PHP的bug么?
我相信有很多的同学有过这样的疑问, 因为光问我类似问题的人就很多, 更不用说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位计算的话,分别是:
0.58 -> 0.57999999999999996
0.57 -> 0.56999999999999995
登入後複製
至于0.58 * 100的具体浮点数乘法, 我们不考虑那么细, 有兴趣的可以看(Floating point), 我们就模糊的以心算来看… 0.58 * 100 = 57.999999999
那你intval一下, 自然就是57了….
可见, 这个问题的关键点就是: “你看似有穷的小数, 在计算机的二进制表示里却是无穷的”
so, 不要再以为这是PHP的bug了, 这就是这样的…..
Comments
- 2013/03/26, FtMan writes: 受教,回头再详细查查
- 2013/03/26, 梦康 writes: 汗,原来还得先转成二进制。小数转二进制,真不知道。说实话这个问题我们这种低级打字员用得比较少,但是知道也好。
- 2013/03/26, xxx writes: 那这种情况如何避免? 浮点和整数之间的计算还是很多的..
- 2013/03/26, 花生 writes: 好东西,必须弄懂的
- 2013/03/26, wy writes: 别用intval,用round ...
- 2013/03/26, kevin writes: function _intval($n){
return floor(floatval($n));
}
这样如何?
- 2013/03/26, Melo618 writes: 另一个例子:
- 2013/03/26, Anonymous writes: 另一个例子:
$n="19.99";
intval($n * 100); // prints 1998
intval(strval($n * 100)); // prints 1999
printf("%.13f", $n * 100);// prints 1998.9999999999998
- 2013/03/26, dodgepudding writes: 习惯上都是先round再intval吧
- 2013/03/26, bright writes: 不仅仅php,java也是这样的~ 面试的人都喜欢这些啊。
- 2013/03/27, justjavac writes: 以前写的一篇浮点数的文章:
代码之谜(四)- 浮点数(从惊讶到思考)
http://justjavac.iteye.com/blog/1725977
- 2013/03/27, mcfog writes: javascript:alert(parseInt(0.58*100))
JS的结果也是一样的
- 2013/04/01, wxf writes: echo会自动判断这种情况吗?因为同样intval(.57*100)值是56,但是echo出来是57
- 2013/04/06, kevin writes: php> = intval(0.58 * 100 )
57
php> = intval(0.58 * 100 . '' )
58
转string时发生了什么?btmath是如何解决这个问题的?
- 2013/04/07, Anonymous writes: 看来还是计算机科班出身的好
- 2013/04/08, Anonymous writes: $ php -r "var_dump(intval(57.999999999999999));";
int(58)
$ php -r "var_dump(intval(57.99999999999999));";
int(57)
- 2013/04/09, gaodi07 writes: 小数点转二进制。。。不知道咋转,受教了
- 2013/04/12, pengzhen writes: 那为什么直接echo出来的是正确的了,echo 0.58*100 得出的就是58,为什么不是57.9999999996
- 2013/04/12, pengzhen writes: 还能再问你个问题吗,你博客里的那些php代码高亮是怎么实现的
- 2013/04/16, ppoo24 writes: @pengzhen 因为这个例子是$f = 0.58;是有个赋值动作的,也就是0.58会被存储,而存储就将以二进制保存。你如果直接输出0.58 * 100这个操作,是不会有存储这步
- 2013/04/16, ppoo24 writes: @pengzhen 不好意思,我刚才的推测,应该是错误的
- 2013/04/17, FtMan writes: 好人 一生平安
- 2013/04/19, karocxing writes: 话说,echo 出来是正确的几位同学,为什么要echo 0.58 * 100?
而不是 echo intval(0.58 * 100) 呢?
汗一个先。
- 2013/04/19, karocxing writes: 还有,echo intval(0.57 * 100) 和 var_dump(intval(0.57 * 100))结果都是56。。。
0.58的也都是57。。。
- 2013/04/23, lyongde writes: 是这样的。
- 2013/04/26, 新锦江娱乐城 writes: PHP小菜级别...我就不说话了
- 2013/04/27, Anonymous writes: 膜拜。
- 2013/04/27, abc writes: 膜拜。
- 2013/04/28, PHP浮点数的一个常见问题的解答 | 午后小憩 writes: [...] 本文地址: http://www.laruence.com/2013/03/26/2884.html [...]
- 2013/04/29, michael writes: 昨天定程序就遇到这个问题,旁边的同事给我解决明白了,没想到鸟哥也出来科普了。呵呵
- 2013/04/29, xuanskyer writes: 鸟叔,0.58的二进制第一位不应该为1么?你说的“下面的数字省掉了隐含的1”是说第一位的1被省略?
- 2013/04/30, PHP5.5或将引入Generators | 午后小憩 writes: [...] PHP浮点数的一个常见问题的解答 [...]
- 2013/05/02, 让PHP更快的提供文件下载 | 午后小憩 writes: [...] PHP浮点数的一个常见问题的解答 [...]
- 2013/05/02, Taint-0.3.0(A XSS codes sniffer) released | 午后小憩 writes: [...] PHP浮点数的一个常见问题的解答 [...]
- 2013/05/07, IEEE754学习笔记 | 屌丝程序猿 writes: [...] PHP浮点数的一个常见问题的解答 [...]
- 2013/05/08, 蚂蚁 writes: 这让我想起了一个基础的计算机试题,如果得到整数的算术平方根
- 2013/05/08, vb2005xu writes: 为什么 只有 0.58 0.57 有这个问题呢
- 2013/05/08, 霸气千秋 writes: 之前在群里边看过这个问题,受限于计算机的计算模式
- 2013/05/13, 红色石头 writes: 新浪sae备案之后真是快啊,膜拜博客新浪首席...待业应届研究生~
- 2013/05/16, 大饼 writes: 计算机里,浮点数一般都是近似值的。除了0.5,0.25,0.125这样的正好是2的整数幂分之一的书是精确的。
- 2013/05/24, php&java Makes me cool » 小数怎么以二进制表示 writes: [...] Written by phpjava. Posted in 杂文分享 最近听到很多同事聊“浮点型”的数据好像经常会出现各种问题,在“Laruence”的PHP浮点数的一个常见问题的解答的博客中解释了这个东西,还是先说说小数如何用二进制表示的问题,后面具体说说浮点的问题 [...]
- 2013/05/24, wclssdn writes:
var_dump((0.8) * 10 == (0.1 + 0.7) * 10); //false
鸟哥. 这个是为啥啊? 求解答..
- 2013/06/03, Beckham writes: 大大 会不会在新的php版本中 有所更新或者其他什么表现?
- 2013/06/06, bliwy writes: perl对正则表达式的优化可以做到基于trie
use Regexp::Optimizer;
my $o = Regexp::Optimizer->new->optimize(qr/foobar|fooxar|foozap/);
# $re is now qr/foo(?:[bx]ar|zap)/
php可以做到么?有没有对应的第三方包?
- 2013/06/15, 小谈博客 writes: 那怎么才能算出准确的值呢?
- 2013/06/15, 小谈博客 writes: 那怎么才能算出准确的值呢?
- 2013/06/29, dog writes: your blog is word press Version 3.0.3 .
- 2013/07/03, 知知了了 writes: 那为什么 var_dump(intval(0.58 * 1000));exit; 出来的不是579而是580呢?
求解。。。
- 2013/07/03, 达达尼亚 writes: 其实也不是都这样,为了保险起见,是不是都要 先用 round函数一下啊?
- 2013/07/05, Anonymous writes: 赞
- 2013/07/24, 微历史 writes: 研究wp,想学点php,看到这么多人讨论的都是比较高深的
- 2013/07/28, 於志远 writes: 这个对我帮助比较大,哈哈。谢鸟哥~
- 2013/07/29, 耀眼 writes: www.szprovence.com液晶拼接
祝你越办越好
- 2013/08/09, la recovery SaintSulpice et kid listing ont vu leur foree et leur g s writes: [...] went schoolfirer for due loiy door Jacques Chirac et Alain Juppé sont durante strength [ Découvrez ces challengers j virtual assistanthaud et ?a l'ensemble des faire planer geeks j parce que alfredia durantei [...]
- 2013/08/28, PHP浮点数的一个常见问题的解答 | LAMP技术博客 writes: [...] 本文转自:?http://www.laruence.com/2013/03/26/2884.html?作者:laruence 分享到: document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000) [...]
- 2013/08/28, zhaoyuhao writes: 对浮点数精度丢失的原因稍做补充
http://zhaoyuhao.com/notes/show/206
- 2013/09/25, 养生指南 writes: 一直在用round的路过
- 2013/10/22, 罗列php与众不同的小运算 | 次子小标 writes: [...] 这个具体解释,详见鸟哥博客PHP浮点数的一个常见问题的解答 [...]
- 2013/10/23, Star writes: 最近的 php5.4 应该修复了吧?
- 2014/08/24, seo Hitchin writes: Nice blog here! Alsso your site loads up fast!
Whhat host are you using? Can I get your affilijate link
to your host? I wish mmy site loaded up ass fast as yours
lol
Feel free to visitt my web site - seo Hitchin
- 2014/09/05, PHP浮点数的一个常见问题 | 行云流水 writes: [...] 之前在项目做订单模块的时候,经常会出现xx.01等到厘的金额,这块就会有浮点的陷阱,别小看几厘哦,在基数比较大的支付情况下,将会是很大的数字。有篇文章分享下给大家,摘自:风雪之隅。 [...]
Copyright © 2010 风雪之隅 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)