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 #if
s)
...
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;
}