在學數學時,我們接觸到的第一個用於求取一個數的平方根的算法基本都是二分法.其步驟如下
- 估算解所在的區間,並獲取解區間的最大值和最小值;
- 計算解區間的中間點的函數值, 明確新的解區間的最大值和最小值;
- 將解區間縮小到原來的二分之一, 並重新賦值解區間的最大值和最小值, 重複第2步, 直到搜索到的解滿足需求;
數學解釋如下:
對於一個單調函數f(x),求取abs(f(x) - num) <= eps的解區間中的一個值,並且我們知道存在解的區間爲[x_min, x_max],我們只需要搜索滿足條件的子區間就可以. 在這裏假設函數是遞增的, 那麼一定有f(x_min) < num < f(x_max);同時f(x_min) < f((x_min+x_max)/2) < f(x_max). 所以可以通過計算區間的中間點的值來確定我們下一步需要搜索的區間位於左還是右. 通過若干步的循環就可以找到解區間.
c++實現如下
template <typename T>
T twoDivide(T num, T eps)
{
if (num <0)
{
printf("Wrong input data!!");
return num;
}
T high_thr = num > 1 : num / 2 ? 1;
T low_thr = 0;
T ans = (high_thr + low_thr) / 2;
while ( abs(ans*ans - num) > eps)
{
if (ans*ans > num)
{
high_thr = ans;
ans = (high_thr + low_thr) / 2;
}
else
{
low_thr = ans;
ans = (low_thr + high_thr) / 2;
}
}
return ans;
}
牛頓拉弗生解法是通過搜索曲線與x軸的交點來求取單調函數的解. 迭代方程如下:
x_n+1 = x_n - f(x_n)/g(x_n)
需要注意的是候選點的導數不能爲0.C++實現如下:
template <typename T>
T newTon(T num, T eps)
{
if (num <0)
{
printf("Wrong input data!!");
return num;
}
T high_thr = num > 1 : num / 2 ? 1;
T low_thr = 0;
T ans = (high_thr + low_thr) / 2;
while ( abs(ans*ans - num) > eps)
{
ans = ans - (ans*ans - num)/2/ans;
}
return ans;
}
通過實驗驗證可知,牛頓法比二分法快很多.