【问题标题】:How does Cpp work with large numbers in calculations?Cpp 如何在计算中处理大数?
【发布时间】:2021-06-19 10:52:24
【问题描述】:

我有一个代码尝试使用梯形规则的方法以数值方式求解给定区间内的函数积分(参见Trapezoid method 中的公式),现在,对于区间中的函数 sin(x) [-pi/2.0,pi/2.0],等待积分为零。

在这种情况下,我将分区数 'n' 设为 4。问题是,当我有 20 位小数的 pi 时,它是零,有 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;
}

【问题讨论】:

  • M_PI 是一个东西。
  • @tadman 或更现代的std::numbers::pi_v(如果有)。
  • 你在问为什么使用不同的 Pi 值会导致不同的结论?是的,它可能会这样做。
  • @Brian 鉴于它使用 MinGW,可能需要十年时间。
  • 我想说的是,当使用更精确的 pi 值时,可以期望得到更精确的积分(在这种情况下更接近于零),但事实并非如此,因为,例如, pi= 3.141 得到零,而用 14 位小数定义的 pi 则不同。

标签: c++ decimal dev-c++ integral


【解决方案1】:

OP 正在将 y=sin(x)-a 集成到 +a。各种测试使用不同的a 值,均接近 pi/2。

该方法使用接近 -1.0 的值的线性求和,下降到 0,然后上升到接近 1.0。

此总和对最后一项的计算误差很敏感,因为最终的数学总和预计为 0.0。由于开始/结束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 的形成。可以尝试以下方法以形成x 对称约 0.0。比较完全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)));

【讨论】:

  • 我明白了,感谢您的回答,唯一不清楚的是为什么按 k=1,3,2 的顺序求和更稳定。我看不出有什么区别。
  • n==4x=f(k=2) --&gt; 0的情况下,没有区别,但考虑n = 100。代码将大量值添加到 negated 然后稍后。为了保持精度,sum 需要额外的位。 x 怎么样? x0+(1*delta_x) 是否与 x0+(3*delta_x) 完全相同?
  • 据我所知,x0+(1*delta_x) 的值与x0+(3*delta_x) 的值相同,n==100 也是如此。那么问题就像你提到的那样,在x=f(k)的形成中,这可能与负号有关吗?哪个会占用一些内存“改变”负分量的实际值?
  • “我所看到的,x0+(1*delta_x) 的值与 x0+(3*delta_x) 的值相同”--> 通过分析或者您是否编写了代码来确认完全等价?
  • 你是对的。 3*delta_x 引入了舍入误差。以#include&lt;iomanip&gt;cout&lt;&lt;fixed&lt;&lt;setprecision(25)&lt;&lt;"Expected value for x0+delta_x ="&lt;&lt;-pi/4&lt;&lt;endl; cout&lt;&lt;fixed&lt;&lt;setprecision(25)&lt;&lt;"Actual value of x0+delta_x = "&lt;&lt;x0+delta_x&lt;&lt;endl; cout&lt;&lt;fixed&lt;&lt;setprecision(25)&lt;&lt;"Expected value for x0+3delta_x ="&lt;&lt;pi/4&lt;&lt;endl; cout&lt;&lt;fixed&lt;&lt;setprecision(25)&lt;&lt;"Actual value of x0+3delta_x = "&lt;&lt;x0+3*delta_x&lt;&lt;endl; 结尾,对于 pi 的不同测试,这很清楚。谢谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-06
  • 1970-01-01
  • 2021-11-29
  • 1970-01-01
  • 2014-01-23
  • 1970-01-01
相关资源
最近更新 更多