Is there an easy way to determine the sign of a floating point number?
I experimented and came up with this:
#include <iostream>
int main(int argc, char** argv)
{
union
{
float f;
char c[4];
};
f = -0.0f;
std::cout << (c[3] & 0x10000000) << "\n";
std::cin.ignore();
std::cin.get();
return 0;
}
where (c[3] & 0x10000000) gives a value > 0 for a negative number but I think this requires me to make the assumptions that:
- The machine's bytes are 8 bits big
- a float point number is 4 bytes big?
- the machine's most significant bit is the left-most bit (endianness?)
Please correct me if any of those assumptions are wrong or if I have missed any.
Assuming it's a valid floating point number (and not, for example, NaN):
float f;
bool is_negative = f < 0;
It is left as an exercise to the reader to figure out how to test whether a floating point number is positive.
Try
float s = copysign(1, f);
from <math.h>
Another helpful thing may be #including <ieee754.h>
, if it's available on your system/compiler.
Use signbit() from math.h.
1) sizeof(int) has nothing to do with it.
2) assuming CHAR_BIT == 8, yes.
3) we need MSB for that, but endianness affects only byte order, not bit order, so the bit we need to check is c[0]&0x80
for big endianness, or c[3]&0x80
for little, so it would be better to declare union with an uint32_t
and checking with 0x80000000.
This trick have sense only for non-special memory operands. Doing it to a float
value that is in XMM or x87 register will be slower than direct approach. Also, it doesn't treat the special values like NaN or INF.
google the floating point format for your system. Many use IEEE 754 and there is specific sign bit in the data to examine. 1 is negative 0 is positive. Other formats have something similar, and as easy to examine.
Note trying to get the compiler to exactly give you the number you want with a hard coded assignment like f = -0.0F; may not work. has nothing to do with the floating point format but has to do with the parser and the C/C++ library used by the compiler. Generating a minus zero may or may not be that trivial in general.
I've got this from http://www.cs.uaf.edu/2008/fall/cs441/lecture/10_07_float.html try this:
/* IEEE floating-point number's bits: sign exponent mantissa */
struct float_bits {
unsigned int fraction:23; /**< Value is binary 1.fraction ("mantissa") */
unsigned int exp:8; /**< Value is 2^(exp-127) */
unsigned int sign:1; /**< 0 for positive, 1 for negative */
};
/* A union is a struct where all the fields *overlap* each other */
union float_dissector {
float f;
struct float_bits b;
};
int main() {
union float_dissector s;
s.f = 16;
printf("float %f sign %u exp %d fraction %u",s.f, s.b.sign,((int)s.b.exp - 127),s.b.fraction);
return 0;
}
Coming to this late, but I thought of another approach.
If you know your system uses IEEE754 floating-point format, but not how big the floating-point types are relative to the integer types, you could do something like this:
bool isFloatIEEE754Negative(float f)
{
float d = f;
if (sizeof(float)==sizeof(unsigned short int)) {
return (*(unsigned short int *)(&d) >> (sizeof(unsigned short int)*CHAR_BIT - 1) == 1);
}
else if (sizeof(float)==sizeof(unsigned int)) {
return (*(unsigned int *)(&d) >> (sizeof(unsigned int)*CHAR_BIT - 1) == 1);
}
else if (sizeof(float)==sizeof(unsigned long)) {
return (*(unsigned long *)(&d) >> (sizeof(unsigned long)*CHAR_BIT - 1) == 1);
}
else if (sizeof(float)==sizeof(unsigned char)) {
return (*(unsigned char *)(&d) >> (sizeof(unsigned char)*CHAR_BIT - 1) == 1);
}
else if (sizeof(float)==sizeof(unsigned long long)) {
return (*(unsigned long long *)(&d) >> (sizeof(unsigned long long)*CHAR_BIT - 1) == 1);
}
return false; // Should never get here if you've covered all the potential types!
}
Essentially, you treat the bytes in your float as an unsigned integer type, then right-shift all but one of the bits (the sign bit) out of existence. '>>' works regardless of endianness so this bypasses that issue.
If it's possible to determine pre-execution which unsigned integer type is the same length as the floating point type, you could abbreviate this:
#define FLOAT_EQUIV_AS_UINT unsigned int // or whatever it is
bool isFloatIEEE754Negative(float f)
{
float d = f;
return (*(FLOAT_EQUIV_AS_UINT *)(&d) >> (sizeof(FLOAT_EQUIV_AS_UINT)*CHAR_BIT - 1) == 1);
}
This worked on my test systems; anyone see any caveats or overlooked 'gotchas'?
Why not if (f < 0.0)
?
来源:https://stackoverflow.com/questions/4235235/sign-of-a-floating-point-number