让我们:
double d = 0.1;
float f = 0.1;
应该表达
(f > d)
返回true
还是false
?
从经验上讲,答案是true
.但是,我希望它是false
.
由于0.1
不能用二进制完美表示,而双精度具有15
到16
十进制数字的精度,而浮点数只有7
。所以,他们都小于0.1
,而双倍更接近0.1
。
我需要对true
进行确切的解释.
说答案取决于将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
转换为二进制,则会得到:
...
永远重复
映射到数据类型,您可以获得:
浮点数 (.1( = %.00011001100110011001101 ^--- 注四舍五入双精度 (.1( = %.0001100110011001100110011001100110011001100110011010
将其转换为基数 10:
浮点数 (.1( = .10000002384185791015625双精度 (.1( = .100000000000000088817841970012523233890533447265625
这是从布鲁斯道森写的一篇文章中摘录的。 可以在这里找到:
双打不是浮点数,所以不要比较它们
由于它不能完全表示,因此比较 1/10 的基数 2 就像比较 10 基数中的 1/7。
1/7 = 0.142857142857...但是在不同的基数10精度(3位与6位小数(下进行比较,我们有0.143>0.142857。
我认为Eric Lippert对这个问题的评论实际上是最清晰的解释,所以我会把它重新发布为答案:
假设您正在计算 3 位十进制和 6 位十进制的 1/9。 0.111 <0.111111,对吧?
现在假设您正在计算 6/9。 0.667> 0.666667,对吧?
您不能认为三位十进制中的 6/9 是 0.666,因为这不是最接近 6/9 的 3 位小数!
只是为了补充谈论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)
双精度的排名大于转换中的浮点数。通过进行逻辑比较,f 被转换为双倍,也许您使用的实现给出了不一致的结果。如果后缀 f 以便编译器将其注册为浮点数,则得到 0.00,这在双精度类型中为 false。无后缀浮动类型是双倍的。
#include <stdio.h>
#include <float.h>
int main()
{
double d = 0.1;
float f = 0.1f;
printf("%fn", (f > d));
return 0;
}