如何使用双精度更安全,更精确
How to use double to be more secure and precise?
两种情况下的语句在数学上是等价的。我的问题是,在编码时选择哪一个更好。哪一部分代码可能导致某些范围的变量溢出,而另一部分代码在相同范围内没有溢出。代码的哪一部分更精确,为什么?
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;
// 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);
相似,因此该案例强调求值顺序。如果子产品超出计算范围,转化为INF
或0.0
或亚正态,则根据顺序,最终产品将受到显著影响。此外,中级数学可以在更宽的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更准确。但无论用哪种方式编码,聪明的编译器都可以对两者进行广泛的乘法运算。
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 正在将csv文件读取为双精度矢量
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 如何在C++中的同一函数中使用字符串和双精度
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 检查是否以特定精度给出双精度
- 转换函数,将 std::数组的双精度作为参数或双精度作为参数单独转换
- C 字符串返回字符串的整数/双精度/长整型值
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- 如何使双精度值的 C++ 和 C# 中的结果相同
- 使用浮点数和双精度数的非常小数字的数学
- 使用 Xcode 将双精度存储在数组C++中
- 在 C++ 中将双精度变量写入二进制文件
- 如何从字符串转换为双精度*
- 为什么我的数组双精度函数不起作用?
- 高精度双精度的 Sprintf 格式化问题
- C++ cout 将双精度对齐到精度 2 并正确对齐
- 具有 IEEE 754 浮点双精度数据类型的安全往返整数值
- 如何使用双精度更安全,更精确
- 在 C++03 中通过 int 运输双精度是否安全