控制溢出和精度损失,同时乘以双倍

时间:2015-07-12 11:01:37

标签: c++ floating-point double floating-point-precision double-precision

QUES:

我有大量的浮点数(~10,000个数字),每个都有6位小数后的数字。现在,所有这些数字的乘法将产生大约60,000个数字。但双倍范围仅为15位数。输出产品必须在十进制后具有6位精度。

我的方法:

我想过将这些数字乘以10 ^ 6,然后将它们相乘,然后将它们除以10 ^ 12。

我还想过使用数组将这些数字相乘以存储它们的数字,然后将它们转换为十进制数字。但这也显得很麻烦,可能无法产生正确的结果。

还有其他更简单的方法吗?

1 个答案:

答案 0 :(得分:2)

  

我想过将这些数字乘以10 ^ 6,然后将它们相乘,然后将它们除以10 ^ 12。

这只会进一步降低准确性。在浮点数中,大数字表示大致就像小数字一样。使你的数字更大只意味着你做了19999次乘法(和一次除法)而不是9999次乘法;它并没有神奇地给你更多有效数字。

这种操作只有在阻止部分产品进入低于正常范围的情况下才有用(在这种情况下,建议乘以2的幂,以避免由于乘法而导致精度损失)。您的问题中没有迹象表明发生了这种情况,没有示例数据集,没有代码,因此只能提供以下通用解释:

浮点乘法在没有下溢或溢出时非常好。在第一个顺序中,您可以假设相对不准确性相加,因此乘以10000值会产生9999个机器epsilons相对于数学结果(*)的结果。

所述问题的解决方案(无代码,无数据集)是为中间乘法使用更宽泛的浮点类型。这解决了下溢或溢出的问题,并使您对最终结果保持相对准确性,这样一旦舍入到原始浮点类型,产品最多错误一个ULP。

根据您的编程语言,这种更广泛的浮点类型may be available as long double。对于10000次乘法,x86处理器中广泛使用的80位“扩展双”格式可以显着改善事物,只要您的编译器将此80位格式映射到浮点,您几乎看不到任何性能差异类型。否则,您将不得不使用软件实现,例如MPFR'的任意精度浮点格式或双倍格式。

(*)实际上,相对不准确性复合,因此相对误差的实际界限更像是(1 +ε) 9999 - 1其中ε是机器epsilon。而且,实际上,相对误差经常相互抵消,因此您可以预期实际相对误差会像理论最大误差的平方根一样增长。