- 本文地址: https://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了, 这就是这样的.....
Space exploration never fails to amaze me. Our universe is full of wonders waiting to be discovered. https://www.prestigeparksgrove.ind.in
Good one.
Sobha Neopolis on Panathur Road in East Bangalore is noteworthy. This area is recognized as one of the prime real estate destinations in the city.
[…] https://www.laruence.com/2013/03/26/2884.html […]
I look forward to seeing your new posts every day. i think many people like your post. thanks for sharing these remarkable things
[…] PHP 的浮点数是不能精确计算的,具体的可以看这篇文章。所幸的是,金额一般不会有太多的小数。那么存储的时候呢,一言以蔽之,以 分 为单位进行存储。在 MySQL 中,以 int 类型存储就行了(视情况选择字段类型)。 […]
[…] 为啥输出了57 针对这个问题,逛了鸟哥的博客。(PHP浮点数的一个常见问题的解答) […]
[…] 本文地址: http://www.laruence.com/2013/03/26/2884.html […]
[…] PHP 的浮点数是不能精确计算的,具体的可以看这篇文章。所幸的是,金额一般不会有太多的小数。那么存储的时候呢,一言以蔽之,以 分 为单位进行存储。在 MySQL 中,以 int 类型存储就行了(视情况选择字段类型)。 […]
学习研究的路上
$f = 0.57;
var_dump(intval($f * 100)); //为啥输出56
$f = 0.56;
var_dump(intval($f * 100)); //为啥输出56
$f = 0.55;
var_dump(intval($f * 100)); //为啥输出55
[…] 在风雪之隅的博客里一篇 PHP浮点数的一个常见问题的解答,里面有说明。 […]
0.58 二进制结果有误,应为 ee8b69658
#include
int main() {
double a = 0.58;
printf(“%lu,%p”,sizeof(a), a);
return 0;
}
$ ./a.out
8,0x7ffee8b69658%
sorry 程序写错了。撤回我刚才说的。。。。。
$ ./a.out
8,3fe28f5c28f5c28f
4,3f147ae1
#include
int main() {
double a = 0.58, *aptr = &a;
float af = 0.58, *afptr = ⁡
printf(“%lu,%lx\n”,sizeof(a), *(long int *)aptr);
printf(“%lu,%x\n”,sizeof(af), *(int *)afptr);
// printf(“%lu,%d”,sizeof(a),(int) (a * 100) );
// int b = 21;
// printf(“%lu, %p\n”, sizeof(b), b);
// printf(“%lu, %d\n”, sizeof(b), (int)(float) b);
return 0;
}
[…] 關於php浮點數,情況laruence部落格文章:http://www.laruence.com/2013/03/26/2884.html […]
[…] 本文地址: http://www.laruence.com/2013/03/26/2884.html […]
[…] 由PHP浮点数运算精度造成的,鸟哥的Bolg有详细的说明。http://www.laruence.com/2013/03/26/2884.html, 小数在二进制表示时,0.58对于二进制,是无限长的值 […]
二进制,让我头痛
[…] 关于php浮点数,情况laruence博客文章:http://www.laruence.com/2013/03/26/2884.html […]
[…] http://www.laruence.com/2013/03/26/2884.html http://www.cnblogs.com/qlwy/archive/2012/08/17/2644470.html Category: 移动端开发 […]
f这个对我帮助比较大,哈哈。谢鸟哥~
这个对我帮助比较大,哈哈。谢鸟哥~
研究wp,想学点php,看到这么多人讨论的都是比较高深
研究wp,想学点php,看到这么多人讨论的都是比较高深的
[…] 具体原因:http://www.laruence.com/2013/03/26/2884.html […]
GITHUB: https://github.com/huqinlou0123/php-internals-extended-development-course
视频地址 http://edu.csdn.net/course/detail/6261
看不太懂的同学,推荐看下PHP底层内核源码与扩展开发视频教程作为入门,
其实就是精度截取的问题,哈哈
这个浮点数问题是,不是php特有的
路过 支持一下
[…] 之前在项目做订单模块的时候,经常会出现xx.01等到厘的金额,这块就会有浮点的陷阱,别小看几厘哦,在基数比较大的支付情况下,将会是很大的数字。有篇文章分享下给大家,摘自:风雪之隅。 […]
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
最近的 php5.4 应该修复了吧?
[…] 这个具体解释,详见鸟哥博客PHP浮点数的一个常见问题的解答 […]
一直在用round的路过
对浮点数精度丢失的原因稍做补充
http://zhaoyuhao.com/notes/show/206
[…] 本文转自: 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) […]
[…] 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 […]
http://www.szprovence.com液晶拼接
祝你越办越好
这个对我帮助比较大,哈哈。谢鸟哥~
研究wp,想学点php,看到这么多人讨论的都是比较高深的
赞
其实也不是都这样,为了保险起见,是不是都要 先用 round函数一下啊?
那为什么 var_dump(intval(0.58 * 1000));exit; 出来的不是579而是580呢?
求解。。。
your blog is word press Version 3.0.3 .
那怎么才能算出准确的值呢?
那怎么才能算出准确的值呢?
perl对正则表达式的优化可以做到基于trie
use Regexp::Optimizer;
my $o = Regexp::Optimizer->new->optimize(qr/foobar|fooxar|foozap/);
# $re is now qr/foo(?:[bx]ar|zap)/
php可以做到么?有没有对应的第三方包?
大大 会不会在新的php版本中 有所更新或者其他什么表现?
var_dump((0.8) * 10 == (0.1 + 0.7) * 10); //false
鸟哥. 这个是为啥啊? 求解答..
[…] Written by phpjava. Posted in 杂文分享 最近听到很多同事聊“浮点型”的数据好像经常会出现各种问题,在“Laruence”的PHP浮点数的一个常见问题的解答的博客中解释了这个东西,还是先说说小数如何用二进制表示的问题,后面具体说说浮点的问题 […]
计算机里,浮点数一般都是近似值的。除了0.5,0.25,0.125这样的正好是2的整数幂分之一的书是精确的。
新浪sae备案之后真是快啊,膜拜博客新浪首席…待业应届研究生~
之前在群里边看过这个问题,受限于计算机的计算模式
为什么 只有 0.58 0.57 有这个问题呢
这让我想起了一个基础的计算机试题,如果得到整数的算术平方根
[…] PHP浮点数的一个常见问题的解答 […]
[…] PHP浮点数的一个常见问题的解答 […]
[…] PHP浮点数的一个常见问题的解答 […]
[…] PHP浮点数的一个常见问题的解答 […]
鸟叔,0.58的二进制第一位不应该为1么?你说的“下面的数字省掉了隐含的1”是说第一位的1被省略?
昨天定程序就遇到这个问题,旁边的同事给我解决明白了,没想到鸟哥也出来科普了。呵呵
[…] 本文地址: http://www.laruence.com/2013/03/26/2884.html […]
膜拜。
膜拜。
PHP小菜级别…我就不说话了
是这样的。
还有,echo intval(0.57 * 100) 和 var_dump(intval(0.57 * 100))结果都是56。。。
0.58的也都是57。。。
话说,echo 出来是正确的几位同学,为什么要echo 0.58 * 100?
而不是 echo intval(0.58 * 100) 呢?
汗一个先。
好人 一生平安
@pengzhen 不好意思,我刚才的推测,应该是错误的
@pengzhen 因为这个例子是$f = 0.58;是有个赋值动作的,也就是0.58会被存储,而存储就将以二进制保存。你如果直接输出0.58 * 100这个操作,是不会有存储这步
还能再问你个问题吗,你博客里的那些php代码高亮是怎么实现的
那为什么直接echo出来的是正确的了,echo 0.58*100 得出的就是58,为什么不是57.9999999996
小数点转二进制。。。不知道咋转,受教了
$ php -r “var_dump(intval(57.999999999999999));”;
int(58)
$ php -r “var_dump(intval(57.99999999999999));”;
int(57)
看来还是计算机科班出身的好
php> = intval(0.58 * 100 )
57
php> = intval(0.58 * 100 . ” )
58
转string时发生了什么?btmath是如何解决这个问题的?
echo会自动判断这种情况吗?因为同样intval(.57*100)值是56,但是echo出来是57
javascript:alert(parseInt(0.58*100))
JS的结果也是一样的
以前写的一篇浮点数的文章:
代码之谜(四)- 浮点数(从惊讶到思考)
http://justjavac.iteye.com/blog/1725977
不仅仅php,java也是这样的~ 面试的人都喜欢这些啊。
习惯上都是先round再intval吧
另一个例子:
$n=”19.99″;
intval($n * 100); // prints 1998
intval(strval($n * 100)); // prints 1999
printf(“%.13f”, $n * 100);// prints 1998.9999999999998
另一个例子:
function _intval($n){
return floor(floatval($n));
}
这样如何?
别用intval,用round …
好东西,必须弄懂的
那这种情况如何避免? 浮点和整数之间的计算还是很多的..
汗,原来还得先转成二进制。小数转二进制,真不知道。说实话这个问题我们这种低级打字员用得比较少,但是知道也好。
受教,回头再详细查查