Reputation: 39
I found the code that checks whether a float is a power of 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?
Upvotes: 0
Views: 102
Reputation: 153338
Code is performing an invalid shift. 1
is an int
. A long long
is needed. @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. @njuffa
// if((bitset.intRepresent & ((1 << 53)-1)) != 0)
if((bitset.intRepresent & ((1LL << (53-1))-1)) != 0)
Code also does not properly work with +infinity.
// return power > 0 && power < 2047;
return power > 0 && power < 1023; // Candidate fix for infinity.
Upvotes: 1
Reputation: 34575
The reason for failure is the wrong number of bits in the significand.
In the case of float
23 bits are stored of 24.
In the case of double
52 bits are stored of 53.
Having corrected that, and added the LL
qualifier (as mentioned in comments) the offending line becomes
if((bitset.intRepresent & ((1LL << 52)-1)) != 0) {
and gives the same result as for float
.
Upvotes: 2