我编写了以下代码来使用牛顿方法计算平方根,但每次运行它时它都会溢出。我自己尝试过检查,但没有发现任何错误。你能帮助我吗?
double root(double n,double init){
if(fabs(init*init-n)<=0.00001){
return init;
}else{
init=(init*init-n)/2*init;
return root(n,init);
}
}
int main()
{
double a;
cout<<"Enter any number to get its square root: ";
cin>>a;
cout<<"Square Root of "<<a<<" is: "<<root(a,2);
return 0;
}
答案 0 :(得分:1)
所以你的问题是双重的。首先,你的牛顿方法稍微偏离(这是一个更大的问题)。其次,你实现它的方式导致溢出。
其他答案似乎忽略了这一点,即使这是一个更大的问题。计算机可以处理小数字的平方溢出,例如计算9的平方根时,但是你的方法甚至对它们都不起作用。这是因为,正如我在评论中提到的,你的牛顿方法略有偏差。
你应该在这一行中使用加号而不是减号(尝试重新发现以了解原因):
init=(init*init+n)/(2*init);
推导:
x_{k+1} = x_k - f(x_k)/f'(x_k)
= x_k - ((x_k)^2 - n)/(2x_k)
= x_k - 1/2*x_k + n/(2x_k) // note the + here
= 0.5*x_k + 0.5*n/x_k
= 0.5*(x_k + n/x_k)
其中x_k
是您的init
变量。
执行init*init
会导致数字过快增长并溢出(更大的数字会出现更多错误)。您可以将其代数重写为:
init=0.5*(init + n/init);
把它们放在一起:
#include <iostream>
#include <cmath>
using namespace std;
double root(double n,double init){
if(fabs(init*init-n)<=0.00001){
return init;
}else{
init=0.5*(init + n/init);
return root(n,init);
}
}
int main()
{
double a;
cout<<"Enter any number to get its square root: ";
cin>>a;
cout<<"Square Root of "<<a<<" is: "<<root(a,2);
return 0;
}
答案 1 :(得分:0)
您正在使用递归,这可能会溢出您的堆栈。例如,我试图输入9999并且你的程序永远挂起(因为n没有减少)。
另一个问题是double * double可能溢出。
正确(高效,简洁和迭代)的版本是:
double root(double n){ // you dont need the second parameter
double val = n; // initial guess
for(;;) {
double last = val;
val = (val + n / val) * 0.5; // iterative
if (abs(val - last) < 1e-9) break; // error small enough
}
return val;
}
如果你坚持递归,这里有一个更简洁的递归实现:
double root(double n, double last){
if (abs(last * last - n) < 1e-9) { // good guess
return last;
}
return root(n, 0.5 * (last + n / last)); // recursive call
}
另请see "Newton Iterative Sqrt Method"了解更多信息。