简体   繁体   English

为什么该函数与float一起正常工作,但对double却不工作?

[英]Why does the function work with float properly but doesn't work with double?

I found the code that checks whether a float is a power of 2: 我找到了检查浮点数是否为2的幂的代码:

int isPowOf2(float number) {
    union {
        float   floatRepresent;
        int     intRepresent;
    } bitset;

    bitset.floatRepresent = number;

    if((bitset.intRepresent & ((1 << 23)-1)) != 0)
        return ((bitset.intRepresent & (bitset.intRepresent-1)) == 0); // denormalized number
    int power = bitset.intRepresent >> 23;
    return power > 0 && power < 255;
}

// ...

printf("[%f -> %d] ",2.0,isPowOf2(2.0f)); // [2.000000 -> 1] 
printf("[%f -> %d] ",4.0,isPowOf2(4.0f)); // [4.000000 -> 1]
printf("[%f -> %d] ",0.25,isPowOf2(0.25f)); // [0.250000 -> 1]
printf("[%f -> %d]\n ",11.0,isPowOf2(11.0f)); // [11.000000 -> 0]

It works without issues as you can see in comments. 正如您在评论中看到的那样,它可以正常工作。 But when I try to turn this program into the version for double numbers, it gives wrong results: 但是,当我尝试将此程序转换为双倍数版本时,它给出了错误的结果:

int isPowOf2(double number) {
    union {
        double      floatRepresent;
        long long   intRepresent;
    } bitset;

    bitset.floatRepresent = number;

    if((bitset.intRepresent & ((1 << 53)-1)) != 0)
        return ((bitset.intRepresent & (bitset.intRepresent-1)) == 0); // denormalized number
    int power = bitset.intRepresent >> 53;
    return power > 0 && power < 2047;
}

// ...

printf("[%f -> %d] ",2.0,isPowOf2(2.0)); // [2.000000 -> 1] 
printf("[%f -> %d] ",4.0,isPowOf2(4.0)); // [4.000000 -> 0]
printf("[%f -> %d] ",0.25,isPowOf2(0.25)); // [0.250000 -> 0]
printf("[%f -> %d]\n ",11.0,isPowOf2(11.0)); // [11.000000 -> 0]

Could you please explain what's the problem? 您能解释什么问题吗?

The reason for failure is the wrong number of bits in the significand. 失败的原因是有效位数错误。

In the case of float 23 bits are stored of 24. 对于float将存储23位。

In the case of double 52 bits are stored of 53. double的情况下,存储了53个位。

Having corrected that, and added the LL qualifier (as mentioned in comments) the offending line becomes 更正了这一点,并添加了LL限定符(如注释中所述),违规行变为

if((bitset.intRepresent & ((1LL << 52)-1)) != 0) {

and gives the same result as for float . 并给出与float相同的结果。

Code is performing an invalid shift. 代码正在执行无效的移位。 1 is an int . 1是一个int A long long is needed. 需要long long @Robᵩ @罗ᵩ

union {
  double floatRepresent;
  long long intRepresent;
} bitset;

// if((bitset.intRepresent & ((1 << 53)-1)) != 0)
if((bitset.intRepresent & ((1LL << 53)-1)) != 0)

Code is using the wrong constant. 代码使用了错误的常量。 An IEEE 754 binary64 double has a 52 bit encoded significand. IEEE 754 binary64 double编码有效位数为52位。 @njuffa @njuffa

// if((bitset.intRepresent & ((1 << 53)-1)) != 0)
if((bitset.intRepresent & ((1LL << (53-1))-1)) != 0)

Code also does not properly work with +infinity. 代码也无法正确使用+ infinity。

// return power > 0 && power < 2047;
return power > 0 && power < 1023;  // Candidate fix for infinity.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM