电脑精度:我什么时候该担心?

时间:2013-05-02 18:39:57

标签: c++ precision double-precision

在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),而SMALL被定义为非常小的值,例如1E-30
  4. 最后,小扰动会导致负值吗?因为如果可能的话,我应该更好地使用if (abs(SUM) < SMALL)
  5. 有经验吗?

2 个答案:

答案 0 :(得分: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的准确值是.0292。但是b2轮到11.2和4ac轮到11.1,因此是最终答案   是.1这是一个70 ulps的错误,即使11.2 - 11.1正是如此   等于.16。减法没有引入任何错误,而是   暴露了早期乘法中引入的误差。

     

在减去确切已知的数量时会发生良性取消。   如果x和y没有舍入误差,则通过定理2得到   用保护数字进行减法,差值x-y非常大   相对误差小(小于2)。

     

有时会出现灾难性取消的公式   重新安排以消除问题。再次考虑二次方   式

答案 1 :(得分:1)

对于您的具体示例,0具有精确表示为double,并且将0精确地添加到double不会更改其值。

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

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