0.1浮点数大于0.1的两倍。 我预料它是错误的
让:
double d = 0.1; float f = 0.1;
应该expression
(f > d)
返回true
或false
?
经验上,答案是true
。 但是,我认为这是false
。
由于0.1
不能完全以二进制表示,而double有15
至16
位的精度,浮点数只有7
。 所以他们都小于0.1
,而双倍更接近0.1
。
我需要一个确切的解释。
我想说的答案取决于舍入模式时,将double
转换为float
。 float
有24个二进制位的精度, double
有53个。在二进制中,0.1是:
0.1₁₀ = 0.0001100110011001100110011001100110011001100110011…₂ ^ ^ ^ ^ 1 10 20 24
所以如果我们在第24位数字中取整,我们会得到
0.1₁₀ ~ 0.000110011001100110011001101
这大于53位的精确值和更精确的近似值。
数字0.1将被舍入到具有给定精度的最接近的浮点表示。 这个近似值可能大于或小于0.1,所以在不考虑实际值的情况下,无法预测单精度或双精度近似值是否更大。
这里是双精度值四舍五入(使用Python解释器):
>>> "%.55f" % 0.1 '0.1000000000000000055511151231257827021181583404541015625'
这里是单精度值:
>>> "%.55f" % numpy.float32("0.1") '0.1000000014901161193847656250000000000000000000000000000'
所以你可以看到单精度逼近更大。
如果你将.1
转换为二进制,你会得到:
0.000110011001100110011001100110011001100110011001100 ...
永远重复
映射到数据types,你会得到:
float(.1)=%.00011001100110011001101 ^ ---注意四舍五入 双(.1)=%.0001100110011001100110011001100110011001100110011010
将其转换为10:
float(.1)= .10000002384185791015625 double(.1)= .100000000000000088817841970012523233890533447265625
这是从Bruce Dawson写的一篇文章中提取出来的。 它可以在这里find:
双打不是花车,所以不要比较它们
我认为Eric Lippert对这个问题的评论其实是最清楚的解释,所以我会把它作为答案重新发布:
假设你正在计算三位十进制和六位十进制的1/9。 0.111 <0.111111,对吗?
现在假设你正在计算6/9。 0.667> 0.666667,对吗?
三位十进制中的6/9不能是0.666,因为它不是最接近6/9的3位小数!
由于不能准确地表示,所以比较基数2的1/10就像比较基数10的1/7。
1/7 = 0.142857142857 …但是在不同的基准10精度(3对6位小数)进行比较时,我们有0.143> 0.142857。
只是添加其他答案,谈论IEEE-754和x86:这个问题比看起来更复杂。 在IEEE-754中没有“一”表示0.1,有两个。 将最后一位数字舍入或舍入将是有效的。 这种差异实际上可能发生 ,因为x86内部浮点计算不使用64位; 它实际上使用80位! 这被称为双倍扩展精度 。
因此,即使是在x86编译器中,有时也会出现这样的情况:相同的数字表示两种不同的方式,因为有些使用64位计算二进制表示,而另一些则使用80。
事实上,甚至在同一台机器上,即使使用相同的编译器也可能发生这种情况!
#include <iostream> #include <cmath> void foo(double x, double y) { if (std::cos(x) != std::cos(y)) { std::cout << "Huh?!?\n"; //← you might end up here when x == y!! } } int main() { foo(1.0, 1.0); return 0; }
即使x == y
为什么是cos(x) != cos(y)
? 获取更多信息。
在转换中,double的级别大于float。 通过做一个逻辑比较,f被转换为double,也许你正在使用的实现给出不一致的结果。 如果你后缀f,所以编译器将它注册为一个浮点数,那么你得到0.00,这是双重types的错误。 没有固定的浮动types是双倍的。
#include <stdio.h> #include <float.h> int main() { double d = 0.1; float f = 0.1f; printf("%f\n", (f > d)); return 0; }