c - 如何正确实现浮点数的乘法(软件 FP)
问题描述
我的程序是关于一个给定浮点数的方法,在这个方法中我想乘或加这些浮点数。但不要像 a * b 那样相乘,我想将这些浮点数分解为它们的结构,例如符号位、指数位的 8 位和尾数的其余位。
我想实现/模拟软件浮点加法和乘法(了解更多关于 FP 硬件必须做什么)。
在程序的头部有故障:
#define SIGN(x) (x>>31);
#define MANT(x) (x&0x7FFFFF);
#define EXPO(x) ((x>>23)&0xFF);
#define SPLIT(x, s, m, e) do { \
s = SIGN(x); \
m = MANT(x); \
e = EXPO(x); \
if ( e != 0x00 && e != 0xFF ) { \
m |= 0x800000; \
} \
} while ( 0 )
#define BUILD(x, s, m, e) do { \
x = (s << 31) | (e<<23) | (m&0x7FFFFF); \
} while ( 0 )
主要外观如下:
float f = 2.3;
float g = 1.8;
float h = foo(&f, &g);
计算方法如下:
float foo(float *a, float *b) {
uint32_t ia = *(unsigned int *)a;
uint32_t ib = *(unsigned int *)b;
uint32_t result = 0;
uint32_t signa, signb, signr;
uint32_t manta, mantb, mantr;
uint32_t expoa, expob, expor;
SPLIT(ia, signa, manta, expoa);
SPLIT(ib, signb, mantb, expob);
我已经通过添加指数并乘以它们的尾数来尝试乘法,如下所示:
expor = (expoa -127) + (expob -127) + 127;
mantr = (manta) * (mantb);
signr = signa ^ signb;
新花车的归还与重建:
BUILD(result, signr, mantr, expor);
return *(float *)&result;
现在的问题是,结果是错误的。mantr 甚至需要一个非常低的负数(如果 foo 得到 1.5 和 2.4 mantr 需要 -838860800 并且结果是 2.0000000)。
解决方案
您不能只截断尾数乘法的结果,您需要取前24 位(在使用低半部分进行舍入之后)并重新归一化(调整指数)。
浮点运算保留最高有效位。 整数乘积的最高位是高位;低位是小数点后更远的位置。(术语:它是“二进制点”,而不是“小数点”,因为二进制浮点数使用基数 2(二进制),而不是 10(十进制)。)
对于标准化输入,输入有效数字中的隐式前导1
意味着用于实现 24 x 24 => 48 位尾数乘法的 32x32 => 64 位uint64_t
乘积将在 2 个可能的位置之一具有其高位,因此您不要不需要位扫描即可找到它。比较或单位测试就可以了。
对于非正常输入,这不能保证,因此您需要检查 MSB 的位置,例如使用 GNU C __builtin_clzll
。(有许多特殊情况需要处理一个或两个输入低于正常,和/或输出低于正常。)
有关 IEEE-754 binary32 格式的更多信息,包括有效数字的隐含前导 1,请参阅https://en.wikipedia.org/wiki/Single-precision_floating-point_format。
并查看@njuffa对实际测试 + 工作实现的回答,该实现出于某种原因将 64 位操作作为两个 32 位半,而不是让 C 有效地做到这一点。
此外,return *(float *)&result;
违反严格的别名。它只在 MSVC 上是安全的。在 C99 / C11 中使用 union 或 memcpy 进行类型双关。
推荐阅读
- python - 在 Google Colab 中训练更快的 rcnn 时出现“无法连接到 X 服务器”错误
- c++ - 如何在 CMake 中设置此文件夹结构?
- javascript - 自定义 API 端点和 Javascript 跟踪代码
- google-compute-engine - 从 GCP 计算引擎服务器连接到 Office VPN
- google-app-engine - 如何将 Cloud Armor 与 GAE Flex 结合使用?
- ajax - laravel:ajax请求没有可用的响应
- javascript - attr 内的变量。无法通过
- kubernetes - 在 Kubernetes 上自动化安全 CockroachDB 部署
- flutter - 我想使用颤振从 rest api 在 DropDownButton 中显示数据
- python - 无法在 discord.py 的命令中打开和写入文件两次