如何使用union(位字段)处理自定义浮点?

时间:2014-03-26 19:13:58

标签: c floating-point unions bit-fields

我正在分析处理指向点的前驱代码(代码在微控制器上运行),但我不了解事情是如何运作的。我必须知道如何将平面转换为十进制,反之亦然。但是,他所做的是在数据结构中使用自定义位字段表示exponent:6 bitsmantissa:26 bit

typedef union {
  struct {
   #ifdef _BIG_ENDIAN
      unsigned int mant: 26;    /* -33,554,432 to +33,554,431 */
      unsigned int exp: 6;      /* 10^-32 to 10^+31 */
   #else
      unsigned int exp: 6;      /* 10^-32 to 10^+31 */
      unsigned int mant: 26;    /* -33,554,432 to +33,554,431 */
   #endif
 } part;
 unsigned long comp;
} DMKS;

随后是客户端的程序逻辑:

  1. 客户端(微控制器)从服务器获取数据并将值设置为unsigned long comp

  2. 致电M_to_u(),将DMKS值转换为micro value

  3. M_to_u()如下所示:

    long M_to_u(DMKS dmks_val)
    {
    
    register unsigned int exp;
    long    retval;
    
    UARTprintf("before x= %x\n",  (dmks_val.comp));//First print of comp
    
    retval = (long) (dmks_val.part.mant);    
    
    UARTprintf("retval x= %x\n", (long) (dmks_val.part.mant));//second print of mantissa
    
    if (retval & 0xfe000000)
    {
        retval |= 0xfe000000;
    }
    
    exp = dmks_val.part.exp;
    
    UARTprintf("exp = %d\n", (long) (dmks_val.part.exp));//Third print of exponent
    //UARTprintf("exp x= %x\n", (long) (dmks_val.part.exp));
    
    
    switch(exp) {
      case 58:
    retval /= 1000000L;
    break;
      case 59:
    retval /= 100000L;
    break;
      case 60:
    retval /= 10000L;
    break;
      case 61:
    retval /= 1000L;
    break;
      case 62:
    retval /= 100L;
    break;
      case 63:
    retval /= 10L;
    break;
      case 0:
    break;
      case 1:
    retval *= 10L;
    break;
      case 2:
    retval *= 100L;
    break;
      case 3:
    retval *= 1000L;
    break;
      case 4:
    retval *= 10000L;
    break;
      default:
    break;
    }
    
    return(retval);
    

    }

  4. 打印出值

  5. - IEEE 754 standard specifies a binary32 format example

    enter image description here

    - customized floating point in this codes = 11110100001001000000111101

    mantissa exponent +---+---+---+---+---+---+---+----+ | 11110100001001000000 | 111101 | +---+---+---+---+---+---+---+----+

    • 第一个UARTPrint :: before x= 3d0903d,它是从服务器发送的联合中comp的纯值, bin格式 = 11110100001001000000111101

    • 尾数字段的第二次打印:: retval x= f4240从尾数的位字段中提取, bin格式 = 11110100001001000000

    • 第三次打印:: exp = 61从指数的位字段中提取, bin格式 = 111101

    问题是:

    IEEE 754标准指定binary32 (exp bits:23~30, and mantissa bits:0 ~22)不同,自定义位字段用于此代码中的浮点。

    1。事情如何运作? - 此代码使用exp位:0~5和尾数位:6~30,因此客户/服务器需要操作  比特顺序?

    2。为什么它除以1000L? - 打印出来显示exp值= 61,所以进入case 61:,但指数61如何连接到divided by 1000L

    由于 -Jin

1 个答案:

答案 0 :(得分:0)

您的前任可能的工作方式,但这是一种不可靠且危险的方法 - struct内的位域序列化顺序是实现定义的,并且不需要它与CPU用于整数的字节顺序一致(顺便说一句,不一定与用于硬件浮点的字节序相同!),声明的顺序,或其他任何。< / p>

由于您以这种自定义格式从微控制器接收unsigned long,我会记下字段的顺序 - 看起来尾数是高位而指数是低位,每个字段内的位顺序与CPU的位顺序一致; 没有文档或测试可以依赖 - 然后使用显式位掩码来提取字段,例如

unsigned long mantissa = (dmks_val & 0xFFFFFFC0) >> 6;
unsigned long exponent = (dmks_val & 0x0000003F) >> 0;

其中dmks_val现在是unsigned long而不是联合。应该用火和剑从你的代码库中清除联盟。

我无法帮助您解决问题2.只有了解这种古怪浮点格式的人才能帮助您解决问题2.顺便说一下,您最好找到符号位。