【问题标题】:How to use double to be more secure and precise? [closed]如何使用double更安全、更精确? [关闭]
【发布时间】:2015-10-08 13:17:36
【问题描述】:

每种情况下的语句在数学上是等价的。我的问题是在编码时选择哪一个更好。代码的哪一部分可能导致某些变量范围的溢出,而另一部分对于相同的范围没有溢出。代码的哪一部分更精确,为什么?

double x, y, z;

//case 1
x = (x * y) * z;
x *= y * z;

//case 2
z = x + x*y;
z = x * ( 1.0 + y);

//case 3
y = x/5.0;
y = x*0.2;

【问题讨论】:

  • 你应该阅读浮点运算。通过简单的搜索即可找到足够的信息。
  • 如果您的项目需要通过强制执行某种编码风格来最大化浮点精度,那么可能会出现问题。
  • What Every Computer Scientist Should Know About Floating-Point Arithmeticx/5.0 会更精确,因为 0.2 不能用二进制浮点表示,但 x*0.2 会更快
  • "...由于上溢和下溢问题而安全" 除非您知道要处理的数字有多大,否则这是没有意义的。您的意思是问哪些行可能存在浮点不准确问题?
  • 例如,(0.000001 * 100000000) * 10000000 不会导致我的计算机溢出,而 0.000001 * (100000000 * 10000000) 会。我还想考虑浮点数的不准确性。

标签: c++ c double overflow underflow


【解决方案1】:
// Case 1
x = (x * y) * z;
x *= y * z;

// Case 2
z = x + x*y;
z = x * ( 1.0 + y);

// Case 3
y = x/5.0;
y = x*0.2;

案例 1:x *= y * z; 就像 x = x * (y * z); 所以这个案例强调评估顺序。如果任一子产品超出计算范围并转换为INF0.0 或低于正常值,最终产品将根据订单受到显着影响。 OTOH,可以在更广泛的 FP 类型上执行中级数学。搜索FLT_EVAL_METHOD。在这种情况下,如果所有计算都以long double 完成,则顺序可能无关紧要。

案例 2:两种形式略有不同。第二个在数字上更稳定,因为加法/减法使用精确值:1, y 与第一个 x, x*y 相比,x*y 可能是一个四舍五入的答案。加法/减法容易导致严重的精度损失——在这种情况下,当y 接近-1.0 时。与案例 1 一样,更广泛的中级数学会有所帮助,但第二种形式仍然更好。

C11 (C99?) 提供fma(double x, double y, double z) 并使用fma(x, y, x) 将是另一个不错的选择。

fma 函数计算 (x × y) + z,作为一个三元运算四舍五入:它们根据当前的舍入模式将值(好像)计算为无限精度并舍入一次到结果格式。可能会出现范围错误。

案例 3:

这里的“诀窍”是double 0.2 和数学0.2 一样吗?通常它不是——但它们很接近。然而,优化编译可以 1)将它们视为相同或 2)或在情况 1 中,使用更广泛的数学。那么这两行代码的结果是一样的。

否则:根据舍入模式,这两种形式可能会在最低位 (ULP) 中表现出差异。使用弱编译器,推荐/5.0

除以 5.0 比乘以大约 0.2 更准确。但无论采用哪种方式编码,智能编译器都可以使用两者进行宽乘。

【讨论】:

  • 我不明白你为什么说x * ( 1.0 + y )x + x*y )更精确第一个使用近似值x*yx,而第二个使用近似值@987654343 @、y1.0 + y
  • 在我的 GCC 4.9.2 中当我选择变量 x = 1000000y = 0.001 时,结果是 x * ( 1.0 + y ) = 1000999.999...x + x*y = 1001000
  • @Mehrshad x 不是一个近似值,它是等式的一个参数。对于误差分析,假设方程/函数的参数是准确的。乘积x*y 不是参数,而是可能不准确的中间结果。加法/减法比乘法/除法对不精确的参数更敏感。因此,先执行 + 并使用精确的增强会比先执行 * 得到更精确的答案。
  • @Mehrshad 尝试了您的测试值,并使用各种代码,这两种方法彼此相差 1.0 ULP。用y near -1.0 进行了相同的测试,x * (1.0 + y) 仍然接近正确答案,而x + x*y 失去了显着的精度——y = -1 + 1e6 失去了 6 个小数位的精度。这不是哪种方法最常给出“正确”答案的问题。对于大多数数字,两者的工作方式大致相同。但是y near -1.0x + x*y 给出了显着的劣质结果。 x * (1.0 + y)没有这样的坑。
  • 泛化:最大进动损失涉及加法/减法,结果几乎抵消。最大范围问题发生在相同绝对方向上的乘法/除法链朝向 0 或 INF
猜你喜欢
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
  • 2016-06-01
  • 1970-01-01
  • 2021-02-16
  • 2013-06-17
  • 2023-02-22
  • 1970-01-01
相关资源
最近更新 更多