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

时间:2015-10-25 14:04:19

标签: c++ c++11 double

我有这段代码:

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

所以最后似乎比较工作正常,但我做的不好。

2 个答案:

答案 0 :(得分:6)

IEEE 754精度浮点值使用指数值中的偏差来完全表示正指数和负指数。对于双精度值,该偏差为1023 [source] ,恰好为十六进制0x3ff,与您为其打印的A的十六进制值匹配10e0

另外两个小笔记:

  • 打印字节时,您可以使用%hhx使其仅打印2个十六进制数字,而不是将符号扩展为8。
  • 您可以使用union将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(即0 0 )。

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

答案 1 :(得分:2)

将双精度值传递给printf()时,将其作为浮点值传递。但是,由于"%x"格式是整数格式,因此printf()实现将尝试读取整数参数。由于这种基本类型不匹配,例如,调用代码可能将您的double值放在浮点寄存器中,而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