【问题标题】:Newton-Raphson in CC中的牛顿-拉夫森
【发布时间】:2016-04-16 12:02:50
【问题描述】:

我正在编写一个程序来使用 C 中的 Newton-Raphson 方法找到给定整数 n 的平方根的近似值。我使用了以下公式:

这是我的代码:

#include <stdio.h>

double newton_raphson(int n, int iter);

double newton_raphson(int n, int iter)
{
    if(iter == 0) // base case
        return 1;
    else // iterative case
        return (1/2*(newton_raphson(n, iter-1) + n/(newton_raphson(n, iter-1))));
}

int main()
{
    int n;
    int i;

    printf("Enter a number you want to know the square root of:\n");
    fflush(stdout);
    scanf("%d", &n);
    printf("Enter number of iterations to be worked out:\n");
    fflush(stdout);
    scanf("%d", &i);

    printf("%.3f", newton_raphson(n,i-1));

    return 0;
}

当我输入 2 和 3,预期输出为 1.417(3 次迭代后 2 的平方根)时,我得到错误 -1.#IO。例如,当我输入 5 和 2 时,我得到 0.000。我已经对其进行了调试,但仍然无法真正弄清楚问题所在。非常感谢任何帮助。

编辑:详细说明输出

【问题讨论】:

  • 1/2改为1.0/2.0以强制使用双精度数(或使用0.5)
  • 你忘记了一些事情。最明显的是您输入的内容,否则我们无法重现您的问题。
  • 抛开 int 与 float 的问题不谈,您使用相同的参数递归调用 newton_raphson 两次,这将导致调用次数超出您的需要。调用一次并将结果存储在变量中,然后对其进行操作。您也可以将算法呈现为循环而不是使用递归。
  • @StefaniaDamato :这是非常低效的,你的讲师应该注意到这一点并给你更少的分数。如果这有助于将其可视化,那么您在这里所拥有的大致相当于 int fib(int n) { if(n &gt;= 2) return fib(n-1) + fib(n-2); }
  • 在 Newton-Raphsen 函数的开头放置一个 print 语句,您会看到对于您的迭代,您调用了该函数七次。通常,您调用该函数 2^iter - 1 次。第二个调用是多余的,因为它再次评估相同的数据。结果是formulas are pretty,但您通常无法逐字逐句输入它们以获得您想要的。

标签: c


【解决方案1】:

您的问题似乎是您对浮点运算处理不当。

  1. newton_raphson 函数的第一个参数应该是double,尤其是因为您似乎在递归调用它。就像现在一样,您只需将一次迭代的结果转换为整数并将其传递给下一次迭代。

  2. 1 / 2 使用整数运算。那应该是0.51.0 / 2.0。请注意,在整数运算中,1 / 20。您看到的错误是因为您将 0 传递给下一次迭代,然后除以 0

固定代码

#include <stdio.h>

double newton_raphson(double n, int iter);

double newton_raphson(double n, int iter)
{
    if (iter == 0) {
        return 1;
    }
    else {
        return 0.5 * (newton_raphson(n, iter - 1) + n/(newton_raphson(n, iter - 1)));
    }
}

int main()
{
    int n;
    int i;

    printf("Enter a number you want to know the square root of:\n");
    fflush(stdout);
    scanf("%d", &n);
    printf("Enter number of iterations to be worked out:\n");
    fflush(stdout);
    scanf("%d", &i);

    printf("%.3f\n", newton_raphson(n, i - 1));

    return 0;
}

可能的改进

正如其他人在 cmets 中指出的那样,您可以让这个实现更加高效。

首先,您可以通过将结果保存在变量中来消除函数调用。由于这是一个递归函数,如果您有很多迭代,这将为您节省 很多 执行时间。

double newton_raphson(double n, int iter)
{
    if (iter == 0) {
        return 1;
    }
    else {
        double xk = newton_raphson(n, iter - 1);
        return 0.5 * (xk + n / xk);
    }
}

然后,您可以完全消除递归。如果您运行多次迭代,这将使您的程序消耗更少的内存,因为您摆脱了不必要的堆栈操作。

double newton_raphson(double n, int iter)
{
    int k;
    double xk = 1;
    for (k = 0; k < iter; k++) {
        xk = 0.5 * (xk + n / xk);
    }
    return xk;
}

更多提示

对于迭代计数,您应该使用unsigned int(或简单的unsigned)而不是int。运行负数的迭代是没有意义的,例如。你不能运行-5 迭代......所以你不需要一个有符号整数。

#include <stdio.h>

double newton_raphson(double n, unsigned iter);

double newton_raphson(double n, unsigned iter)
{
    unsigned k;
    double xk = 1;
    for (k = 0; k < iter; k++) {
        xk = 0.5 * (xk + n / xk);
    }
    return xk;
}

int main()
{
    int n;
    unsigned i;

    printf("Enter a number you want to know the square root of:\n");
    fflush(stdout);
    scanf("%d", &n);
    printf("Enter number of iterations to be worked out:\n");
    fflush(stdout);
    scanf("%u", &i);

    printf("%.3f\n", newton_raphson(n, i - 1));

    return 0;
}

还有几件事:

  • 通过检查函数的参数或可能返回零的函数调用的结果,通常可以防止代码被零除错。
  • 您可能应该检查输入的负数,并告诉用户负数不是您可以使用此算法计算平方根的值。
  • 对于输入,您可以允许用户输入浮点数而不是整数。

【讨论】:

  • 考虑到浮点除法成本高,更实用的方法是先计算逆squire root,然后乘以得到squire root。
猜你喜欢
  • 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
相关资源
最近更新 更多