有人可以向我解释如何将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) << 10;
fltInt16 |= ((fltInt32 & 0x80000000) >> 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);
答案 0 :(得分:5)
指数需要不偏不倚,限制和重新定位。这是我使用的快速代码:
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工作流程。
实施的局限性:
2^-15
和2^-14
之间返回未定义的值,而不是零。小心非常规。如果您的架构使用它们,它们可能会极大地降低您的程序速度。
答案 1 :(得分:4)
float32和float16表示中的指数可能有偏差,偏差也不同。您需要取消从float32表示中获得的指数以获取实际指数,然后将其偏向于float16表示。
除了这个细节之外,我确实认为这很简单,但我仍然不时对浮点表示感到惊讶。
编辑:
当您使用指数时,检查是否存在溢出。
你的算法会突然切断mantisa的最后几位,这可能是可以接受的,但你可能想要通过查看即将被丢弃的位来实现,例如,舍入到最近。 “0 ......” - &gt;向下,“100..001 ......” - &gt;向上,“100..00” - &gt;圆到均匀。
答案 2 :(得分:4)
以下是关于IEEE754的文章的链接,该文章给出了位布局和偏差。