原文:http://blog.csdn.net/legend050709/article/details/39394381
sqrt算法實現:
(一)int sqrt1(int n);
求取整數x的平方根,向下取整;
(0)步驟:
1.先求出范圍;然后排序
2.然后二分查找;
(1)方法一:O(n)
for(int i=0;i*i<n;i++);
i=i-1;
(2)方法二:二分查找,O(lgn)
1)范圍已經確定,即0~n,並且0~n之間的數據有序;
2)二分查找:
int sqrt1(int n){
int left=0;
int right=n;
int mid;
int last;
while(left<=right){//應該找出mid*mid<=n的最后一個數
mid=(right-left)/2+left;
if(mid*mid<=n){//尋找最后一個數,所以不斷壓縮左邊,即left=mid+1
last=mid;
left=mid+1;
}else{
right=mid-1;
}
}
return last;
}
(3)方法三:O(lg(2分之根號n))+lg(根號n)
1)先確定范圍;O(lg(2分支根號n))
for(int i=n;i*i>n;i=i/2);
j=2*i;
循環結束時,i*i<=n<(2i)*(2i)即i^2<=n<4i^2
然后只需要在i~2i之間尋找一個最大的數k,是的k^2<=n。
2)二分查找:
int left=i,right=j;
while(left<=right){//應該找出mid*mid<=n的最后一個數
mid=(right-left)/2+left;
if(mid*mid<=n){//尋找最后一個數,所以不斷壓縮左邊,即left=mid+1
last=mid;
left=mid+1;
}else{
right=mid-1;
}
}
return last;
----------------------
(二)float sqrt(float x)庫函數的實現:
(1)二分法:
const float eps=0.000001; // eps的值可能影響最后計算精度,甚至導致無限循環
// 二分法,注意區分x的取值區間
float SqrtByBisection(float x)
{
if(x<0) // 負數
return x;
if(x<=eps) // 正數0
return 0.0f;
if(fabs(x-1)<=eps) // 正數1
return 1.0f;
float left, right;
float mid;
if(x>eps&&x<1.0f-eps) // (0,1)區間
{
left=x;
right=1.0f;
}
else
{
left=1.0f;
right=x;
}
while(right-left>eps) // (1,)區間
{
mid=(left+right)/2;
if(mid*mid>x+eps)
right=mid;
else if(mid*mid<x-eps)
left=mid;
else
return mid;
}
return mid;
}
---
(2)牛頓迭代算法:
1)示例圖如下:
圖一,圖二:


2)代碼實現:
// 牛頓迭代法
const float eps=0.000001; // eps的值可能影響最后計算精度,甚至導致無限循環
float SqrtByNewton(float x)
{
float val=x;
float last;
while(fabs(val-last)>eps)
{
last=val;
val=(val+x/val)/2;
}
return val;
}
----
(3)性能最好:比標准庫函數快4倍;(不需要理解,了解即可)
float InvSqrt(float x)
{
float xhalf = 0.5f*x;
int i = *(int*)&x; // get bits for floating VALUE
i = 0x5f375a86- (i>>1); // gives initial guess y0
x = *(float*)&i; // convert bits BACK to float
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
return 1/x;
}
