1

我编写了一个程序,看起来与我在网上看到的其他递归牛顿平方根函数非常相似。出于某种原因,这个只适用于完美的正方形,我似乎找不到原因。我尝试传递 3 个变量(epsilon),设置 x=a,将 a = 设置为第 9 行中传递的方程,然后传递 abs(a*ax)。我试图尽可能地描述它,这对我来说是一个稍微新的话题,我只是不确定这是否只能找到完美的根源,或者我的代码/方程式是否不正确。

 1  #include <cmath>
 2  #include <iostream>
 3  using namespace std;
 4
 5  double newtroot(double x, double a) {
 6      if (fabs(a*a - x) <= DBL_EPSILON)
 7          return a;
 8      else 
 9          return newtroot(x, fabs(a*a + x)/(2*a));
10  }
11
12  int main() {
13      cout << newtroot(9, 1) << endl;
14      system("pause");
15      return 0;
16  }

编辑:该函数不仅适用于完美正方形,而且仅适用于完美正方形。如果它不是一个完美的正方形a最终是正确的值(在调试器中检查)但递归永远不会停止。我认为它必须与第 6 行中的比较有关,所以我尝试将 DBL_EPSILON 替换为a并返回不正确的值。
当输入不完美的正方形时,此错误也会显示在第 6 行:

RecursionProgrammingExcercisesMurphyT.exe 中 0x00007FFE8E9C06F0 (ucrtbased.dll) 处未处理的异常:0xC00000FD:堆栈溢出(参数:0x0000000000000001、0x00000013B2603FE8)。发生了

4

1 回答 1

1

未检测到基本情况是由于过于乐观的解释:
DBL_EPSILON不是“适合终止改进任何近似值的值”,而是1
与可表示的大于 1 的最小值之间的差异
需要对其进行缩放以限制相对误差.
return (fabs(approx*approx - x) <= 2*x*DBL_EPSILON) ? approx
        : newtroot(x, fabs(approx*approx + x)/(2*approx));
当近似值足够快以容忍数值错误时,终止它的一种有希望的方法是检查新的近似值既不是当前的也不是以前的。

/*! approximate the value of x**.5 */
double newtroot(double x, double approx, double previous) {
    double next = fabs(approx*approx + x)/(2*approx);
    return next == approx || next == previous
        ? approx : newtroot(x, next, approx);
}
于 2018-02-18T14:04:19.417 回答