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?
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
.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.