0.1 浮点数大于 0.1 双精度.我以为它是假的



让我们:

double d = 0.1;
float f = 0.1;

应该表达

(f > d)

返回true还是false

从经验上讲,答案是true.但是,我希望它是false.

由于0.1不能用二进制完美表示,而双精度具有1516十进制数字的精度,而浮点数只有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转换为二进制,则会得到:

0.000110011001100110011001100110011001100110011001100
...

永远重复

映射到数据类型,您可以获得:

浮点数 (.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;
}

最新更新