1

在 C++ 编程中,我什么时候需要担心精度问题?举一个小例子(虽然它可能不是一个完美的例子),

std::vector<double> first (50000, 0.0);
std::vector<double> second (first);

有没有可能second[619] = 0.00000000000000000000000000001234(我的意思是一个非常小的值)。或者SUM = second[0]+second[1]+...+second[49999] => 1e-31?或者SUM = second[0]-second[1]-...-second[49999] => -7.987654321e-12

我的问题:

  1. 在使用double类型编号时会不会有一些小干扰?
  2. 什么可能导致这些小干扰?即舍入误差变大?你能把它们列出来吗?如何采取预防措施?
  3. 如果在某些操作中可能有小干扰,是否意味着在这些操作之后,使用if (SUM == 0)危险的?然后应该始终使用if (SUM < SMALL), whereSMALL被定义为一个非常小的值,例如1E-30
  4. 最后,小扰动会导致负值吗?因为如果可能的话,那我应该更好地使用它if (abs(SUM) < SMALL)

有什么经验吗?

4

2 回答 2

4

这是一个很好的浮点精度参考文档:What Every Computer Scientist Should Know About Floating-Point Arithmetic

更重要的部分之一是灾难性取消

当操作数受到舍入错误时,会发生灾难性取消。例如,在二次公式中,出现表达式 b2 - 4ac。数量 b2 和 4ac 存在舍入误差,因为它们是浮点乘法的结果。假设它们被四舍五入到最接近的浮点数,因此精确到 0.5 ulp 以内。当它们被减去时,取消会导致许多准确的数字消失,留下的主要是被舍入误差污染的数字。因此,差异可能有许多 ulps 的错误。例如,考虑 b = 3.34、a = 1.22 和 c = 2.28。b2 - 4ac 的精确值为 0.0292。但是 b2 舍入到 11.2 和 4ac 舍入到 11.1,因此最终答案是 0.1,这是 70 ulps 的误差,即使 11.2 - 11.1 正好等于 0.16。

当减去完全已知的量时会发生良性抵消。如果 x 和 y 没有舍入误差,则根据定理 2,如果减法是使用保护位进行的,则差 xy 具有非常小的相对误差(小于 2)。

有时可以重新排列显示灾难性抵消的公式以消除问题。再次考虑二次公式

于 2013-05-02T18:45:09.140 回答
1

对于您的具体示例, 0 具有作为双精度的精确表示,并且将 0 精确添加到双精度不会改变其值。

此外,与您放入变量中的任何其他值一样,您在数组中初始化的数字不会发生神秘的变化。只有当计算结果不能精确地表示为浮点数时,才会进行舍入。

为了更好地了解“干扰”,我需要知道您的代码执行的计算类型。

于 2013-05-02T19:13:01.290 回答