【问题标题】:Converges and diverges of Newton's method牛顿法的收敛和发散
【发布时间】:2021-11-27 20:28:15
【问题描述】:

我需要使用牛顿法找到arctan(xe)的根,并证明存在这样的“a”,如果|xe|a 方法发散,则导出方程为找 这个“a”并解决它。我写了一个程序,但不明白如何找到这个“a”。

#include <stdio.h>
#include <math.h>
double f(double x) ;
double fd(double x) ;
double newton(double x,double eps);
#define e 2.71828182845904523
int main() 
{
   double x,eps=1.e-16 ;
   printf("Enter x :") ;
   scanf("%le",&x) ; 
   printf("%le",newton(x,eps)) ;
   
    return 0;
}


double f(double x)
{
   double z ;
   z=atan(x-e);
   return z ; 
}

double fd(double x)
{
   double z ;
   z=1/((x-e)*(x-e)+1);
   return z ; 
}



double newton(double x,double eps)
{
  double x1 ;   
  
  while(1)
  {
    x1=x-f(x)/fd(x) ;
    if(fabs(x1-x)<eps) return x1 ; 
    x=x1 ;
  }
  
  return x1 ; 
}

【问题讨论】:

    标签: c floating-point newtons-method


    【解决方案1】:

    double x 在 C 中的意思是在内存中提前堆栈。如果你不用 0 填充它,它只会占用x 下的值内存。

    一个改进:double x = 0 或您想要的值。它会将 8 个字(1 个字 = 8 位)填充到 0x00000000,而不是像 0x2409caf42 或 idk 这样的随机数据

    【讨论】:

      【解决方案2】:

      f(x)/df(x) 最小化一个函数。但是,如果您将导数最小化,您实际上会找到一个根 f。

      df(x)/ddf(x).

      • 如果你使用 f(x)/df(x),最简单的方法是梯度下降:x -= 0.001*f(x)/df(x)

      【讨论】:

        【解决方案3】:

        证明存在这样的a,如果|x-e|&lt;a方法收敛

        牛顿法在近似解接近正确解时起作用。

        当候选解发散或振荡时,牛顿法会失败。

        添加发散测试(例如:a 变为非数字或无穷大)和循环迭代限制。

        使用二分搜索找到a 的上限:在近似解 (a = e) 和发散点 (a = e + 100) 之间。见下文。

        重复(对a_min, a_max 角色和初始值进行代码调整)以找到a 的下限。未显示,留给 OP 查找。 (我发现低边 a 在 1.0 到 1.5 范围内)

        int main() {
          double x, eps = 1.e-16;
          printf("Enter x :\n");
          //scanf("%le", &x);
          x = e*1.0001;
          printf("%le\n", newton(x, eps));
        
          double a_min = e;
          double a_max = e + 100.0;
          double a;
          while (1) {
            a = a_min + (a_max - a_min)/2;
            if (a == a_min) break;
            else if (a == a_max) break;
            if (a_min >= a_max) break;
            printf("a_min:%20e a_max:%20e a:%20e\n", a_min, a_max, a);
            if (isnan(newton(a, eps))) {
              a_max = a;
            } else {
              a_min = a;
            }
          }
          printf("a high side:%e\n", a);
        
          return 0;
        }
        
        double newton(double x, double eps) {
          double x1;
        
          int i;
          for (i=10; i>0; i--) {
            //printf("%2d %20e %20e %20e\n", i, x, fd(x), f(x));
            if (isnan(x)) return x;
        
            x1 = x - f(x) / fd(x);
            if (fabs(x1-x) < eps)
              return x1;
            x = x1;
          }
          return 0.0/0.0;
        }
        

        结果

        Enter x :
        2.718282e+00
        a_min:        2.718282e+00 a_max:        1.027183e+02 a:        5.271828e+01
        a_min:        2.718282e+00 a_max:        5.271828e+01 a:        2.771828e+01
        a_min:        2.718282e+00 a_max:        2.771828e+01 a:        1.521828e+01
        a_min:        2.718282e+00 a_max:        1.521828e+01 a:        8.968282e+00
        a_min:        2.718282e+00 a_max:        8.968282e+00 a:        5.843282e+00
        a_min:        2.718282e+00 a_max:        5.843282e+00 a:        4.280782e+00
        a_min:        2.718282e+00 a_max:        4.280782e+00 a:        3.499532e+00
        a_min:        3.499532e+00 a_max:        4.280782e+00 a:        3.890157e+00
        a_min:        3.890157e+00 a_max:        4.280782e+00 a:        4.085469e+00
        a_min:        4.085469e+00 a_max:        4.280782e+00 a:        4.183126e+00
        a_min:        4.085469e+00 a_max:        4.183126e+00 a:        4.134297e+00
        a_min:        4.085469e+00 a_max:        4.134297e+00 a:        4.109883e+00
        ...
        a_min:        4.104323e+00 a_max:        4.104323e+00 a:        4.104323e+00
        a high side:4.104323e+00
        

        导出方程以找到这个“a”并求解它。

        "Derive" --> dang,更有趣的模拟如上找到它。

        考虑两个x:x_lox_hi 和牛顿迭代x_better(x) = x - f(x)/f'(x)

        next_better(x_lo) == next_better(x_hi)x_lo &lt; x_hi 时,我们处于一个振荡对中。

        剩下的留给 OP。该走了。

        【讨论】:

        • 在他原来的问题中,在编辑之前,他没有初始化“x”。我认为他之前根本没有测试它来问这里。
        • @alinsoar 我之所以使用它,是因为我从 cmets 对未初始化 x 感到惊讶我只是没有写 printf、scanf 而是将 x 设置为我想要计算的值。不知道这是一个大问题。
        • @Nick_Dowson 如果您认为答案有用,您应该接受它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-07
        • 1970-01-01
        • 1970-01-01
        • 2013-10-17
        • 2017-05-05
        相关资源
        最近更新 更多