對於負整數 x 和任意 y > 0 的y,x / y 向上舍入的結果和 ( x+y-1 ) / y 向下舍入的結果是相同,把 y = 2^k 帶入向下舍入的公式有, ( x + 2^k -1 ) / 2^k,換算成C語言的移位表達式也就是
( x + (1 << k) - 1 ) >> k
這樣就可以保證負數通過這麼一個偏置,其“右移”的結果也是向上舍入。
總結起來,就是 x / (2^k) 等價的右移表達式爲:
( x < 0 ? x + (1<<k) - 1 : x) >> k
IEEE浮點數舍入:
浮點數舍入相比向整數舍入,就複雜一些,IEEE定義了四種不同的舍入方式,默認的爲向偶數舍入(round-to-even)。其他三個分別是向零舍入,向上舍入和向下舍入。
其他三個比較直觀,就不再說明,以十進制爲例說明“向偶數舍入”,平常的四捨五入中,以舍入到小數點後兩位爲例,如果第3位小數小於5,則捨去,大於等於5的則進1。向偶數舍入除了最中間的這個值(第3位小數爲5)以外,其他與平常的舍入相同,中間的這個值,則要保證在舍入的時候舍入位必須爲偶數。比如1.40, 1.60, 1.50, 2.50, -1.50向偶數舍入的結果分別爲1, 2, 2, 2, -2
至於爲什麼要想偶數舍入,這是CSAPP(2e)中的原文:
The problem with such a convention is that one can easily imagine scenarios
in which rounding a set of data values would then introduce a statistical bias
into the computation of an average of the values. The average of a set of numbers
that we rounded by this means would be slightly higher than the average of
the numbers themselves. Conversely, if we always rounded numbers halfway
between downward, the average of a set of rounded numbers would be
slightly lower than the average of the numbers themselves. Rounding toward
even numbers avoids this statistical bias in most real-life situations.
It will round upward about 50% of the time and round downward about 50% of the time.
也就是如果在一組數據中,向偶數舍入一般既有向上舍入也有向下舍入,可以一定程度上消除統計平均數時由於總是向上舍入時所帶來的統計偏差。
擴展成二進制,就是對形如 XX···X.YY···Y100···二進制模式位的數(最右邊的Y是要舍入的位置),根據舍入位是否爲偶數來選擇是向上舍入還是向下舍入。(至於爲什麼是100,我還沒想明白)
比如10.010, 10.011, 10.110, 11.001向偶數舍入(保留小數點後一位)的結果分別爲10.0, 10.1, 11.0, 11.0。
總結:
向整數舍入總是向零舍入,因此爲了保證負數右移 k 位的結果與除以 2^k 的結果是相同的,要做一個偏置。而浮點數舍入則爲向偶數舍入,中間值根據舍入位是否爲偶數來決定是向上還是向下舍入。
補充:對於V = 0.yyyyy··· 的無窮二進制位(其中 y 是一個 k 位的序列,例如 1/3 = 0.01010101···,y = 01,k = 2),滿足以下公式:
推倒:V 左移 k 爲爲 y.yyyy···,也即 Y + V = V * 2^k,變換一下就可以得到公式。
用這種方法可以快速計算出某些二進制位代表的十進制數,比如 0.001001001··· = 1 / (2^3 - 1) = 1 / 7,0.000111000111000111··· = 7 / (2^6 - 1) = 7 / 63 = 1 / 9