软件模拟的 IEEE 浮点数/双精度数很慢,因为需要检查和正确处理许多边缘情况。
- +/-无穷大输入
- 输入中的非数字
- +/-0 输入
- 输入中的规范化与非规范化数字以及尾数中的隐式“1”
- 拆箱包装
- 规范化/非规范化
- 不足和溢出检查
- 正确的舍入,这可能导致额外的(反)规范化和/或下溢/溢出
如果您将上述内容粗略地算作一些原始微操作(列表中的每个项目为 1),您将接近 10。在最坏的情况下还会有更多。
因此,如果您对 IEEE 兼容的浮点运算感兴趣,预计每个模拟运算都比其对应的整数运算慢 30 倍(CodesInChaos 的评论是及时的,每次加法/乘法需要 38 个时钟)。
您可以通过选择浮点格式来减少一些角落:
- 只有一个零
- 没有非数字
- 仅归一化数字
- 尾数中没有隐含的“1”
- 指数和尾数各占整数个字节
- 无或原始舍入
- 可能,没有无穷大
- 可能,2的补码尾数
- 可能,没有指数偏差
定点算术可能会变得更加高效。但它通常的问题是您必须事先知道输入和中间结果的所有范围,以便您可以选择正确的格式以避免溢出。您可能还需要支持多种不同的定点格式,例如 16.16、32.32、8.24、0.32。C++ 模板可能有助于减少此处的代码重复。
无论如何,你能做的最好的事情就是定义你的问题,用浮点和定点算法解决它,观察两者中哪一个最适合哪个 CPU 并选择获胜者。
编辑:对于更简单的浮点格式的示例,请查看MIL-STD-1750A 的 32 位浮点格式:
MSB LSB MSB LSB
------------------------------------------------------------------
| S| Mantissa | Exponent |
------------------------------------------------------------------
0 1 23 24 31
浮点数表示为小数尾数乘以 2 的指数次方。在浮点运算开始时,所有浮点数都被假定为归一化或浮点零,并且所有浮点运算的结果都被归一化(归一化的浮点数具有尾数的符号和相反值的下一位)或浮点零。浮点零定义为 0000 0000 16,即零尾数和零指数 (00 16 )。扩展浮点零定义为 0000 0000 0000 16,即零尾数和零指数。32 位浮点数的机器表示示例:
十进制数十六进制表示法
(尾数 x Exp)
0.9999998 x 2 127 7FFFFF 7F
0.5 x 2 127 400000 7F
0.625 x 2 4 500000 04
0.5 x 2 1 400000 01
0.5 x 2 0 400000 00
0.5 x 2 -1 400000 法郎
0.5×2 -128 400000 80
0.0 x 2 0 000000 00
-1.0 x 2 0 800000 00
-0.5000001 x 2 -128 BFFFFF 80
-0.7500001 x 2 4 9FFFFF 04