Implement int sqrt(int x).
求n的平方根,先假設一猜測值X0 = 1
,然後根據以下公式求出X1
,再將X1
代入公式右邊,繼續求出X2
…通過有效次迭代後即可求出n的平方根,Xk+1
先讓我們來驗證下這個巧妙的方法準確性,來算下2的平方根 (Computed by Mathomatic)
1-> x_new = ( x_old + y/x_old )/2 y (x_old + -----) x_old #1: x_new = --------------- 2 1-> calculate x_old 1 Enter y: 2 Enter initial x_old: 1 x_new = 1.5 1-> calculate x_old 2 Enter y: 2 Enter initial x_old: 1 x_new = 1.41666666666671-> calculate x_old 3 Enter y: 2 Enter initial x_old: 1 x_new = 1.4142156862745 1-> calculate x_old 10 Enter y: 2 Enter initial x_old: 1 Convergence reached after 6 iterations. x_new = 1.4142135623731 ...
可見,隨著迭代次數的增加,運算值會愈發接近真實值。
於是可以得到程式碼段:
PS:後來在leetcode上提交後發現用了6ms只擊敗了百分之10.13的其他使用者,一怒之下一同分析刪掉ABS函式,仍然沒變化,等週末有空好好的研究下推導,再次刷到這個題的時候再考慮更好的方法double abs_math(double num) { return num<0?-num:num; //取絕對值 } class Solution{ public: int mySqrt(int x) { double g = x; while(abs_math(g*g-x)>0.000001){ g = (g + x / g ) / 2; } return g; } }
接下來是相關的數理推導:
簡單推導
假設
求出
簡化等式得到:
然後利用得到的最終式進行迭代運算直至求到一個比較精確的滿意值,為什麼可以用迭代法呢?理由是中值定理(Intermediate Value Theorem):
我們先猜測一
回到我們最開始的那個求2次方根的公式,令
求
代入前面求到的最終式中:
化簡即得到我們最初提到的那個求平方根的神奇公式了:
用泰勒公式推導在The Art and Science of C一書中有用到泰勒公式求平方根的演算法,其實牛頓迭代法也可以看作是泰勒公式(Taylor Series)的簡化,先回顧下泰勒公式:
僅保留等式右邊前兩項:
令
再令
轉化為:
|
引申
從推導來看,其實牛頓迭代法不僅可以用來求平方根,還可以求立方根,甚至更復雜的運算。