让:
double d = 0.1;
float f = 0.1;
表达式
(f > d)
返回true
或false
?
根据经验,答案是true
。但是,我预计它会false
。
由于0.1
不能完美地用二进制表示,而double的精度为15
到16
十进制数,而float只有7
。因此,它们都小于0.1
,而双倍更接近0.1
。
我需要true
的确切解释。
答案 0 :(得分:171)
我会说答案取决于将double
转换为float
时的舍入模式。 float
有24个二进制位精度,double
有53个。在二进制中,0.1是:
0.1₁₀ = 0.0001100110011001100110011001100110011001100110011…₂
^ ^ ^ ^
1 10 20 24
因此,如果我们将第24位数字 up ,我们将获得
0.1₁₀ ~ 0.000110011001100110011001101
大于精确值,53位数的精确近似值。
答案 1 :(得分:55)
数字0.1将四舍五入为具有给定精度的最接近的浮点表示。这种近似可能大于或小于0.1,因此如果不查看实际值,就无法预测单精度或双精度近似是否更大。
这是双精度值四舍五入到的(使用Python解释器):
>>> "%.55f" % 0.1
'0.1000000000000000055511151231257827021181583404541015625'
这是单精度值:
>>> "%.55f" % numpy.float32("0.1")
'0.1000000014901161193847656250000000000000000000000000000'
所以你可以看到单精度近似值更大。
答案 2 :(得分:19)
如果您将.1
转换为二进制文件,则会获得:
0.000110011001100110011001100110011001100110011001100...
永远重复
映射到数据类型,您得到:
float(.1) = %.00011001100110011001101 ^--- note rounding double(.1) = %.0001100110011001100110011001100110011001100110011010
将其转换为基数10:
float(.1) = .10000002384185791015625 double(.1) = .100000000000000088817841970012523233890533447265625
这取自布鲁斯道森撰写的一篇文章。它可以在这里找到:
Doubles are not floats, so don’t compare them
答案 3 :(得分:5)
我认为问题Eric Lippert's comment实际上是最明确的解释,所以我会将其作为答案重新发布:
假设您计算1/3的3位十进制和6位十进制数。 0.111< 0.111111,对吧?
现在假设您正在计算6/9。 0.667> 0.666667,对吧?
你不能认为三位十进制中的6/9是0.666,因为这不是最接近3位小数的6/9!
答案 4 :(得分:4)
由于无法准确表示,因此比较基数2中的1/10就像比较基数10中的1/7。
1/7 = 0.142857142857 ...但是在不同的基础10精度(3对6位小数位)进行比较时,我们得到0.143> 0.142857。
答案 5 :(得分:1)
只是为了增加谈论IEEE-754和x86的其他答案:这个问题比看起来更复杂。没有"一个"在IEEE-754中表示为0.1 - 有两个。向下或向上舍入最后一位数字都是有效的。这种差异可以并且确实会发生,因为x86 不使用64位进行内部浮点计算;它实际上使用80位!这称为double extended-precision。
因此,即使在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;
}
有关详细信息,请参阅Why is cos(x) != cos(y)
even though x == y
?。
答案 6 :(得分:1)
double的等级大于转换中的float等级。通过进行逻辑比较,f被强制转换为double,并且您正在使用的实现可能会产生不一致的结果。如果后缀为f,则编译器将其注册为float,则得到0.00,在double类型中为false。非浮动类型是双重的。
#include <stdio.h>
#include <float.h>
int main()
{
double d = 0.1;
float f = 0.1f;
printf("%f\n", (f > d));
return 0;
}