Float32到Float16

有人可以向我解释如何将32位浮点值转换为16位浮点值吗?

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

如果32位浮点数是1s7e24m
16位浮点数为1s5e10m

那么这么简单吗?

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

我假设它不是那么简单……所以有人能告诉我你需要做什么吗?

编辑:我看到我的指针转移错误了…所以这会更好吗?

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

我希望这是正确的。 如果我遗漏了一些明显的话,我会道歉。 它在星期五晚上几乎是午夜……所以我不是“完全”清醒;)

编辑2:哎呀。 再次惹恼了它。 我想失去前3位而不是更低! 那怎么样:

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

最终代码应该是

 fltInt16 = ((fltInt32 & 0x7fffffff) >> 13) - (0x38000000 >> 13); fltInt16 |= ((fltInt32 & 0x80000000) >> 16); 

float32和float16表示中的指数可能有偏差,偏差也不同。 您需要取消从float32表示中获得的指数以获取实际指数,然后将其偏向于float16表示。

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

编辑:

  1. 当你使用指数做事时,检查溢出。

  2. 你的算法会突然切断mantisa的最后几位,这可能是可以接受的,但你可能想要通过查看即将被丢弃的位来实现,例如,舍入到最近。 “0 ……” – >向下,“100..001 ……” – >向上,“100..00” – >向右舍入到“均匀”。

指数需要不偏不倚,限制和重新定位。 这是我使用的快速代码:

 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^-152^-14之间的未定义值,而不是零。
  • Denormals将给出未定义的值。

非常规小心。 如果您的架构使用它们,它们可能会极大地降低您的程序速度。

这是关于IEEE754的文章的链接,它提供了位布局和偏差。

http://en.wikipedia.org/wiki/IEEE_754-2008