半精确多倍似乎会产生错误的结果

half precision muliplication seems to produce wrong result

本文关键字:错误 结果      更新时间:2023-10-16

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

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

#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 = %fn", (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 = %fn", (float)sx);
printf("w_scale specified as 1.847656 was 0x%xn", *(unsigned short *)&w_scale);
#endif
}

结果如下所示:

w_scale = 0x3f63
sx = 600
sx = 0x60b0

但 sx 应该是 325 * 1.847656 = 600.4882。可能出了什么问题?

补充:当我第一次发布这个问题时,我没想到这个值正好是 600.4882,而是接近它。后来我发现半精度,其限制是只表示 3~4 个有效数字,乘法的最接近值刚刚证明只有 600.00。虽然大家都知道浮点有这种局限性,但有些人会像我一样犯一个错误,忽略了半精度只能有3~4个有效数字的事实。所以我认为这个问题值得未来的提问者去看。(在stackoverflow中,我认为有些人只是将每个问题都视为同一个旧问题,而实际上情况略有不同。有几个类似的问题并没有什么坏处。

我想出了原因。半精度的有效精度约为log10(2^10(~3或4位。我希望将sx打印为 600.488 或接近的内容,但这不能用半精度表示。 这部分是在图像预处理过程中完成的,无需 16 位精度(我们的暂定硬件(,所以我可以在这个阶段只使用浮点运算。
补充 :这种异常是在图像尺寸计算过程中出现的,在这种情况下,我们没有任何理由使用 16 位浮点数。仅图像数据(像素或特征图数据(应使用 16 位浮点数。写了这篇文章,这是一个一般规则。