How to get the sign, mantissa and exponent of a floating point number

匿名 (未验证) 提交于 2019-12-03 09:02:45

问题:

I have a program, which is running on two processors, one of which does not have floating point support. So, I need to perform floating point calculations using fixed point in that processor. For that purpose, I will be using a floating point emulation library.

I need to first extract the signs, mantissas and exponents of floating point numbers on the processor which do support floating point. So, my question is how can I get the sign, mantissa and exponent of a single precision floating point number.

Following the format from this figure,

That is what I've done so far, but except sign, neither mantissa and exponent are correct. I think, I'm missing something.

void getSME( int& s, int& m, int& e, float number ) {     unsigned int* ptr = (unsigned int*)&number;      s = *ptr >> 31;     e = *ptr & 0x7f800000;     e >>= 23;     m = *ptr & 0x007fffff; } 

回答1:

I think it is better to use unions to do the casts, it is clearer.

#include   typedef union {   float f;   struct {     unsigned int mantisa : 23;     unsigned int exponent : 8;     unsigned int sign : 1;   } parts; } float_cast;  int main(void) {   float_cast d1 = { .f = 0.15625 };   printf("sign = %x\n", d1.parts.sign);   printf("exponent = %x\n", d1.parts.exponent);   printf("mantisa = %x\n", d1.parts.mantisa); } 

Example based on http://en.wikipedia.org/wiki/Single_precision



回答2:

Find out the format of the floating point numbers used on the CPU that directly supports floating point and break it down into those parts. The most common format is IEEE-754.

Alternatively, you could obtain those parts using a few special functions (double frexp(double value, int *exp); and double ldexp(double x, int exp);) as shown in this answer.

Another option is to use %a with printf().



回答3:

My advice is to stick to rule 0 and not redo what standard libraries already do, if this is enough. Look at math.h (cmath in standard C++) and functions frexp, frexpf, frexpl, that break a floating point value (double, float, or long double) in its significand and exponent part. To extract the sign from the significand you can use signbit, also in math.h / cmath, or copysign (only C++11). Some alternatives, with slighter different semantics, are modf and ilogb/scalbn, available in C++11; http://en.cppreference.com/w/cpp/numeric/math/logb compares them, but I didn't find in the documentation how all these functions behave with +/-inf and NaNs. Finally, if you really want to use bitmasks (e.g., you desperately need to know the exact bits, and your program may have different NaNs with different representations, and you don't trust the above functions), at least make everything platform-independent by using the macros in float.h/cfloat.



回答4:

You're &ing the wrong bits. I think you want:

s = *ptr >> 31; e = *ptr & 0x7f800000; e >>= 23; m = *ptr & 0x007fffff; 

Remember, when you &, you are zeroing out bits that you don't set. So in this case, you want to zero out the sign bit when you get the exponent, and you want to zero out the sign bit and the exponent when you get the mantissa.

Note that the masks come directly from your picture. So, the exponent mask will look like:

0 11111111 00000000000000000000000

and the mantissa mask will look like:

0 00000000 11111111111111111111111



回答5:

On Linux package glibc-headers provides header #include with floating point types definitions, e.g.:

union ieee754_double   {     double d;      /* This is the IEEE 754 double-precision format.  */     struct       { #if __BYTE_ORDER == __BIG_ENDIAN     unsigned int negative:1;     unsigned int exponent:11;     /* Together these comprise the mantissa.  */     unsigned int mantissa0:20;     unsigned int mantissa1:32; #endif              /* Big endian.  */ #if __BYTE_ORDER == __LITTLE_ENDIAN # if    __FLOAT_WORD_ORDER == __BIG_ENDIAN     unsigned int mantissa0:20;     unsigned int exponent:11;     unsigned int negative:1;     unsigned int mantissa1:32; # else     /* Together these comprise the mantissa.  */     unsigned int mantissa1:32;     unsigned int mantissa0:20;     unsigned int exponent:11;     unsigned int negative:1; # endif #endif              /* Little endian.  */       } ieee;      /* This format makes it easier to see if a NaN is a signalling NaN.  */     struct       { #if __BYTE_ORDER == __BIG_ENDIAN     unsigned int negative:1;     unsigned int exponent:11;     unsigned int quiet_nan:1;     /* Together these comprise the mantissa.  */     unsigned int mantissa0:19;     unsigned int mantissa1:32; #else # if    __FLOAT_WORD_ORDER == __BIG_ENDIAN     unsigned int mantissa0:19;     unsigned int quiet_nan:1;     unsigned int exponent:11;     unsigned int negative:1;     unsigned int mantissa1:32; # else     /* Together these comprise the mantissa.  */     unsigned int mantissa1:32;     unsigned int mantissa0:19;     unsigned int quiet_nan:1;     unsigned int exponent:11;     unsigned int negative:1; # endif #endif       } ieee_nan;   };  #define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent.  */ 


回答6:

Cast a pointer to the floating point variable as something like an unsigned int. Then you can shift and mask the bits to get each component.

float foo; unsigned int ival, mantissa, exponent, sign;  foo = -21.4f; ival = *((unsigned int *)&foo); mantissa = ( ival & 0x7FFFFF); ival = ival >> 23; exponent = ( ival  & 0xFF ); ival = ival >> 8; sign = ( ival & 0x01 ); 

Obviously you probably wouldn't use unsigned ints for the exponent and sign bits but this should at least give you the idea.



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