Sign of a floating point number

别来无恙 提交于 2019-11-30 18:41:04

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.

Walter

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)?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!