【问题标题】:Float32 to Float16浮点 32 到浮点 16
【发布时间】:2011-03-02 20:54:17
【问题描述】:

有人可以向我解释一下如何将 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);

【问题讨论】:

  • 我认为这已经被问到(并回答)了:stackoverflow.com/questions/1659440/…
  • 它可能就这么简单,但是除非 float32 不使用它所拥有的所有“精度”,否则你会失去精度......基本上,你得到 exp 的 5/7 位(你当然拿最重要的)和尾数的 10/24;这些比率以某种方式说明了您可以在转换中损失多少。如果您想将 32 位整数放入 16 位整数中,情况完全一样……可表示数字的范围更小; “切割”尾数会降低“精度”,指数也限制了范围:5个有符号位给出-16到+15,反对-64/+63(如果我做得对......:D晚了)
  • @ShinTakezou:当然不可能丢失 16 位数据而不丢失精度?? Float16 的精度要低得多,因此精度会自动降低……还是我误解了你?
  • 您可以松开 16 位并让“float16”代表“精确”相同的 float32 数字,只需“选择”float32 数字以便它发生......但通常可以'不选择,所以大多数时候发生的事情是丢失信息。换句话说,您可以将任何 float16 数字(提供相同的约定)放入 float32 并再次“返回”到 float16 没有任何损失(f16 > f32 不会“发明”“精度”,因此 f16 > f32 > f16' 可以这样做是为了 f16' === f16)

标签: c floating-point


【解决方案1】:

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

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 之间的未定义值,而不是零。
  • 非正规将给出未定义的值。

小心非规范化。如果您的架构使用它们,它们可能会大大减慢您的程序。

【讨论】:

    【解决方案2】:

    你的 float32 和 float16 表示中的指数可能有偏差,而且偏差不同。您需要对从 float32 表示中获得的指数进行无偏以获得实际指数,然后将其偏向 float16 表示。

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

    编辑:

    1. 在处理指数时检查溢出。

    2. 您的算法会稍微突然地截断尾数的最后一位,这可能是可以接受的,但您可能希望通过查看即将被丢弃的位来实现,例如,舍入到最近的位。 "0..." -> 向下取整,"100..001..." -> 向上取整,"100..00" -> 取整。

    【讨论】:

    • IEEE754 标准中的 32 位浮点数有 23 位尾数和 8 位指数。
    • @bbudge ...公平地说,我试图从记忆中做到这一点。显然,我拿错了一点;)
    【解决方案3】:

    这是 IEEE754 上一篇文章的链接,其中给出了位布局和偏差。

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

    【讨论】:

      猜你喜欢
      • 2010-12-12
      • 1970-01-01
      • 2015-06-20
      • 2011-10-25
      • 1970-01-01
      • 2020-09-04
      • 2011-12-14
      • 1970-01-01
      相关资源
      最近更新 更多