2011-06-30 65 views
1

我遇到了一些我從未見過的東西,並且非常想知道發生了什麼。我正在試圖將double加2位小數,並將該值轉換爲一個字符串。演員完成後,事情對我發瘋。將浮點(雙精度)鑄造成字符串

下面是代碼:

void formatPercent(std::string& percent, const std::string& value, Config& config) 
{ 
    double number = boost::lexical_cast<double>(value); 
    if (config.total == 0) 
    { 
     std::ostringstream err; 
     err << "Cannot calculate percent from zero total."; 
     throw std::runtime_error(err.str()); 
    } 
    number = (number/config.total)*100; 
    // Format the string to only return 2 decimals of precision 
    number = floor(number*100 + .5)/100; 
    percent = boost::lexical_cast<std::string>(number); 

    return; 
} 

我沒有得到完全是我預料,所以我做了一些調查。我做了以下內容:

std::cout << std::setprecision(10) << "number = " << number << std::endl; 
std::cout << "percent = " << percent << std::endl; 

...並得到如下:

number = 30.63 
percent = 30.629999999999999 

我懷疑升壓正在做一些有趣的事情。有沒有人有任何見解?

說真的,這有多奇怪?!?我要求一個雙精度的10位精度,並獲得4位數字。我要求將這4位數字轉換成一個字符串,並將其弄亂。到底是怎麼回事?

+7

是時候另一個鏈接到什麼每臺計算機科學家應該知道關於浮點運算:http://download.oracle.com/docs/cd/E19957-01 /806-3568/ncg_goldberg.html –

+1

您的鏈接根本無法解決我的問題。這其實只是一種迂迴的回答我的問題的方式。你會注意到Martin Beckett的回答直接回答了這個問題。 – Rico

+0

二進制的30.63的擴展是無限的,正如基數10中1/3的擴展是無限的。詞法鑄()做它應該是因爲數字真的不是30.63。請參閱http://stackoverflow.com/questions/5016464/boostlexical-cast-conversion-double-to-string-c –

回答

1

的std ::精度設置的顯著位的最大數目,以顯示

在缺省浮點 表示法中,精密場 指定 有意義的最大位數總共 計數顯示小數點後的那些以及那些 。請注意, 它不是最小值,因此如果 顯示的數字位數小於 精度,則它不會將顯示的數字填充爲尾隨零的 。

30.629999999999999是30.63

+0

謝謝你這個有用的答案。我沒有意識到std :: precision不會顯示尾隨零(或9)。 – Rico

+0

@Rico - 直到我GOOGLE了這個! –

0

問題是浮點數不能準確表示任意十進制值。你看到的是浮點錯誤。 Boost正在準確顯示您提供給它的值。

1

實際浮點表示你要求的精度十個位數,但實際的「不準確」,是進一步下跌,所以當它四捨五入到十位數字就變成了整潔30.63。您的lexical_cast將所有數字考慮在內,因此會產生精確的浮點值(可能不是您想要的精度,但它是計算機內存中內容的最精確表示)。

3

十進制數30.63不能存儲在double類型的對象中。實際存儲的最接近的有效雙精度值是8621578536647393 * 2^-48,在十進制中,該值爲30.629999999999999005240169935859739780426025390625

你可以看到,如果你做std::cout << std::setprecision(100) << "number = " << number << std::endl;