小數點後截位問題

2021-06-19 08:20:03 字數 3291 閱讀 5140

在許多應用程式領域中,都需要控制小數點後的小數字,但是浮點數對此不能提供直接的支援。怎樣對程式中的浮點資料進行"整齊"地格式化呢?在此我們有乙個迂迴的方法,先把它們轉換為字串,格式化後以文字形式顯示出來。

在日常程式設計中--包括對話方塊、關聯式資料庫、金融程式、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物件提供的...