2016-04-10 29 views
1

背景:我在記錄中有一些元素,其中一些元素可以是float,unsigned int或unsigned long long。所以,我雖然使用float作爲一個公共值從讀取這些元素的函數返回。從無符號整數轉換爲浮點時出錯

但是,我看到這個奇怪的錯誤從無符號整數轉換爲浮點數。在打印該值時,它會發生變化。我怎樣才能避免它?我不應該從這個函數返回float嗎?

#include <iostream> 
#include <limits> 
using namespace std; 
int main() 
{ 
    unsigned int myU = numeric_limits<unsigned int>::max(); 
    cout<<" myU is "<<myU<<'\n'; //correct 
    float myF = (float) myU; 
    cout<<" back To Long "<<(unsigned long long) myF<<'\n'; //error? 
    cout<<" back To unsigned int "<<(unsigned int) myF<<'\n'; //error? 
    cout<<" to Float Without Fixed "<<(float) myU<<'\n';//not clear, so have to use fixed 
    cout<<" to Float With Fixed "<<fixed<<(float) myU<<'\n';//error? 
    cout<<" difference "<<myF-myU<<'\n'; //error? 
    cout<<" myU+32 "<<myU+32<<'\n'; //-1+32=31 ==> understandable 
} 

用gcc 4.6.3輸出:

myU is 4294967295 
back To Long 4294967296 
back To unsigned int 0 
to Float Without Fixed 4.29497e+09 
to Float With Fixed 4294967296.000000 
difference 1.000000 
myU+32 31 
+1

32位[float](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)不能有足夠的精度來存儲32位無符號整數的_exact_值(或者更糟糕的是長長),因爲有效位精度只有24位。嘗試使用double,而不是長整數。 –

+1

注意:「返回無符號整數」行導致未定義的行爲,因爲值超出範圍 –

回答

3

4294967295float (32-bit IEEE 754)被表示爲如下:

0  10011111  00000000000000000000000 
sign exponent  mantissa 
(+1) (2^32)  (1.0) 

用於將其轉換回的整數(或長在此情況下)的規則是:

sign * (2^exponent) * mantissa 

其結果將爲4294967296,這是適當的大小,以填補long long爲你,但太大,不適合在unsigned int所以你會得到0unsigned int轉換。

請注意,問題是用浮點數表示大數的限制,例如42949672954294967200當它們以浮點形式存儲時都表示相同的位。

+0

@ M.M感謝您的筆記,我糾正了這一點,是的,4294967200和4294967295之間的數字不能表示 – Pooya

+1

好的。我試圖做的一點是,4294967295不是這樣表示的(實際上它根本不能表示);你展示的表述是一種可能性,如果你試圖表示這個數字,那麼可能會出現這種情況。 –

0

您所看到的主要問題,是一個floating point type只提供它的小數部分,這當然是很自然的,因爲它可以在有限的精度只保存這麼多的信息。

現在,當您從unsigned int轉換爲float時,您使用的數字太長而不適合分數部分。現在某些精度已經丟失,並且您轉換回整數格式,它可能會有所不同。到unsigned long long,結果只是一個更大,但在轉換爲unsigned int時,您會看到溢出發生。