为什么这种与零的比较不能正常工作?

Why this comparison to zero is not working properly?

我有这个代码:

double A = doSomethingWonderful(); // same as doing  A = 0;
if(A == 0)
{
    fprintf(stderr,"A=%llx\n", A);
}

和这个输出:

A=7f35959a51c0

这怎么可能?

我检查了7f35959a51c0的值,好像是6.91040329973658785751176861252E-310,很小,但不是零。

编辑:

好的,我知道那种为双精度打印十六进制值的方法是行不通的。我需要找到一种方法来打印双字节的字节。

根据评论我修改了我的代码:

    A = doSomethingWonderful();// same as doing  A = 0;
    if(A == 0)
    {
        char bytes[8];
        memcpy(bytes, &A, sizeof(double));
        for(int i = 0; i < 8; i++)
        fprintf(stderr," %x", bytes[i]);
    }

我得到了这个输出:

0 0 0 0 0 0 0 0

最后看来比较工作正常,但我的打印效果不佳。

IEEE 754 精度浮点值在指数值中使用偏差,以便完全表示正指数和负指数。对于双精度值,偏差是 1023[source],它恰好是十六进制的 0x3ff,它与 A 的十六进制值相匹配您为 10e0.

打印

另外两个小笔记:

  • 当打印字节时,你可以使用%hhx让它只打印 2 个十六进制数字而不是符号扩展到 8。
  • 您可以使用联合将 double 值可靠地打印为 8 字节整数。
double A = 0;
if(A == 0)
{
    A = 1; // Note that you were setting A to 1 here!
    char bytes[8];
    memcpy(bytes, &A, sizeof(double));
    for(int i = 0; i < 8; i++)
        printf(" %hhx", bytes[i]);
}
int isZero;
union {
    unsigned long i;
    double d;
} u;
u.d = 0;
isZero = (u.d == 0.0);
printf("\n============\n");
printf("hex   = %lx\nfloat = %f\nzero?   %d\n", u.i, u.d, isZero);

结果:

 0 0 0 0 0 0 f0 3f
============
hex   = 0
float = 0.000000
zero?   1

所以在第一行,我们看到 1.00e0(即 00)。

在下面几行中,我们看到当您使用联合打印双精度 0.0 的十六进制值时,您会按预期得到 0

当您将双精度值传递给 printf() 时,您将其作为 浮点数 值传递。但是,由于 "%x" 格式是整数格式,您的 printf() 实现将尝试读取 integer 参数。由于这种基本类型不匹配,例如,调用代码可能将您的双精度值放在浮点寄存器中,而 printf() 实现试图从整数寄存器中读取它。详细信息取决于您的 ABI,但显然您看到的位不是您通过的位。从语言的角度来看,当一个 printf() 参数与其相应的格式规范之间存在类型不匹配时,您就有未定义的行为。

除此之外,+0.0 确实表示为所有位为零,无论是单精度格式还是双精度格式。然而,这只是正零,-0.0用符号位集表示。

在最后一段代码中,您正在检查 1.0 的位模式,因为您在进行转换之前覆盖了 A 的值。另请注意,由于符号扩展,您得到的是 fffffff0 而不是第七个字节的 f0 。要获得正确的输出,请使用 unsigned 字节的数组。

您看到的模式解码如下:

00 00 00 00 00 00 f0 3f
to big endian:
3f f0 00 00 00 00 00 00

decode fields:
sign: 0 (1 bit)
exponent: 01111111111 (11 bit), value = 1023
    exponent = value - bias = 1023 - 1023 = 0
mantissa: 0...0 (52 bit), value with implicit leading 1 bit: 1.0000...

entire value: -1^0 * 2^0 * 1.0 = 1.0