[英]Numerical Procedure generating different outputs in Windows10 vs Debian GNU/Linux 10
I was playing arround with the Maehly Procedure to polish the roots of a polinomial and stumbled upon something interessing: The exact samame code gave me two really different outputs depending on the machine it was compiled on.我正在使用 Maehly 程序来完善多项式的根,并偶然发现了一些有趣的东西:根据编译它的机器,确切的相同代码给了我两个非常不同的输出。
The Code编码
#include <stdio.h>
#define MAX_ITERATION 1000
double poly(double x){
double coeff[9]={-61.688, 72.5235, 72.822, -108.519, -5.12949, 39.9139,-7.07373, -3.91823, 1.0};
double result=coeff[0];
double buffer;
for(int i=1; i<9;i++){
buffer=coeff[i];
for(int j=1;j<=i;j++){
buffer*=x;
}
result+=buffer;
}
return result;
}
double poly_der(double x){
double coeff[8]={ 72.5235, 72.822, -108.519, -5.12949, 39.9139,-7.07373, -3.91823, 1.0};
double result=coeff[0];
double buffer;
for(int i=1; i<8;i++){
buffer=coeff[i]*(i+1);
for(int j=1;j<=i;j++){
buffer*=x;
}
result+=buffer;
}
return result;
}
int main(){
double roots[8]={0.9, -1.1, 1.4, 1.4, -2.0, -2.0, 2.2, 2.2};
double factor;
double pol_eval;
//Implement Maehly-procedure
for(int i=0; i<MAX_ITERATION;i++){
for(int k=0;k<8;k++){
factor=0;
for(int j=0;j<k;j++){
factor+=1/(roots[k]-roots[j]);
}
pol_eval=poly(roots[k]);
roots[k]-=pol_eval/(poly_der(roots[k])-(pol_eval*factor));
}
}
for(int i=0;i<8;i++){
printf("\n%d: x:%0.16f poly:%e \n",i,roots[i],poly(roots[i]));
}
}
The Windows output (Windows10): Windows output(Windows10):
0: x:1.0072928773885637 poly:-8.437695e-015
1: x:-1.0004044550991309 poly:-2.375877e-014
2: x:1.3770602924650244 poly:-3.552714e-015
3: x:-2.5000428878301499 poly:0.000000e+000
4: x:-1.7318124315476966 poly:-1.136868e-013
5: x:3.0001628929552053 poly:9.094947e-013
6: x:2.2341265341600458 poly:-2.273737e-013
7: x:3.0001628929552049 poly:0.000000e+000
The Linux Output(Debian GNU/Linux 10): Linux 输出(Debian GNU/Linux 10):
0: x:1.0072928773885637 poly:-8.437695e-15
1: x:-1.0004044550991309 poly:-2.375877e-14
2: x:1.3770602924650244 poly:-3.552714e-15
3: x:-2.5000428878301499 poly:0.000000e+00
4: x:-1.7318124315476959 poly:2.842171e-14
5: x:3.0001628929552093 poly:-1.818989e-12
6: x:2.2341265341600458 poly:-2.273737e-13
7: x:1.5318471775081237 poly:0.000000e+00
The x are the polished roots of the polinomial, start values are saved in the array roots[8]
. x 是多项式的抛光根,起始值保存在数组 root roots[8]
中。
Can you help me explain this behavior and,most important, help me understand how to avoid something similar in the future?你能帮我解释一下这种行为吗,最重要的是,帮助我了解如何避免将来发生类似的事情?
We have to 2 issue, why different?我们要2个问题,为什么不同? Which is better - or may a 3rd way?哪个更好 - 或者可能是第三种方式?
OP reports different FLT_EVAL_METHOD
values of 2 and 0. This implies the Windows version is using long double
math for intermediate calculations and the Linux one is just using double
. OP 报告2 和 0 的不同FLT_EVAL_METHOD
值。这意味着 Windows 版本使用long double
数学进行中间计算,而 Linux 版本仅使用double
。 Usually the FLT_EVAL_METHOD==2
is more correct.通常FLT_EVAL_METHOD==2
更正确。
#include <float.h>
printf("%d\n", FLT_EVAL_METHOD);
FP have a weakness in subtracting values nearly the same. FP 在减去几乎相同的值方面有一个弱点。 The cancelation of many common bits leads to the slight computational errors becoming more significant.许多公共位的取消导致轻微的计算错误变得更加显着。 Different compilations may have slightly different rounded result for various reasons, although I'd _expect the same.由于各种原因,不同的编译结果可能略有不同,尽管我_expect 相同。 poly()
does that with repeated calculations to find a power of x
and then adding terms that cancel out. poly()
通过重复计算来找到x
的幂,然后添加抵消的项。
Alternative code below does far fewer calculations are certainly provide a better result for both systems.下面的替代代码所做的计算要少得多,肯定会为两个系统提供更好的结果。
double poly(double x) {
const double coeff[9] = {-61.688, //
72.5235, 72.822, -108.519, -5.12949, //
39.9139, -7.07373, -3.91823, 1.0};
double result = 0.0;
for (int i = 9; i-- > 0; ) {
result = result * x + coeff[i];
}
return result;
}
On my system FLT_EVAL_METHOD
is 0.在我的系统FLT_EVAL_METHOD
是 0。
Result of just changing poly()
.只是改变poly()
的结果。 Similar issue applies to poly_der()
.类似的问题适用于poly_der()
。
0: x:1.0072928773885645 poly:0.000000e+00
1: x:-1.0004044550991309 poly:-7.105427e-15
2: x:1.3770602924650401 poly:-2.842171e-14
3: x:3.0001628929552013 poly:3.552714e-13
4: x:-1.7318124315476964 poly:-2.842171e-14
5: x:-2.5000428878301499 poly:6.821210e-13
6: x:2.2341265341600485 poly:-7.105427e-15
7: x:1.5318471775081424 poly:3.552714e-14
Fixing both poly()
and poly_dev()
修复poly()
和poly_dev()
static const double coeff[9] = {-61.688, //
72.5235, 72.822, -108.519, -5.12949, //
39.9139, -7.07373, -3.91823, 1.0};
double poly(double x) {
double result = 0.0;
for (int i = 9; i-- > 0; ) {
result = result * x + coeff[i];
}
return result;
}
double poly_der(double x) {
double result = 0.0;
for (int i = 9; i-- > 1; ) {
result = result * x + coeff[i]*i;
}
return result;
}
Results with only double
math rival the weaker computational code using long double
math.只有double
数学的结果可以与使用long double
数学的较弱计算代码相媲美。
printf("%d: x:% 0.16f poly:% e \n", i, roots[i], poly(roots[i]));
0: x: 1.0072928773885645 poly: 0.000000e+00
1: x:-1.0004044550991309 poly:-7.105427e-15
2: x: 1.3770602924650324 poly:-4.973799e-14
3: x:-2.5000428878301495 poly:-6.394885e-13
4: x:-1.7318124315476964 poly:-2.842171e-14
5: x: 1.5318471775081377 poly: 0.000000e+00
6: x: 2.2341265341600520 poly: 0.000000e+00
7: x: 3.0001628929552009 poly:-2.771117e-13
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.