php 浮点bug,PHP浮点运算中一个不算BUG的BUG

博客讨论了计算机如何用二进制存储定点小数,解释了浮点数的表示方法,特别是如何表示0.625。指出由于浮点数的有限位数和舍入误差,十进制到二进制转换可能导致不精确性,进而影响浮点数的比较。举例说明即使在C语言中,直接比较浮点数也可能得到不相等的结果。总结了浮点运算的不准确性是由计算机原理决定的,建议在比较浮点数时采取特定策略。
摘要由CSDN通过智能技术生成

其实这个问题要追溯到微机原理(也有可能是计算机组成原理,记不清楚是哪一本书了),这里面讲了计算机是如何用二进制来存储定点小数。大致是这样 的:如果用一个字节的长度来表示一个定点小数,第一位表示小数的符号,0为正,1为负;后面7位表示小数的值,第2位至第8位的位权分别是 1/2,1/4,1/8,1/16,1/32,1/64,1/128,然后用这些权值的和来表示所有的小数。如何表示0.625呢?

这个有固定的算法:首先,将小数点左侧的整数部分变换为其二进制形式,处理小数部分的算法是将我们的小数部分乘以基数 2,记录乘积结果的整数部分,接着将结果的小数部分继续乘以 2,并不断继续该过程。

0.625 × 2  =  1.25    1

0.25  × 2  =  0.5      0

0.5    × 2  =  1        1

当最后的结果为1时,结束这个过程。这时右侧的一列数字就是我们所需的二进制小数部分,即 0.101。这样,我们就得到了完整的二进制形式 0.101 ,按阶展开:1x1/2+0x1/4+1x1/8=0.5+0.125=0.625。

我们上面先的例子比较特殊,这个数只需要三次运算就能够结束。那会不会有无法结束的情况,不难想象,很多小数根本不能经过有限次这样的过程而得到结 果(比如最简单的 0.1)。但浮点数尾数域的位数是有限的,为此,浮点数的处理办法是持续该过程直到由此得到的尾数足以填满尾数域,之后对多余的位进行舍入。也就是说,十 进制到二进制的变换也并不能保证总是精确的,而只能是近似值。事实上,只有很少一部分十进制小数具有精确的二进制浮点数表达。再加上浮点数运算过程中的误 差累积,结果是很多我们看来非常简单的十进制运算在计算机上却往往出人意料。这就是最常见的浮点运算的"不准确"问题。

所以,在计算机里表示的浮点数只是一个近似的数,并不是像表示整数那样精确没有偏差。既然它只是一个约数,那么你用精确的==来比较两位不精确的约数就没有太大意义了。如果一定要比较两个浮点数,可以考虑先转换成字符串,然后再去比较。

我在Linux下使用c编写了一段类似的浮点数比较的代码,结果也是不相等的。实际上在所有的语言里都会存在此问题,因为这是计算机原理所决定的。但也不排除一些语言做了些后期处理,可以直接比较两个浮点数。

以上仅是个人理解,不保证绝对正确,有错误还请多多谅解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值