半精度muliplication似乎产生了错误的结果

时间:2017-07-25 06:14:47

标签: c++ precision numeric ieee-754

首先,IEEE754半精度浮点数使用16位。它使用1位符号,5位指数和10位尾数。实际值可以计算为符号* 2 ^(指数-15)*(1 + mantisa / 1024) 我尝试使用半精度运行图像检测程序。原始程序使用单精度(= float)。我在http://half.sourceforge.net/中使用了半精度等级。使用类的一半,我至少可以运行相同的程序。(通过使用half而不是float并使用g ++而不是gcc进行编译,并且经过许多类型的铸件...)
我发现了乘法似乎错误的问题。

这里是查看问题的示例代码(要打印半精度数,我应该将其转换为float以查看值。并且自动转换不会在half和integer的操作中发生所以我放了一些铸件..):

#include <stdio.h>
#include "half.h"
using half_float::half;
typedef half Dtype;

main()
{
#if 0 // method 0 : this makes sx 600, which is wrong.

int c = 325;
Dtype w_scale = (Dtype)1.847656;
Dtype sx = Dtype(c*w_scale);
printf("sx = %f\n", (float)sx);  // <== shows 600.000 which is wrong.

#else  // method 1, which also produces wrong result..

int c = 325;
Dtype w_scale = (Dtype)1.847656;
Dtype sx = (Dtype)((Dtype)c*w_scale);
printf("sx = %f\n", (float)sx);
printf("w_scale specified as 1.847656 was 0x%x\n", *(unsigned short *)&w_scale);

#endif
}

结果如下:

w_scale = 0x3f63
sx = 600
sx = 0x60b0

但是sx应该是325 * 1.847656 = 600.4882。有什么不对?

ADD:当我第一次发布这个问题时,我并没有预料到这个值恰好是600.4882,而是接近它的某个地方。我后来发现了半精度,其限制只表示3~4个有效数字,多重的最接近的值恰好是600.00。虽然大家都知道浮点有这种局限,但有些人会因为忽略半精度只有3~4个有效数字的事实会像我一样犯错误。所以我认为这个问题值得一看未来的问题。 (在stackoverflow中,我认为有些人只是将每个问题都视为同一个老问题,当它实际上是一个稍微不同的情况时。如果有一些类似的问题并不会造成伤害。)

1 个答案:

答案 0 :(得分:0)

我弄明白了为什么。半精度具有大约log10(2 ^ 10)~3或4位的有效精度。我希望sx打印为600.488或接近但是这不能用半精度表示。 这部分来自图像预处理,可以在没有16位精度的情况下完成(我们的暂定硬件),所以我可以在这个阶段使用浮点运算。
ADD:这种异常在图像尺寸计算过程中出现,我们没有任何理由在这种情况下使用16位浮点数。只是图像数据(像素或要素图数据)应该使用16位浮点数。写完之后,这是一般规则。