一句話介紹
四舍六入五考慮灾票,五后非零就進一摇邦,五后為零看奇偶,五前為偶應舍去趾撵,五前為奇要進一侄柔。
疑問
一直以為 JavaScript
的 toFixed()
是四舍五入的,但今天卻驚訝地發(fā)現(xiàn):它并不是一直都會四舍五入的
1.35.toFixed(1) // 1.4
1.45.toFixed(1) // 1.4
為什么對于相同的尾數(shù)5的舍入占调,結(jié)果卻不同呢暂题?
因為 toFixed()
使用的是“銀行家舍入法”
銀行家舍入法是由 IEEE 754 標準規(guī)定的浮點數(shù)取整算法,大部分的編程軟件都使用這種方法究珊。
當舍去位的數(shù)值:
- 小于等于4薪者,直接舍去該位
- 大于等于6,向前位進一
- 等于5
- 5后有數(shù)剿涮,向前位進一
- 5后全0
- 5前位數(shù)值為奇言津,則向前位進一(將前位湊成偶)
- 5前位數(shù)值為偶,則直接舍去該位
場景
我們知道銀行的盈利渠道主要是利息差取试,從儲戶手里收攏資金悬槽,然后放貸出去,其間的利息差額便是所獲得的利潤瞬浓。對一個銀行來說初婆,對付給儲戶的利息的計算非常頻繁。
假如我們使用四舍五入法瑟蜈,且假設銀行收到的錢中烟逊,要舍入的那位數(shù)在0~9是等概率的,那么假設銀行分別收到了 0.000, 0.001, ..., 0.009
元铺根,然后通過四舍五入法宪躯,銀行能夠得到五個 0.000
和五個 1.000
,也許在概率上看起來是公平的位迂,但是:
以銀行家的身份來思考這個算法:
(1)四舍:舍棄的數(shù)值:0.000访雪、0.001详瑞、0.002、0.003臣缀、0.004坝橡,因為是舍棄,對銀行家來說精置,就是不用付款給儲戶的计寇,那每舍棄一個數(shù)字就會賺取相應的金額:0.000脂倦、0.001番宁、0.002、0.003赖阻、0.004蝶押。
(2)五入:進位的數(shù)值:0.005、0.006火欧、0.007棋电、0.008、0.009苇侵,因為是進位赶盔,對銀行家來說,每進一位就會多付款給儲戶衅檀,也就是虧損了招刨,那虧損部分就是其對應的10進制補數(shù):0.005霎俩、0.004哀军、0.003、0.002打却、0.001
因為舍棄和進位的數(shù)字是在0到9之間均勻分布的杉适,所以對于銀行家來說,每10筆存款的利息因采用四舍五入而獲得的盈利是:
0.000 + 0.001 + 0.002 + 0.003 + 0.004 - 0.005 - 0.004 - 0.003 - 0.002 - 0.001 = -0.005
也就是說柳击,每10筆的利息計算中就虧損0.005元猿推,即每筆利息計算損失0.0005元
問題:為什么銀行家舍入是合理的?
- 四舍六入本身沒問題捌肴,5前偶舍奇進也沒問題蹬叭,關(guān)鍵在為什么5后有非0數(shù)要進位?
- 遇5舍棄的情況只有一種状知,即5是最后一位有效的數(shù)字且前一位數(shù)是偶數(shù)
- 當數(shù)值精度達到5后一位秽五,其為0的概率為1/10,5前為偶數(shù)的概率是1/2饥悴,所以舍5的概率是1/10 * 1/2 = 1/20坦喘,而進5的概率是19/20
- 當數(shù)值精度越大盲再,舍5個概率就越低,無限趨近于0瓣铣,也就是說答朋,當數(shù)值精度越高,該算法越像“四舍五入”
- 那么棠笑,為什么這個算法是合理的呢梦碗?
- 現(xiàn)實情況就是數(shù)值的精度不可能無限大,存款利息率一般為百分之零點幾蓖救,而數(shù)值精度一般4位叉弦,5后存在非0數(shù)的概率相對較小,所以趨近于1/2舍5藻糖,1/2進5
后記
說是 toFixed() 使用的銀行家舍入法所以表現(xiàn)起來不是四舍五入淹冰,但是在 Chrome
瀏覽器的實測中,我注意到它也并不一定都符合銀行家舍入法:
0.45.toFixed(1) // 0.5 而不是0.4
1.45.toFixed(1) // 1.4
個人認為巨柒,這可能是由于浮點數(shù)存儲精度問題導致的(未查閱資料證實)樱拴。
比如這里的 0.45其實類似于0.4500000002,存在一點點尾數(shù)洋满,所以進行了舍入變?yōu)?.5晶乔。
有人認為因此在嚴肅的情況下不應使用 toFixed(),不過我個人倒是認為誤差是隨機的牺勾,所以從概率而言最后得到的結(jié)果還是公平的正罢。