筆試題:求一個數的開方,如根號2
阿新 • • 發佈:2019-01-27
題目:
求一個數的開方,如根號2,要求保留到小數點位後10位。解法一:
也就相當於求一個數n的開方,我們用二分法進行計算,不斷縮小範圍,但是double、float不能直接等,最後如果 mid*mid和n的相差不超過一個指定的最小值。那麼所求的mid就是我們得到的值。之後我們將它按照小數點之後10位打印出來就行。 程式碼如下:注意: setprecision 也是包含在名稱空間iomanip 中的C++ 操作符,該操作符的作用是設定浮點數小數點後的位數;#include<iostream> #include<math.h> #include<iomanip> using namespace std; void kaifang(double n,double accuracy); void main() { double n=2; double accuracy=1e-10; kaifang(n,accuracy); } void kaifang(double n,double accuracy) { if(n<0) return; double low=0; double high=n; double kf=0; while(low<high) { double mid=(low+high)/2; double pf=mid*mid; double res=pf-n; if(abs(res)<accuracy) { kf=mid; break; } else if(pf>n) high=mid; else low=mid; } printf("%.10f\n",kf);//利用原始的c打印出小數點後10位 cout<<setiosflags(ios::fixed)<<setprecision(10);//利用C++的操作符打印出小數點後10位 cout<<kf; }
setprecision(2) 的意思就是小數點輸出的精度,即是小數點右面的數字的個數為2,C++預設的流輸出數值有效位是6。。 #include <iomanip>
它是I/O流控制頭文 件,就像C裡面的格式化輸出一樣.以下是一些常見的控制函式的:
dec 置基數為10 相當於"%d"
hex 置基數為16 相當於"%X"
oct 置基數為8 相當於"%o" setioflags(ios::fixed) 固定的浮點顯示
setioflags(ios::scientific) 指數表示
setiosflags(ios::left) 左對齊
setiosflags(ios::right) 右對齊
setiosflags(ios::skipws 忽略前導空白
setiosflags(ios::uppercase) 16進位制數大寫輸出
setiosflags(ios::lowercase) 16進位制小寫輸出
setiosflags(ios::showpoint) 強制顯示小數點
setiosflags(ios::showpos) 強制顯示符號
舉例:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout<<12345.0<<endl;//輸出"12345"
cout<<setiosflags(ios::fixed)<<setprecision(3)<<1.2345<<endl;輸出"1.235"
cout<<setiosflags(ios::scientific)<<12345.0<<endl;//輸出"1.234500e+004 "
cout<<setprecision(3)<<12345.0<<endl;//輸出"1.235e+004 "
return 0;
}
解法二:
利用牛頓迭代法,任意整數x,我任猜它的平方根為y,如果不對或精度不夠準確,那我令y = (x+x/y)/2。如此迴圈反覆下去,y就會無限逼近x的平方根。 例如,我想求根號2等於多少。假如我猜測的結果為4,雖然錯的離譜,但你可以看到使用牛頓迭代法後這個值很快就趨近於根號2了:( 4 + 2/ 4 ) / 2 = 2.25
( 2.25 + 2/ 2.25 ) / 2 = 1.56944..
( 1.56944..+ 2/1.56944..) / 2 = 1.42189..
( 1.42189..+ 2/1.42189..) / 2 = 1.41423..
….
這種演算法的原理很簡單,我們僅僅是不斷用(x,f(x))的切線來逼近方程x^2-a=0的根。根號a實際上就是x^2-a=0的一個正實根,這個函式的導數是2x。也就是說,函式上任一點(x,f(x))處的切線斜率是2x。那麼,x-f(x)/(2x)就是一個比x更接近的近似值。代入f(x)=x^2-a得到x-(x^2-a)/(2x),也就是(x+a/x)/2。
程式碼如下:
double NewtonIteration (double n,double accuracy)
{
double y=1;//可任意取值(除零以外)
long m=0;
while(abs((y*y)-n)>accuracy)
{
y=(y+(n/y))/2;
m++;
}
printf("%.10f\n",y);//利用原始的c打印出小數點後10位
cout<<setiosflags(ios::fixed)<<setprecision(10)<<y<<endl;//利用C++的操作符打印出小數點後10位
cout<<"while number: "<<m;
return y;
}
最後我們比較兩個演算法執行while迴圈的次數,給出完整程式碼如下:
#include<iostream>
#include<math.h>
#include<iomanip>
using namespace std;
void kaifang(double n,double accuracy);
double NewtonIteration (double n,double accuracy);
void main()
{
double n=2;
double accuracy=1e-10;
kaifang(n,accuracy);
NewtonIteration (n,accuracy);
}
void kaifang(double n,double accuracy)
{
if(n<0) return;
double low=0;
double high=n;
double kf=0;
long m=0;
while(low<high)
{
double mid=(low+high)/2;
double pf=mid*mid;
double res=pf-n;
if(abs(res)<accuracy)
{
kf=mid;
break;
}
else if(pf>n)
high=mid;
else
low=mid;
m++;
}
printf("%.10f\n",kf);//利用原始的c打印出小數點後10位
cout<<setiosflags(ios::fixed)<<setprecision(10)<<kf<<endl;//利用C++的操作符打印出小數點後10位
cout<<"while number: "<<m<<endl;
}
double NewtonIteration (double n,double accuracy)
{
double y=1;//可任意取值(除零以外)
long m=0;
while(abs((y*y)-n)>accuracy)
{
y=(y+(n/y))/2;
m++;
}
printf("%.10f\n",y);//利用原始的c打印出小數點後10位
cout<<setiosflags(ios::fixed)<<setprecision(10)<<y<<endl;//利用C++的操作符打印出小數點後10位
cout<<"while number: "<<m;
return y;
}
執行結果為:
從結果中可以看出牛頓法的計算效率好一些,我還試了其他的y值,若y值為4或者3時,仍然while4次,就算是8,也只需while 7次,相較於29次的二分法,效率要高很多。