问题 浮点格式会受big-endian和little endian的影响吗?


我知道big-endian机器和little-endian机器之间的整数格式会有所不同,浮点格式(IEEE 754)是否相同?


9964
2018-03-09 07:23


起源

在维基百科上阅读“big-endian”与“little-endian”。应用逻辑。 - Cheers and hth. - Alf


答案:


浮点数的IEEE754规范根本不包括字节序问题。因此,浮点数可以在不同的机器上使用不同的表示,并且理论上,甚至可能对于两个处理器,整数字节序是相同的并且浮点不同,反之亦然。

看到 这篇维基百科文章 了解更多信息。


12
2018-03-09 07:36





如果你有一个Linux盒子,你可能会有/usr/include/ieee754.h ...(注意 #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;
  ...

2
2018-03-09 07:47



标准未指定位字节的位顺序,字节顺序和对齐,因此编译器开关实际上没有做任何有用的事情。使用此代码,您只需要在endianess和浮点实现之上涉及第三个特定于系统的因素,即位字段的编译器特定实现。此外,编译器可以向位字段添加任意数量的填充字节,也可以添加到并集。 - Lundin
@Lundin:非常正确,这太难了......这就是为什么Linux无法工作且不可移植的原因。哦,好吧,试试Linus ;-)。 - Tony Delroy
@Tony我想指出一些Linux- / GCC特定的位字段与关于浮点格式的一般C编程讨论无关。作为旁注,Linux是可移植的仅仅因为端口使用适合Linux代码的硬件和C编译器,而不是任何真正便携式软件的标准。 - Lundin
@Lundin:关于endianness是否会影响实数的内存布局的讨论......如何显示一个标题的例子,它是根据字节顺序显式更改字段顺序的?这不是关于示例的普遍性的问题,重点是 任何 这样的标题适用于至少一个大端和一个小端系统,证明这些格式是字节序敏感的.... - Tony Delroy
@Lundin:我完全接受它不能保证工作......这不是重点。这只是确认需求。无论如何,这对我们任何一个人来说都没有任何好处,所以如果他们选择的话,我会让读者坚持下去.... - Tony Delroy


一旦考虑由较小单元组成的东西,就会出现字节序问题。较小单元的排列方式可能会发生变化。

然后,如果您关心FP格式的变化,您必须意识到IEEE 754没有描述FP表示(即使它只有一个图表建议),并且至少还有一个与字节序相关的变体:表示信令子正常的比特在不同的实现中被不同地解释。


1
2018-03-09 07:38





以下是无论C编译器如何以可移植的方式处理此问题的建议。请将此视为伪代码,它在此处编写,现在在我的Web浏览器中编写,未经过测试:

#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;
}

1
2018-03-09 13:00