利用二分法和牛頓法開根號


一.問題描述:給定一個數,如何求它的平方根(不能使用內置函數,如sqrt()函數)。

二.題解:

  這屬於比較經典的一道題目,通常有兩種方法:二分法和牛頓法,下面是詳細描述。

方法1:二分法,這是比較容易想到的一種方法。通過比較中間值與最終值的大小來改變中間值,最終在滿足某個精度的情況下返回這個中間值作為最終結果。代碼如下:

#include<iostream>
#include<cmath>
using namespace std;
//n是大於等於1的數
double MySqrt(double n)
{
    double _max = n; //此處一定為浮點數,不要用整數
    double _min = 0.0;
    double p = 1e-5; //此處為精度,當滿足該精度時,返回該近似值
    double  mid = (_max + _min) / 2.0;
    while(fabs(mid * mid - n) > p)//此處是浮點數之差的絕對值與精度進行比較
    {
        if(mid * mid < n)
            _min = mid;
        else if(mid * mid > n)
            _max = mid;
        else
            return mid;
        mid = (_max + _min) / 2.0;
    }
    return mid;
}
int main()
{
    cout<<MySqrt(80)<<endl;
}

 

很容易看出,該算法的時間復雜度為O(logN),空間復雜度為O(1)。而且最終結果的精度取決於精度p的設置。

需要注意的是,對於n小於1的時候,二分法就不適用了,因為mid一定是小於1的數,而mid*mid一定會變得更小,導致區間始終向0靠近(向左靠近),不符合二分法的特征。

注:這里面的變量類型都是浮點型!!

方法2:1.牛頓法,牛頓迭代法(Newton's method)又稱為牛頓-拉夫遜方法(Newton-Raphson method),它是牛頓在17世紀提出的一種在實數域和復數域上近似求解方程的方法。多數方程不存在求根公式,因此求精確根非常困難,甚至不可能,從而尋找方程的近似根就顯得特別重要。方法使用函數f(x)的泰勒級數的前面幾項來尋找方程f(x) = 0的根。牛頓迭代法是求方程根的重要方法之一,其最大優點是在方程f(x) = 0的單根附近具有平方收斂,而且該法還可以用來求方程的重根、復根。另外該方法廣泛用於計算機編程中。

設r是f(x) = 0的根,選取x0作為r初始近似值,過點(x0,f(x0))做曲線y = f(x)的切線L,L的方程為y = f(x0)+f'(x0)(x-x0),求出L與x軸交點的橫坐標 x1 = x0-f(x0)/f'(x0),稱x1為r的一次近似值。

過點(x1,f(x1))做曲線y = f(x)的切線,並求該切線與x軸交點的橫坐標 x2 = x1-f(x1)/f'(x1),稱x2為r的二次近似值。重復以上過程,得r的近似值序列,其中x(n+1)=x(n)-f(x(n))/f'(x(n)),稱為r的n+1次近似值,上式稱為牛頓迭代公式。

2.而開根號的問題可以看作求解f(x) = x2 - a = 0的根。

(1)在曲線f(x)=x^2-a上任取一點(x0,f(x0)),x0≠0,該點的切線方程為: 
這里寫圖片描述 
(2)該切線與x軸的交點為: 
這里寫圖片描述 

(3)不斷用新的交點來更新原來的交點(即逼近的過程) 
根據牛頓迭代的原理,可以得到以下的迭代公式:

          

根據這個公式,可實現該算法,代碼如下:

#include<iostream>
#include<cmath>
using namespace std;
double MySqrt(double n)
{
    double x = 1.0;//設置初值
    double p = 1e-5;//設置精度
    while(fabs(x*x - n) > p)
    {
        x = (x + n / x) / 2.0;
    }
    return x;
}
int main()
{
    cout<<MySqrt(82)<<endl;
}

牛頓法同二分法一樣,時間復雜度為O(logN),空間復雜度為O(1)。牛頓法每次迭代的誤差都會至少小一半,所以復雜度最多是O(logN)。根據牛頓法的原理可知,迭代的次數越多,近似值越逼近真實值,當然我們會通過設置精度來限制它的迭代次數。

三.牛頓法與二分法的比較:

1.我通過測試82的平方根來比較這兩種方法:

二分法:

牛頓法:

可以看出,當我設置兩種算法的精度一樣時,二分法迭代次數為24次,而牛頓法的迭代次數為7次;且牛頓法的准確率更高。

所以說,牛頓法與二分法相比,速度更快、准確率更高。

2.牛頓法需要設置初值(即初始的x0),有時問題的答案的准確率很依賴於初值的設定(可參考:https://www.zhihu.com/question/20690553);而二分法不需要設置初值,所以穩定性較強。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM