1

my question concerns IEEE 754 single percision numbers. Suppose I have a struct:

typedef struct __ieee754
{ 
   int sign;
   int exponent;
   int mantissa;
} IEEE754,*pIEEE754;

Can I convert that to a single percision (1-8-23 float) number? I am using C.

Andro
  • 2,195
  • 1
  • 29
  • 38
  • 3
    The identifier `__ieee754` (as all identifiers starting with `__`) is reserved for the implementation. I suggest you use another name for portability sake. – pmg Feb 15 '12 at 23:17

3 Answers3

4

Supposing your implementation uses IEEE 754 single precision numbers for float, something like this should work

struct __ieee754 f;
/* set f to something valid */
float x = f.sign * f.mantissa * pow(2, f.exponent);
pmg
  • 103,426
  • 11
  • 122
  • 196
3

Assuming 32-bit unsigned int and IEEE-754 single precision float type:

union bla {
    unsigned int a;
    float b;
};

union bla num = {
        (((unsigned int) f.sign & 1) << 31)
      | (((unsigned int) f.exponent & 0xFF) << 23)
      | ( (unsigned int) f.mantissa & 0x7FFFFF); 
};

printf("%f\n", num.b)
ouah
  • 138,975
  • 15
  • 262
  • 325
  • 1
    I didn't downvote, but your shifts and masks for the exponent and mantissa are off. And you can't just assign it to a `float`. You need to pass the bits over via a `union` or something of that sort. – Mysticial Feb 15 '12 at 23:28
  • @Mysticial yes, many errors in the first version, thank you for the remark. – ouah Feb 15 '12 at 23:39
  • There's still an error - the exponent needs to be biased to remove negatives, and the implicit leading 1 in the mantissa needs to be accounted for. Unless the input structure has done this, in which case @pmg's answer is incorrect. – AShelly Feb 16 '12 at 00:08
  • @AShelly this is a good remark. Let say I assumed the `exponent` struct member is the IEEE-754 `exponent`, otherwise I agree the exponent bias has to be accounted for to be correct. – ouah Feb 16 '12 at 10:48
  • After looking at the definition again, I suspect your assumption is correct, but the question is not clear. – AShelly Feb 16 '12 at 19:48
3

One of the previous two answers must be incorrect - because the question is underspecified. We need to know if the structure contains the binary representation of the IEEE float components, or if it contains a numeric definition.

Based on the fact that they are integers, the first is more likely: -4.2 would be represented as {1,0x81,0x066666} or 0xC0866666. In this case, @ouah's answer is correct, and @pmg's will give 2.85e44.

On the other hand, in order for @pmg's code to be correct, the struct for -4.2 would be have to be stored as {-1,-21,0x433333}. And then applying @ouah's algorithm gives 0xF5C33333 which is -4.9489e32 when interpreted as an IEEE float.

If we assume that you are using the first representation, then there is a non-portable processor trick which can simplify your code. Redefine your struct as a union as follows.

union flt  {  
    struct ieee754 {
       unsigned int mantissa:23;
       unsigned int exponent:8;
       unsigned int sign:1;
    } raw;
    float f;
 }

(You might need to reverse the order of arguments depending on your procesor - and ensure the packing is correct - that's the non-portable part)

Now your code can write directly to the memory as bits and read it back as floats:

  union flt num;
  num.raw.sign = 1;
  num.raw.exponent = 129;
  num.raw.mantissa = 0x66666;
  printf("%f", num.f);  //prints 4.2
AShelly
  • 33,795
  • 13
  • 89
  • 148
  • +1, personnally for portability reasons I tend to always avoid bit-fields (almost everything is implementation defined when dealing with bit-fields) but you have nice points in your answer. – ouah Feb 16 '12 at 19:58