为什么函数可以正常使用float但不适用于double?

时间:2017-10-24 16:52:48

标签: c floating-point double bit-manipulation

我找到了检查浮点数是否为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]

正如您在评论中看到的那样,它没有任何问题。但是,当我尝试将此程序转换为双数字版本时,它会产生错误的结果:

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]

你能解释一下这是什么问题吗?

2 个答案:

答案 0 :(得分:2)

失败的原因是有效数字中的位数错误。

float的情况下,存储了24位。

double的情况下,52位存储为53。

更正了这一点,并添加了LL限定符(如评论中所述)违规行变为

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

并给出与float相同的结果。

答案 1 :(得分:1)

代码执行无效转移。 1int。需要long long@Robᵩ

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

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

代码使用了错误的常量。 IEEE 754 binary64 double具有52位编码的有效数字。 @njuffa

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

代码也无法正常使用+无穷大。

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