Python 和 C 中梯形规则的精度
precision of trapezoidal rule in Python and C
我在 Python 中编写了集成代码,并使用梯形法则在 C 中再次编写了代码。任务是从 file 中读取数据并随着时间的推移对速度进行积分。将数据文件复制到我的工作目录后,我编译并 运行 以下程序。 C 程序给了我 8.218921,而 Python 程序给了我 8.218924000000003。这两个值小数点后6位不同
差异从何而来?
这是我的 C 程序。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int
main (void)
{
FILE *fptr;
if((fptr = fopen("velocities.txt", "r"))==NULL){
printf("cannot open the file\n");
exit(1);
}
printf("file opened\n");
int t[200] = {};
double v[200] = {};
int n = 0;
while( (fscanf(fptr, "%d\t %lf\n", &t[n], &v[n])!=EOF) && (n<200) ){
printf("%d\t %lf\n", t[n], v[n]);
n++;
}
int h = 0;
float area = 0.0;
printf("calculating the travel distance\n");
for(int i=1;i<n;i++){
h = t[i]-t[i-1];
area += (v[i]+v[i-1])*h/2;
}
printf("area : %lf\n", area);
fclose(fptr);
return 0;
}
这是 Python 个代码。
import numpy as np
arr = np.loadtxt("./velocities.txt")
arr = arr.T
h, area = 0, 0
for i in range(1, 101):
h = arr[0,i] - arr[0,i-1]
area += (arr[1,i]+arr[1,i-1])/2
print(area)
结果可能是正确的,这是由于precision with floating numbers。
几乎每种语言都会发生这种情况,您的 C 程序可能只是将它隐藏在这里。
不同之处在于,尽管 double v[200] = {};
具有双精度,但 float area = 0.0;
是一个 floating-point 数字,因此会损失一半的精度。
Python 将默认使用 double
,从而保持精度。
如您所见,floating-point 个数字很快失去精度:
#include <stdio.h>
int main()
{
float pi_flt = ((float)22)/7;
double pi_dbl = ((double)22)/7;
printf("%.8f, %.8lf\n", pi_flt, pi_dbl);
return 0;
}
编译并运行:
$ clang -Weverything test.c
test.c:9:29: warning: implicit conversion increases floating-point precision: 'float'
to 'double' [-Wdouble-promotion]
printf("%.8f, %.8lf\n", pi_flt, pi_dbl);
~~~~~~ ^~~~~~
1 warning generated.
$ ./a.out
3.14285707, 3.14285714
我在 Python 中编写了集成代码,并使用梯形法则在 C 中再次编写了代码。任务是从 file 中读取数据并随着时间的推移对速度进行积分。将数据文件复制到我的工作目录后,我编译并 运行 以下程序。 C 程序给了我 8.218921,而 Python 程序给了我 8.218924000000003。这两个值小数点后6位不同
差异从何而来?
这是我的 C 程序。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int
main (void)
{
FILE *fptr;
if((fptr = fopen("velocities.txt", "r"))==NULL){
printf("cannot open the file\n");
exit(1);
}
printf("file opened\n");
int t[200] = {};
double v[200] = {};
int n = 0;
while( (fscanf(fptr, "%d\t %lf\n", &t[n], &v[n])!=EOF) && (n<200) ){
printf("%d\t %lf\n", t[n], v[n]);
n++;
}
int h = 0;
float area = 0.0;
printf("calculating the travel distance\n");
for(int i=1;i<n;i++){
h = t[i]-t[i-1];
area += (v[i]+v[i-1])*h/2;
}
printf("area : %lf\n", area);
fclose(fptr);
return 0;
}
这是 Python 个代码。
import numpy as np
arr = np.loadtxt("./velocities.txt")
arr = arr.T
h, area = 0, 0
for i in range(1, 101):
h = arr[0,i] - arr[0,i-1]
area += (arr[1,i]+arr[1,i-1])/2
print(area)
结果可能是正确的,这是由于precision with floating numbers。
几乎每种语言都会发生这种情况,您的 C 程序可能只是将它隐藏在这里。
不同之处在于,尽管 double v[200] = {};
具有双精度,但 float area = 0.0;
是一个 floating-point 数字,因此会损失一半的精度。
Python 将默认使用 double
,从而保持精度。
如您所见,floating-point 个数字很快失去精度:
#include <stdio.h>
int main()
{
float pi_flt = ((float)22)/7;
double pi_dbl = ((double)22)/7;
printf("%.8f, %.8lf\n", pi_flt, pi_dbl);
return 0;
}
编译并运行:
$ clang -Weverything test.c
test.c:9:29: warning: implicit conversion increases floating-point precision: 'float'
to 'double' [-Wdouble-promotion]
printf("%.8f, %.8lf\n", pi_flt, pi_dbl);
~~~~~~ ^~~~~~
1 warning generated.
$ ./a.out
3.14285707, 3.14285714