2012-09-19 70 views
1

我正在搜索幾個論壇,以獲得關於如何序列化浮點數的一些想法,我碰巧碰到下面的代碼。序列化浮點數

oxdrstream& 
oxdrstream::operator<<(
    float    source) 
{ 
    BytePutter   dest(*this) ; 
    bool    isNeg = source < 0 ; 
    if (isNeg) { 
     source = - source ; 
    } 
    int     exp ; 
    if (source == 0.0) { 
     exp = 0 ; 
    } else { 
     source = ldexp(frexp(source, &exp), 24) ; 
     exp += 126 ; 
    } 
    uint32_t   mant = source ; 
    dest.put((isNeg ? 0x80 : 0x00) | exp >> 1) ; 
    dest.put(((exp << 7) & 0x80) | ((mant >> 16) & 0x7F)) ; 
    dest.put(mant >> 8) ; 
    dest.put(mant  ) ; 
    return *this ; 
} 

我不明白爲什麼我們要做這個

source = ldexp(frexp(source, &exp), 24) ; 

frexp()將返回在0.5(含)和1(不含)的值。

對於如: frexp()返回0.81

ldexp(0.81,24) - > 19.44和分配給unit_32時,它會betruncated。

我看不到這背後的邏輯。有人能爲我澄清這一點嗎?

回答

2

ldexp(.81f, 24)不產生19.44;它產生13589545.該代碼的設計使得ldexp總是產生一個小於2的整數,並精確地在mant(它應該被稱爲significand,因爲它不是尾數)捕獲有效數字。

此代碼不適用於負零,低於正常值,無窮大或NaN。

+0

我不知道爲什麼我寫了19.44。 ldexp(x,y)→x * 2^y。在這種情況下,它將返回13589544.96四捨五入到13589545. 0.810000001 *(1 << 24)將返回相同的值,對不對?在這種情況下,我們是不是引入了額外的精確損失 – KodeWarrior

+0

但是,我確實得到了你試圖提出的觀點。欣賞它! – KodeWarrior

+0

輸入是一個浮點數。你的「.81」是雙倍的。浮點數輸入值永遠不會有超過24位的有效數。當按照代碼進行縮放時,結果總是恰好爲整數。 –