浮點數顯示問題
這篇文章主要是來介紹有關manipulator(操控器)對於浮點數顯示的影響, 當使用到的函數或旗標時,會多加介紹。看個例子:
int main() { double dNum1 = 1.23456789 , dNum2 = 0.123456789 , dNum3 = 0.0123456789 ; cout<<"Num1:"<<dNum1<<endl; cout<<"Num2:"<<dNum2<<endl; cout<<"Num3:"<<dNum3<<endl; return 0; }
輸出為: Num1:1.23457 Num2:0.123457 Num3:0.0123457
曉得原因嗎?在沒有設定任何的旗標或參數時,輸出的精度(precision)是6個十進位數 這個精度的意思是說,小數點前的數字加上小數點後的數字,總共為6個 在顯示數值之前,未滿足精度的位數會做四捨五入(round)的動作, 並且前導的0(leading zero)並不算在精度的位數中。 dNum1顯示六個數字,而最後一個數字是因為後半段四捨五入的關係 dNum2顯示七個數字,因為前導的零(leading)並不算在精度顯示的限制 dNum3顯示八個數字,跟上面的解釋是一樣的 那加點東西來看看:
int main() { double dNum1 = 1.23456789 , dNum2 = 0.123456789 , dNum3 = 0.0123456789 ; cout.setf(ios::fixed,ios::floatfield); cout<<"Num1:"<<dNum1<<endl; cout<<"Num2:"<<dNum2<<endl; cout<<"Num3:"<<dNum3<<endl; return 0; }
輸出為: Num1:1.234568 Num2:0.123457 Num3:0.012346
變了!這是因為設定浮點數表示的方式所造成的! ios::floatfield是一個遮罩(MASK) 而其中的旗標有 fixed:使用小數記號法 scientific:使用科學記號法 none:使用上述兩者中最適合者(預設狀況) 而setf(ios::fixed,ios::floatfield);這種用法是這樣解釋的: 設置fixed旗標,同時自動清除同組的其他旗標(scientific及none)
所以現在顯示的旗標是設定fixed, 而fixed精度(precision)的定義是指小數點後的數字總數,沒有包含小數點之前的 預設精度(precision)一樣是6,其餘的數字一樣會做四捨五入的動作。
另一種在設置旗標的方式,是直接加在cout<<之後: cout.setf(ios::fixed,ios::floatfield); cout<<"Num1:"<<dNum1<<endl; ==>cout<<fixed<<"Num1:"<<dNum1<<endl; 以此類推。
接著接做點改變: int main() { double dNum1 = 1.23456789 , dNum2 = 0.123456789 , dNum3 = 0.0123456789 ; cout<<scientific; cout<<"Num1:"<<dNum1<<endl; cout<<"Num2:"<<dNum2<<endl; cout<<"Num3:"<<dNum3<<endl; return 0; } 輸出結果: Num1:1.234568e+000 Num2:1.234568e-001 Num3:1.234568e-002
顯示 的方式是以科學記號法,e+XXX表示10的XXX次方
精度一樣是跟fixed一樣,是指小數點之後的位數,預設為6。
而要如何設定精度(precision)呢?
可以利用cout.precision(n);
或直接寫在cout<<之後std::setprecision(n);
但注意利用setprecision需引入<iomanip>標題檔
在網路上查尋到一個範例,讓大家看一下:
#include <iostream> int main() { double x = 123.456789012345,y = 1.123456789012345e-7; // No floatfield flags set(沒有設置任何的旗標) std::cout << "x " << x << ", y = " << y << '\n'; //輸出 x 123.457, y = 1.12346e-007 // Using fixed floating point notation(使用科學記號表示法) std::cout.setf(std::ios::fixed,std::ios::floatfield); std::cout << "x " << x << ", y = " << y << '\n'; //輸出 x 123.456789, y = 0.000000 std::cout.precision(9); std::cout << "x " << x << ", y = " << y << '\n'; //輸出 x 123.456789012, y = 0.000000112 // Restore it to "normal" representation(回復到原本的none或稱為normal旗標) //但注意精度不是原本的6了,因為上式已經設定精度為9了! //利用fmtflags(0)來clear std::cout.setf(std::ios::fmtflags(0),std::ios::floatfield); std::cout << "x " << x << ", y = " << y << '\n'; //輸出 x 123.456789, y = 1.12345679e-007 // Revert to fixed(返回到fixed看看) std::cout.setf(std::ios::fixed,std::ios::floatfield); std::cout << "x " << x << ", y = " << y << '\n'; //輸出 x 123.456789012, y = 0.000000112 // Try scientific(試看看scientific) std::cout.setf(std::ios::scientific,std::ios::floatfield); std::cout << "x " << x << ", y = " << y << '\n'; //輸出 x 1.234567890e+002, y = 1.123456789e-007 }
那先在有一個常見的問題,如何把浮點數轉成字串呢?
在C語言中,可以利用fcvt函數,但由於這個函數並不是標準的C函數,
所以使用編譯器可能會顯示沒有此函數,這個函數的相關資料連結在此:
Convert floating point value to string.char * fcvt ( double value, int num, int * dec, int * sign );
而在C++也有另一種方法,來看一下程式:
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double fNum = -123.456789;
string str;
stringstream sstream;
sstream<<setprecision(9) <<fNum;
str = sstream.str();
cout<<str<<endl;
return 0;
}
setprecision(9)中的9是因為在沒有設定任何fixed或scientific時,使用的旗標是none 所以精度(precision)的數值代表,小數點前的數字數目加上小數點後的數字數目 其實string、stringstream可以需要自己去研讀了! 網路上搜集來的範例與文章:
Example 6: Input and Output Expressions The Standard Library Streams
Written By James On 2004/02/08