代码之家  ›  专栏  ›  技术社区  ›  Goz

浮动32到浮动16

  •  8
  • Goz  · 技术社区  · 15 年前

    有人能解释一下如何将32位浮点值转换成16位浮点值吗?

    (s=符号e=指数,m=尾数)


    那就这么简单吗?

    int     fltInt32;
    short   fltInt16;
    memcpy( &fltInt32, &flt, sizeof( float ) );
    
    fltInt16 = (fltInt32 & 0x00FFFFFF) >> 14;
    fltInt16 |= ((fltInt32 & 0x7f000000) >> 26) << 10;
    fltInt16 |= ((fltInt32 & 0x80000000) >> 16);
    

    编辑:我看我的指数移位错了。。。这样会更好吗?

    fltInt16 =  (fltInt32 & 0x007FFFFF) >> 13;
    fltInt16 |= (fltInt32 & 0x7c000000) >> 13;
    fltInt16 |= (fltInt32 & 0x80000000) >> 16;
    

    编辑2:Ooops。又弄坏了。我想失去前三位而不是更低的!那么这个怎么样:

    fltInt16 =  (fltInt32 & 0x007FFFFF) >> 13;
    fltInt16 |= (fltInt32 & 0x0f800000) >> 13;
    fltInt16 |= (fltInt32 & 0x80000000) >> 16;
    

    最终代码应为 :

    fltInt16    =  ((fltInt32 & 0x7fffffff) >> 13) - (0x38000000 >> 13);
    fltInt16    |= ((fltInt32 & 0x80000000) >> 16);
    
    3 回复  |  直到 11 年前
        1
  •  4
  •   Pascal Cuoq    15 年前

    float32和float16表示中的指数可能有偏差,并且偏差不同。您需要取消从float32表示中获得的指数的偏差以获得实际指数,然后为float16表示对其进行偏差。

    除了这个细节之外,我确实认为它就这么简单,但我仍然时常对浮点表示法感到惊讶。

    编辑:

    1. 检查溢出时,做的事情与指数,而你在它。

    2. 您的算法会突然截断mantisa的最后一位,这可能是可以接受的,但您可能希望通过查看即将被丢弃的位来实现,比如说,舍入到最近的位。”0…->向下取整,“100..001…”->四舍五入,“100..00”->从圆到平。

        2
  •  7
  •   sam hocevar    14 年前

    指数需要无偏、钳制和重偏。这是我使用的快速代码:

    unsigned int fltInt32;
    unsigned short fltInt16;
    
    fltInt16 = (fltInt32 >> 31) << 5;
    unsigned short tmp = (fltInt32 >> 23) & 0xff;
    tmp = (tmp - 0x70) & ((unsigned int)((int)(0x70 - tmp) >> 4) >> 27);
    fltInt16 = (fltInt16 | tmp) << 10;
    fltInt16 |= (fltInt32 >> 13) & 0x3ff;
    

    使用指数的查找表,这段代码会更快,但我使用这段代码是因为它很容易适应SIMD工作流。

    • 无法在float16中表示的溢出值将给出未定义的值。
    • 2^-15 2^-14 而不是零。
    • 非规格化将给出未定义的值。

    小心非规范化。如果您的体系结构使用它们,它们可能会极大地降低您的程序速度。