【问题标题】:newton raphson in CC中的牛顿拉夫森
【发布时间】:2012-11-13 16:18:43
【问题描述】:

我已经实现了用于在 C 中查找根的牛顿拉夫森算法。我想在不进入 nan 的情况下尽可能打印出最准确的根近似值。我的策略是while (!(isnan(x0)) { dostuff(); } 但这会继续多次打印出结果。理想情况下,我想设置一个范围,以便在我的情况下,当前一个电流小于某个范围 .000001 时,每个计算的 x 截距近似值之间的差异将停止。我在下面有一个可能的实现。当我输入 2.999 时只需要一步,但是当我输入 3.0 时需要 20 步,这对我来说似乎不正确。

(当我输入3.0时)

λ newton_raphson 3 2.500000 2.250000 2.125000 2.062500 2.031250 2.015625 2.007812 2.003906 2.001953 2.000977 2.000488 2.000244 2.000122 2.000061 2.000031 2.000015 2.000008 2.000004 2.000002 2.000001 进行了 20 次操作来逼近 2.000002 的正确根 在 0.000001 范围内

(当我输入 2.999 时)

λ newton_raphson 2.999 进行了 1 次操作来逼近 2.000000 的正确根 在 0.000001 范围内

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define RANGE 0.000001


double absolute(double number)
{
    if (number < 0) return -number;
    else return number;
}

 double newton_raphson(double (*func)(double), double (*derivative)(double), double x0){
    int count;
    double temp;
    count = 0;
    while (!isnan(x0)) {
            temp = x0;
            x0 = (x0 - (func(x0)/derivative(x0)));
            if (!isnan(x0))
                printf("%f\n", x0);
            count++;
            if (absolute(temp - x0) < RANGE && count > 1)
                break;
    }
    printf("Took %d operation(s) to approximate a proper root of %6f\nwithin a range of 0.000001\n", count, temp);
    return x0;
 }


/* (x-2)^2 */
 double func(double x){ return pow(x-2.0, 2.0); }
/* 2x-4 */
 double derivative(double x){ return 2.0*x - 4.0; }

 int main(int argc, char ** argv)
 {
   double x0 = atof(argv[1]);
   double (*funcPtr)(double) = &func; /* this is a user defined function */
   double (*derivativePtr)(double) = &derivative; /* this is the derivative of that function */

   double result = newton_raphson(funcPtr, derivativePtr, x0);
   return 0;
 }

【问题讨论】:

  • 我知道这可能不是生产代码,但请在使用它们之前使用检查参数,例如if (NULL == argv[1]) { ... print help ... ; return 0; }。否则你的程序没有参数的段错误。
  • 您在计算中使用了双精度,但未显示 printf() 中的所有数字。将格式字符串更改为 "%.15f\n" 以获得更多数字。

标签: c algorithm numerical-methods


【解决方案1】:

你打电话给trunc(x0),这会将2.999变成2.0。自然,当您从正确的答案开始时,就不需要迭代了!换句话说,虽然您打算使用2.999 作为您的起始值,但您实际上使用了2.0

只需删除对trunc() 的调用。

【讨论】:

  • 不客气。我花了惊人的时间自己发现它!
  • 我想总结一下(没有双关语),非常感谢。
【解决方案2】:

值得指出:采取 20 步收敛是异常;因为您正在收敛到多重根,所以收敛只是线性的,而不是牛顿-拉夫森在一般情况下给出的典型二次收敛。您可以通过每次迭代将错误减半这一事实看出这一点(使用通常的二次收敛,每次迭代您将获得两倍的正确数字,并且收敛速度要快得多)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    • 2012-04-18
    • 2018-07-29
    • 2022-01-10
    • 2015-03-04
    • 1970-01-01
    相关资源
    最近更新 更多