在許多應用程式領域中,都需要控制小數點後的小數字,但是浮點數對此不能提供直接的支援。怎樣對程式中的浮點資料進行"整齊"地格式化呢?在此我們有乙個迂迴的方法,先把它們轉換為字串,格式化後以文字形式顯示出來。
在日常程式設計中--包括對話方塊、關聯式資料庫、金融程式、sms程式及一切處理資料檔案的程式,需要控制小數點後的小數字的情況非常普遍,本文中將要講解如何用簡單的方法來控制小數字,另外,還要揭開字串及資料精度的一點點小秘密。
問題的引出
如有乙個函式,其可接受乙個long double引數,並將引數轉換為字串,結果字串應保留兩位小數,例如,浮點值123.45678應該生成"123.45"這樣的字串。表面上看來這是乙個意義不大的程式設計問題,然而,如果真要在實際中派上用場,函式應設計為具有一定彈性,以允許呼叫者指定小數字數。另外,函式也應該能夠處理各種異常情況,如像123.0或123這樣的整數。
在開始之前,先看一下編寫"優雅"c++**時的兩句"真言":
"真言"1:無論何時需要格式化乙個數值,都應先轉換為乙個字串。這樣可保證每位數剛好佔據乙個字元。
"真言"2:在需要轉換為字串時,請使用庫。 中國網管聯盟bitscn.com
轉換函式的介面非常簡潔:第乙個引數是需被格式化的數值;第二個引數代表小數點後顯示的小數字,且應該具有乙個預設值;返回值為乙個string型別:
string do_fraction(long double value, int decplaces=3);
注意,第二個引數代表的小數字數中包括了小數點,因此,兩位小數需要預設值為3。
精度問題
string do_fraction(long double value, int decplaces=3) 網管bitscn_com
如果沒有小數點,函式直接返回字串,否則,函式將繼續檢查小數字是否多於decplaces。如果是,小數部分將會被截斷:
size_t n=str.find(decimal_point);
網管網www_bitscn_com
if ((n!=string::npos)//有小數點嗎?
&&(str.size()> n+decplaces)) //後面至少還有decplaces位嗎?
//在小數decplaces位之後寫入nul
str[n+decplaces]='\0';
最後一行覆蓋了多餘的小數字,它使用了\0常量來截斷字串,要注意,string物件的資料可以包含nul字元;而字串的實際長度由size()的返回值決定。因此,你不能假定字串已被正確地格式化,換句話來說,如果在str中原來為"123.4567",在插入\0常量之後,它變成了"123.45\07",為把str縮減為"123.45",一般可使用自交換的方法: str.swap(string(str.c_str()) );//刪除nul之後的多餘字元
那它的原理是什麼呢?函式string::c_str()返回乙個const char *代表此字串物件,而這個值被用作乙個臨時string物件的初始化值,接著,臨時物件又被用作str.swap()的引數,swap()會把值"123.45"賦給str。一些老一點的編譯器不支援預設模板引數,可能不會讓swap()通過編譯,如果是這樣的話,使用手工交換來代替:
string temp=str.c_str();
str=temp;
網管bitscn_com
**雖不是很"優美",但能達到目的就行。以下是do_fraction()的完整**:
string do_fraction(long double value, int decplaces=3)
str.swap(string(str.c_str()));//刪除nul之後的多餘字元
return str;
} 如果不想通過傳值返回乙個string物件,還可增加乙個引數,把str物件以引用傳遞:
void do_fraction(long double value, string & str, int decplaces=3);
網管聯盟bitscn@com
從個人的角度來講,還是傾向於讓編譯器做這樣的優化,另外,使用傳值返回,還可以讓你以下面這種方式使用do_fraction():
cout << funct(123456789.69999001) << '\t' << funct(12.011)《輸出:
123456789.69 12.01
使用setprecision(n)可控制輸出流顯示浮點數的數字個數。c++預設的流輸出數值有效位是6。
如果setprecision(n)與setiosflags(ios::fixed)合用,可以控制小數點右邊的數字個數。setiosflags(ios::fixed)是用定點方式表示實數。
如果與setiosnags(ios::scientific)合用, 可以控制指數表示法的小數字數。setiosflags(ios::scientific)是用指數方式表示實數。
例如,下面的**分別用浮點、定點和指數方式表示乙個實數:
//*********************
//** ch2_1.cpp **
//*********************
#include
#include //要用到格式控制符
void main()
執行結果為:
3.14286
3 3
3.1
3.14
3.143
3.14285714
3.14285714e+00
該程式在32位機器上執行通過。
在用浮點表示的輸出中,setprecision(n)表示有效位數。
第1行輸出數值之前沒有設定有效位數,所以用流的有效位數預設設定值6:第2個輸出設定了有效位數0,c++最小的有效位數為1,所以作為有效位數設定為1來看待:第3~6行輸出按設定的有效位數輸出。
在用定點表示的輸出中,setprecision(n)表示小數字數。
第7行輸出是與setiosflags(ios::fixed)合用。所以setprecision(8)設定的是小數點後面的位數,而非全部數字個數。
在用指數形式輸出時,setprecision(n)表示小數字數。
第8行輸出用setiosflags(ios::scientific)來表示指數表示的輸出形式。其有效位數沿用上次的設定值8
setw(n)是設定域寬。
就是你的輸出要佔多少個字元
比如:
cout<就輸出
12345
cout<輸出 12345
而如果你要輸出的字元寬度超出了setw(n)的n值,就按輸出字元的寬度輸出。
如你的cout<就輸出12.3456
小數點後k位
立華奏在學習初中數學的時候遇到了這樣一道大水題 設箱子內有 n 個球,其中給 m 個球打上標記,設一次摸球摸到每乙個球的概率均等,求一次摸球摸到打標記的球的概率 但是她改了一下詢問方式 設最終的答案為 p 請輸出 p 小數點後 k1 到 k2 位的所有數字 若不足則用 0 補齊 第一行乙個整數 t,...
限制小數點 16 19小數點後200位是多少?
c語言求解精確小數點 題目內容 由於計算機內部表達方式的限制,浮點運算都有精度問題,為了得到高精度的計算結果,就需要自己設計實現方法。0,1 之間的任何浮點數都可以表達為兩個正整數的商,為了表達這樣兩個數的商,可以將相除的結果存放在一維陣列中,陣列的每個元素存放一位十進位制數字。即商的第一位存放在第...
jxl讀取excel小數點後三位擷取問題
今天讀取excel檔案時發現乙個問題,獲得sheet物件後,通過方法sheet.getcell i,j getcontents 取回的數值會被自動四捨五入只保留小數點後3位,後來查閱資料發現,jxl裡對getcontents 進行了封裝。如果小數點後多於3位,則需要使用numbercell物件提供的...