如何不用库函数实现根号的求值

今天和朋友聊面经,说到一道题目,如何不用库函数求根号,并且能用函数的输入参数来控制误差,他想了一个比较牛逼的方法,小数转整数,然后二分查找。在那么短的时间想到这个地步真是不错,但是我貌似记得科学计算的课上说过类似的东西,用泰勒计算:

其实想到了这个其他的都比较简单了,贴一下代码:

#include <iostream> #include <cmath> using namespace std; #define _DEBUG //(1+x)^t = 1+ t*x + t*(t-1)/(t!)8x^2+...+t*(t-1)(t-2)...(t-n+1)/(t!)*x^n const double alpha = 0.5; int main(int argc,char **argv) { if(argc!=2) return 0; double x,y, error = atof(argv[1]), n = 1.0,//int最大只能算12的阶乘! temp_a = alpha, temp = 100.0; cin>>y; x = y-1; y = 1.0; int i = 1; while(abs(temp) > error) { y+=temp_a/n*x; n*=(i+1); temp_a*=(alpha-i); x*=x; temp = temp_a/n*x; ++i; } cout<<"i= "<<i<<" Y = "<<y<<endl; return 0; }

 

但是可能是浮点数精度的问题,精度只能达到有限值,试一下long double结果一样,只能精确到10e-4的量级,这个如何解决?

是哪里计算的问题呢?再考虑一下!(当n过大时n!超出了double的表示范围!)。

 

《九章算术》中有云:
开方术曰:置积为实。借一算,步之,超一等。议所得,以一乘所借一算为法,而以除。除已,倍法为定法。其复除,折法而下。复置借算,步之如初,以复议一乘之,所得副以加定法,以除。以所得副从定法。复除,折下如前。

 

因此代码修正如下:

#include <iostream> #include <cmath> using namespace std; #define _DEBUG //(1+x)^t = 1+ t*x + t*(t-1)/(t!)8x^2+...+t*(t-1)(t-2)...(t-n+1)/(t!)*x^n const double alpha = 0.5; int main(int argc,char **argv) { if(argc!=2) return 0; double x,result, error = atof(argv[1]),//int最大只能算12的阶乘! temp; cin>>result; //设定循环的初始值 x = result-1; result = 1.0; temp = alpha*x; //设定循环次数统计变量 int i = 1; while(abs(temp) > error) { result+=temp; temp*=(alpha-i)/(i+1)*x;//霍纳法则更新temp的值 ++i; } cout<<"i= "<<i<<" Y = "<<result<<endl; return 0; }

 

整个问题的核心就在于如何使用泰勒级数,了解了公式,一切都比较好解决。

但是如果扩展这个问题,假定给定的是多项式,如何求根?使用泰勒级数逐项展开的前期工作量会变的很大,这时候需要考虑一下牛顿迭代了。

牛顿迭代的原理可以简单叙述如下:

1。 对原始方程求导F1(假定方程有解)

2。 任取一点X0,求出曲线上的点(X0,Y0),并求出斜率F1(X0),作直线

3。 求出该直线和X轴的交点,并把新求出的X1作为新的迭代值

4。 重复1-3直到达到允许误差

 

DONE~~

你可能感兴趣的:(工作,扩展,iostream)