Would float point format be affected by big-endian

2019-01-22 22:38发布

问题:

I know the integer format would be different between big-endian machine and little-endian machine, is it the same for float point format (IEEE 754)?

回答1:

The IEEE754 specification for floating point numbers simply doesn't cover the endianness problem. Floating point numbers therefore may use different representations on different machines and, in theory, it's even possible that for two processors integer endianness is the same and floating point is different or vice-versa.

See this wikipedia article for more information.



回答2:

If you have a Linux box, you'll probably have /usr/include/ieee754.h... (note the #ifs)

...
union ieee754_float
  {
    float f;

    /* This is the IEEE 754 single-precision format.  */
    struct
      {
#if     __BYTE_ORDER == __BIG_ENDIAN
        unsigned int negative:1;
        unsigned int exponent:8;
        unsigned int mantissa:23;
#endif                          /* Big endian.  */
#if     __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int mantissa:23;
        unsigned int exponent:8;
        unsigned int negative:1;
#endif                          /* Little endian.  */
      } ieee;
  ...


回答3:

Endianness issues arise as soon as you consider something as made up of smaller units. The way the smaller units are arranged may change.

Then if you care about variations in FP format, you must be aware that IEEE 754 doesn't describe a FP representation (even if it one diagram suggest one), and there is at least one more variation than the one related to endianness: the bit denoting signaling subnormals is interpreted differently in different implementation.



回答4:

Here is a suggestion for how you can handle this in a portable manner no matter C compiler. Please regard this as pseudo-code, it is written here and now in my web browser and not tested:

#include <stdint.h>
#include <stdio.h>

static uint16_t endian = 0xAABB;
#if ( *(const uint8_t*)&endian == 0xAA )
  #define BIG_ENDIAN
#else
  #define LITTLE_ENDIAN
#endif


#ifdef BIG_ENDIAN

  #define FLOAT_NEGATIVE  0x80000000U
  #define FLOAT_EXPONENT  0x7F800000U
  #define FLOAT_MANTISSA  0x007FFFFFU

  #define SHIFT_NEGATIVE  31U
  #define SHIFT_EXPONENT  23U
  #define SHIFT_MANTISSA   0U

#elif defined LITTLE_ENDIAN

  #define FLOAT_NEGATIVE  0x00000001U
  #define FLOAT_EXPONENT  0x000001FEU
  #define FLOAT_MANTISSA  0xFFFFFE00U

  #define SHIFT_NEGATIVE  0U
  #define SHIFT_EXPONENT  1U
  #define SHIFT_MANTISSA  9U

#endif


typedef union 
{
  float     as_float;
  uint32_t  as_int;

} ieee745_t;



uint32_t  float_negative (ieee745_t ieee);
uint32_t  float_exponent (ieee745_t ieee);
uint32_t  float_mantissa (ieee745_t ieee);



uint32_t  float_negative (ieee745_t ieee)
{
  return (ieee.as_int & FLOAT_NEGATIVE) >> SHIFT_NEGATIVE;
}


uint32_t  float_exponent (ieee745_t ieee)
{
  return (ieee.as_int & FLOAT_EXPONENT) >> SHIFT_EXPONENT;
}


uint32_t  float_mantissa (ieee745_t ieee)
{
  return (ieee.as_int & FLOAT_MANTISSA) >> SHIFT_MANTISSA;
}


int main()
{
  ieee745_t f = {-1.23f};

  printf("%f\n", f.as_float);
  printf("Negative:\t%X\n", float_negative(f) );
  printf("Exponent:\t%X\n", float_exponent(f) );
  printf("Mantissa:\t%X\n", float_mantissa(f) );
  getchar();

  return 0;
}