【问题标题】:Boole's rule for N intervals (C)N 个区间的布尔规则 (C)
【发布时间】:2014-10-23 05:06:25
【问题描述】:

我正在尝试使用此公式 在 n 个间隔上实现布尔规则

到目前为止,我已经开发了这段代码:

//f = function on the range [a,b] n = number of intervals
long double booles(long double (*f) (long double), 
                double a, double b, int n) 
{
  long double sum=7*f(a); //because the starting value is not doubled 
  long double h = (b - a)/(n-1); //width of each interval
  int mod;
  int i =1;
  while (i<n-1)
    {
      mod = i%4;
      if (mod==0)
        sum+=14*f(a+i*h);
      else if (mod==1)
        sum+=32*f(a+i*h);
      else if (mod==2)
        sum+=12*f(a+i*h);
      else
        sum+=32*f(a+i*h);
      ++i;
    }
  return 2* h/45 * sum;
}

这将运行并给出一个体面的答案,但它不在 Bool 错误的规则之内,即错误是 。 我解决了将第一项加倍的问题,但我不确定如何在循环结束附近解决可能的加倍问题。此外,误差相对较大,我不认为我唯一的问题是最后四个术语。

【问题讨论】:

  • 完成编辑我最后的答案是代码,您的代码有错误您的系数与公式不匹配... mod==0 大小写应该是7.0* 而不是@987654328 @ ...顺便说一句,这应该标记为您正在使用的C++ ++i;
  • @Spektre 不幸的是,如果我只循环计算一次,这才是正确的。我需要布尔规则的一次迭代的结束与下一次迭代的开始重叠。这是 Simpson 的 3/8 规则来证明重叠的必要性(当没有被循环通过时)![1] (upload.wikimedia.org/math/3/0/0/…)(当被循环通过时)!(2)[upload.wikimedia.org/math/7/5/c/…

标签: c++ c math floating-point-precision integral


【解决方案1】:
  1. 长双

    Wiki 说: 扩展精度浮点类型。未指定实际属性。与 float 和 double 类型不同,它可以是 80 位浮点格式、非 IEEE“双双”或 IEEE 754 四精度浮点格式(如果提供了更高的精度格式),否则与双倍的。有关详细信息,请参阅关于 long double 的文章。

    • 所以很难说你实际使用的是什么数据类型(我更喜欢使用双精度)
  2. 常量

    您将整数和浮点数混合在一起,因此编译器必须决定使用什么。将所有浮点数重写为 4545.0 以确保正确完成或 a+i*h ...i 是 int 并且 h 是 double ...

  3. 整合

    不知道你的值的总和和范围的大小,但为了提高浮动精度,你应该避免将大小值加在一起,因为如果指数相差太大,你就会失去太多相关性尾数位。

    所以在两个变量中求和,就像这样(在 C++ 中):

    double suml=0.0,sumh=0.0,summ=1000.0;
    for (int i=0;i<n;i++)
     {
     suml+=...; // here goes the formula
     if (fabs(suml)>summ) { sumh+=suml; suml=0; }
     } sumh+=suml; suml=0;
    // here the result is in sumh
    
    • summ 是 suml 的最大值。与总和迭代值相比,它应该在相对安全的范围内,例如 100-10000 倍于平均值。

    • suml 是低幅度和变量

    • sumh 是大的和变量

    如果你的求和值的范围真的很大,那么你可以添加另一个如果

    if (fabs(value)>summ) sumh+=value; else suml+=value;
    

    如果它更大,那么您可以以相同的方式对任意数量的变量求和,只需将值范围划分为某个含义的完整范围

  4. 公式

    可能是我遗漏了一些东西,但你为什么要改装?如我所见,您根本不需要循环,而且 ifs 也已过时,那么为什么要使用 a+i*h 而不是 a+=h?它将提高性能和精度

    类似这样的:

    double sum,h;
    h = (b-a)/double(n-1);
    sum = 7.0*f(a); a+=h;
    sum+=32.0*f(a); a+=h;
    sum+=12.0*f(a); a+=h;
    sum+=32.0*f(a); a+=h;
    sum+= 7.0*f(a); a+=h;
    return 2.0*h*sum/45.0;
    // + the thing in the bullet 3 of coarse ...
    // now I see you had an error in your constants !!!
    

[edit1] 已实施除法(不是四倍)

//---------------------------------------------------------------------------
double f(double x)
    {
//  return x+0.2*x*x-0.001*x*x*x+2.0*cos(0.1*x)*tan(0.01*x*x)+25.0;
    return x+0.2*x*x-0.001*x*x*x;
    }
//---------------------------------------------------------------------------
double integrate_rect(double (*f)(double),double x0,double x1,int n)
    {
    int i;
    double s=0.0,x=x0,dx=(x1-x0)/double(n-1);
    for (i=0;i<n;i++,x+=dx) s+=f(x);
    return s*dx;
    }
//---------------------------------------------------------------------------
double integrate_Boole(double (*f)(double),double x0,double x1,int n)
    {
    n-=n%5; if (n<5) n=5;
    int i;
    double s=0.0,x=x0,dx=(x1-x0)/double(n-1);
    for (i=0;i<n;i+=5)
        {
        s+= 7.0*f(x); x+=dx;
        s+=32.0*f(x); x+=dx;
        s+=12.0*f(x); x+=dx;
        s+=32.0*f(x); x+=dx;
        s+= 7.0*f(x); x+=dx;
        }
    s*=(2.0*dx)/(45.0);
    return s*1.25; // this is the ratio to cover most cases
    }
//---------------------------------------------------------------------------
void main()
    {
    int n=100000;
    double x0=0.0,x1=+100.0,i0,i1;
    i0=integrate_rect (f,x0,x1,n); cout << i0 << endl;
    i1=integrate_Boole(f,x0,x1,n); cout << i1 << endl << i0/i1;
    }
//---------------------------------------------------------------------------

我主要使用矩形规则,因为 FPU 是最快和最精确的方法。更高级的方法在纸面上效果更好,但在计算机上增加的开销和舍入通常比矩形规则的精度更慢/精度更低

【讨论】:

  • 感谢您的回答,我正在修改,因为我想将 [a,b] 分解为 n,所以假设为 [1,0]。如果 N = 12,我将在较小的范围内进行 4 次布尔规则迭代。通过具有较小的范围,我的误差项中的 H 值会更小(请参阅我帖子底部的误差方程)。但是,我尝试对我的代码进行更改,这将错误项从大约 1.8645 * 10^-6 提高到 0.62831。我相信你不能做第二个 7*f,因为如果有意义的话,你必须让你的开始和结束在算法内部重叠。
  • 请参阅我在 cmets 部分中对您的答案发表的评论,以进一步解释重叠。
  • @CodeMonkey 1. 你的 n 是常数 n=5 那么为什么它在标题中并且它具有正确的值? 2. 我的代码代表你在 OP 中的方程(那里没有循环),所以如果你需要一个不同的方程,那么你应该将它包含在你的帖子中。 3. 改变方程中的系数来纠正解决方案不是一个好主意(如果你必须自己推导出方程,那么在数学/几何上而不是经验上去做!!!否则它不适用于所有可能的输入)
  • @CodeMonkey 你也计算过你输入的错误应该是什么?希望您知道 f(6)(c) 表示 f(x) 由 x 的第 6 次推导...您的输入函数和区间是什么?
  • @CodeMonkey 很好奇并根据矩形规则对其进行了测试,Boode 规则给出了非常奇怪的结果输入函数/间隔的约束是什么?这看起来像一些推导/集成快捷方式而不是几何,因此它可能不适用于任何给定的功能
猜你喜欢
  • 2013-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
相关资源
最近更新 更多