Cpp 在计算中如何处理大数?
How does Cpp work with large numbers in calculations?
我有一个代码尝试使用梯形法则(请参阅 Trapezoid method 中的公式)以数值方式求解给定区间内函数的积分,现在,对于函数 sin(x )在区间[-pi/2.0,pi/2.0]内,等待积分为零。
在这种情况下,我将分区数 'n' 设为 4。问题是当我的 pi 有 20 位小数时它是零,有 14 位小数时它是 8.72e^( -17),则小数点后11位为零,小数点后8位为8.72e^(-17),小数点后3位为零。我的意思是,对于 pi 的不同近似值,积分为零或接近零的数字,但它没有明确的趋势。
非常感谢您帮助我理解为什么会发生这种情况。 (我在 Dev-C++ 中做到了 运行)。
#include <iostream>
#include <math.h>
using namespace std;
#define pi 3.14159265358979323846
//Pi: 3.14159265358979323846
double func(double x){
return sin(x);
}
int main() {
double x0 = -pi/2.0, xf = pi/2.0;
int n = 4;
double delta_x = (xf-x0)/(n*1.0);
double sum = (func(x0)+func(xf))/2.0;
double integral;
for (int k = 1; k<n; k++){
// cout<<"func: "<<func(x0+(k*delta_x))<<" "<<"last sum: "<<sum<<endl;
sum = sum + func(x0+(k*delta_x));
// cout<<"func + last sum= "<<sum<<endl;
}
integral = delta_x*sum;
cout<<"The value for the integral is: "<<integral<<endl;
return 0;
}
OP 正在将 y=sin(x)
从 -a
整合到 +a
。各种测试使用不同的 a
值,都接近 pi/2.
该方法使用 -1.0 附近的值的线性求和,下降到 0,然后上升到接近 1.0。
此求和对最后一项的计算误差很敏感,因为最终的数学求和预计为 0.0。由于 start/end a
不同,错误也不同。
一个更稳定的结果是首先添加极端的 f = sin(f(k))
值。例如sum += sin(f(k=1))
,然后是 sum += sin(f(k=3))
,然后是 sum += sin(f(k=2))
而不是 k=1,2,3。特别是术语 x=f(k=3)
的形成可能与其 x=f(k=1)
较早的术语的负面影响有点不同,进一步使问题复杂化。
欢迎来到数值分析世界
如果代码使用全部 float
或全部 long double
,则存在问题,只是程度不同。
问题不是因为使用了不精确的 pi 值(对于 FP 不可能有精确值,因为 pi 是无理数,而所有有限的 FP 都是有理数)。
很大程度上要归功于 x
的形成。可以尝试下面的方法来形成关于 0.0 对称的 x
。比较 完全 x
以这种方式生成与 x
原始方式。
x = (x0-x1)/2 + ((k - n/2)*delta_x)
打印出准确的计算值以加深理解。
printf("x:%a y:%a\n", x0+(k*delta_x), func(x0+(k*delta_x)));
我有一个代码尝试使用梯形法则(请参阅 Trapezoid method 中的公式)以数值方式求解给定区间内函数的积分,现在,对于函数 sin(x )在区间[-pi/2.0,pi/2.0]内,等待积分为零。
在这种情况下,我将分区数 'n' 设为 4。问题是当我的 pi 有 20 位小数时它是零,有 14 位小数时它是 8.72e^( -17),则小数点后11位为零,小数点后8位为8.72e^(-17),小数点后3位为零。我的意思是,对于 pi 的不同近似值,积分为零或接近零的数字,但它没有明确的趋势。
非常感谢您帮助我理解为什么会发生这种情况。 (我在 Dev-C++ 中做到了 运行)。
#include <iostream>
#include <math.h>
using namespace std;
#define pi 3.14159265358979323846
//Pi: 3.14159265358979323846
double func(double x){
return sin(x);
}
int main() {
double x0 = -pi/2.0, xf = pi/2.0;
int n = 4;
double delta_x = (xf-x0)/(n*1.0);
double sum = (func(x0)+func(xf))/2.0;
double integral;
for (int k = 1; k<n; k++){
// cout<<"func: "<<func(x0+(k*delta_x))<<" "<<"last sum: "<<sum<<endl;
sum = sum + func(x0+(k*delta_x));
// cout<<"func + last sum= "<<sum<<endl;
}
integral = delta_x*sum;
cout<<"The value for the integral is: "<<integral<<endl;
return 0;
}
OP 正在将 y=sin(x)
从 -a
整合到 +a
。各种测试使用不同的 a
值,都接近 pi/2.
该方法使用 -1.0 附近的值的线性求和,下降到 0,然后上升到接近 1.0。
此求和对最后一项的计算误差很敏感,因为最终的数学求和预计为 0.0。由于 start/end a
不同,错误也不同。
一个更稳定的结果是首先添加极端的 f = sin(f(k))
值。例如sum += sin(f(k=1))
,然后是 sum += sin(f(k=3))
,然后是 sum += sin(f(k=2))
而不是 k=1,2,3。特别是术语 x=f(k=3)
的形成可能与其 x=f(k=1)
较早的术语的负面影响有点不同,进一步使问题复杂化。
欢迎来到数值分析世界
如果代码使用全部 float
或全部 long double
,则存在问题,只是程度不同。
问题不是因为使用了不精确的 pi 值(对于 FP 不可能有精确值,因为 pi 是无理数,而所有有限的 FP 都是有理数)。
很大程度上要归功于 x
的形成。可以尝试下面的方法来形成关于 0.0 对称的 x
。比较 完全 x
以这种方式生成与 x
原始方式。
x = (x0-x1)/2 + ((k - n/2)*delta_x)
打印出准确的计算值以加深理解。
printf("x:%a y:%a\n", x0+(k*delta_x), func(x0+(k*delta_x)));