突然發現個問題,我們生活中的金融體系最多只有兩位小數位,例如12.37,精確到分,但是當兩位小數和非整數計算時也會得出三位小數啊,例如銀行的日率,一定會有計算得出三位小數或更多小數位的,但是為什麼我們只看得到兩位小數的餘額呢,多出的小數位不也是錢嗎,被省略了嗎,怎麼省略的呢。感覺這個問題有點意思。
我的猜想:
其實只要我們金融體系只是用兩位小數,當產生超過兩位小數時,後面的小數位都不要了,直接不要,而不是滿五進一,如果進一,就造成多給用戶錢了,就算是多給0.001元,這在整個系統中的損失也是巨大的,所以當出現兩位以上的小數時,只能直接省去後面的小數位,哪怕是0.239也要省去0.009,這個0.009元的損失只能讓用戶承擔。
例如銀行的系統,支付寶,這些都是兩位小數位的,我們一般餘額字段都是使用decimal(10,2)
,保留兩位小數位,我突然想到這個問題,好糾結,不知道是不是我想的那樣。
例如支付寶使用積分,購物券抵扣同時下多個訂單時,那個抵扣的錢好像就是根據訂單金額的比例拆分到每個訂單下面去了,這樣就出現小數了,但是那個小數也是兩位,我沒仔細注意過,不知道多個訂單的抵扣加起來是不是等於下單時抵扣的錢。
如果是我想的那樣,那這樣我感覺很多時候我們肯定損失了很多錢?我原本想多保留幾位小數就可以解決這個問題,可是感覺可能還會有無窮的小數,還是不太可能,難道就只能讓用戶損失錢嗎,哪怕只是那麼一點點。
希望大神指點一下,搞得我好迷惑,目前專案中正遇到了這類問題。
謝謝!
突然發現個問題,我們生活中的金融體系最多只有兩位小數位,例如12.37,精確到分,但是當兩位小數和非整數計算時也會得出三位小數啊,例如銀行的日率,一定會有計算得出三位小數或更多小數位的,但是為什麼我們只看得到兩位小數的餘額呢,多出的小數位不也是錢嗎,被省略了嗎,怎麼省略的呢。感覺這個問題有點意思。
我的猜想:
其實只要我們金融體系只是用兩位小數,當產生超過兩位小數時,後面的小數位都不要了,直接不要,而不是滿五進一,如果進一,就造成多給用戶錢了,就算是多給0.001元,這在整個系統中的損失也是巨大的,所以當出現兩位以上的小數時,只能直接省去後面的小數位,哪怕是0.239也要省去0.009,這個0.009元的損失只能讓用戶承擔。
例如銀行的系統,支付寶,這些都是兩位小數位的,我們一般餘額字段都是使用decimal(10,2)
,保留兩位小數位,我突然想到這個問題,好糾結,不知道是不是我想的那樣。
例如支付寶使用積分,購物券抵扣同時下多個訂單時,那個抵扣的錢好像就是根據訂單金額的比例拆分到每個訂單下面去了,這樣就出現小數了,但是那個小數也是兩位,我沒仔細注意過,不知道多個訂單的抵扣加起來是不是等於下單時抵扣的錢。
如果是我想的那樣,那這樣我感覺很多時候我們肯定損失了很多錢?我原本想多保留幾位小數就可以解決這個問題,可是感覺可能還會有無窮的小數,還是不太可能,難道就只能讓用戶損失錢嗎,哪怕只是那麼一點點。
希望大神指點一下,搞得我好迷惑,目前專案中正遇到了這類問題。
謝謝!
有個 銀行家舍入 的方法,即:
捨去位的數值小於5時,直接捨去;
捨去位的數值大於等於6時,進位後捨去;
當捨去位的數值等於5時,分兩種情況:5後面還有其他數字(非0),則進位後捨去;若5後面是0(即5是最後一位),則根據5前一位數的奇偶性來判斷是否需要進位,奇數進位,偶數捨去。
依上述規則舉例,假設我們要求數字要求精確到個位:
<code>49.6101 -> 50 49.499 -> 49 49.50921 -> 50 48.50921 -> 48 48.5101 -> 49</code>
有個很好的例子可以看出這種計算方式的優點:
2.55 + 3.45 = 6
如果我們要保留一位小數,去轉換 2.55 和 3.45,則會變成這樣:
2.6 + 3.5 = 6.1
很顯然這樣多了0.1,那麼按照我們的「四捨六入五成雙」 再來計算,2.55 其實可以說是2.550,我們要捨去的5 的後面是0,則根據前面一位的奇偶判斷是否進位,很顯然前面為奇數,則進位後為2.6,對於3.45,5 前面是偶數,則捨去,結果為3.4,因此兩者計算如下:
2.6 + 3.4 = 6
有人提出了 2.55 + 2.55 實際上依舊多算了 0.1,而我為什麼沒有舉這個例子呢?因為用 四捨五入,也會存在這個情況。重點是 2.45 + 2.45,常規的四捨五入會被捨去,我們需要避免這種接近中間值卻未進位的情況,因為只有這樣,才能保證 近似計算中捨去和進位的概率相等
。這才是主要目的。畢竟只要精度有限必定存在損耗,我們只需要保證在大量樣本下,機率相等即可。
這塊的資金問題還是得考慮業務需求的。照我以前的做法,是儲存4位小數。根據不同的場景,進行取捨!但前台所有顯示的金額都只顯示2位,並向下取數
一般會向下取數
,如10.1234
;那實際可提現金額為10.12
。
如銀行額度總共為1000元,然後剛好買了一樣東西,全花了,在操作分期。分3期;
按正常思維是1000/3=333.33333333
;在四捨五入一下就成了333.33
;等你三期都還完了,發現只還了999.99
;等你三期都還完了,發現只還了
。這就坑了
一般做法是:
前2期以四捨五入計算。最後一期,以減法算:
其他說明
根據不同業務,保留位數和取捨都不一樣。如基金的淨值。小數點的長度影響的資金量還是很大的。這塊是越精準越好。具體需求跟產品溝通吧!
其實並不是這樣。我們電商財務系統在進行對帳和對傭的時候通通算到了後6位。 decimal(16, 6)在計算完後才會四捨五入。一般最後四捨五入這一步是寫在 協議裡面的,最後一步我覺得應該屬於協商的範疇吧。跟系統已經沒啥關係了。
不懂很專業的東西,但是我覺得做系統沒什麼考慮的,兩位小數後面的全部用戶損失
如果出賬0.111只出0.11
只是算到最終給用戶的由於分之後無法兌現所以就按照一定的演算法計算最終結果。
計算機中的整數1 跟小數1.0是不相等的,所以在金錢上的小數換算為整數做處理
我覺得比較穩健的方式的資料庫儲存的金額欄位計量單位使用分,這樣前台顯示的時候先取整,再除100就是元了.
計算方式得分"給"和"收",以銀行為主體的話,
"給":如果字段值是200.11 那麼算成元是2元零1.1厘..這個1.1厘可以捨去了,只給2元即可,就是說只取整數部分.
重點時,用分做金額的計量單位,如果上億的話,需要考慮下資料型別的Max,別超出範圍了.
🎜題主你居然發了金融機構秘密圈錢的手段,哈哈哈。 🎜
收款时直接把分以后的数字进位处理,付款时直接截去分以后的小数位。
展示显示2位小数不代表系统中处理都是2位小数吧。我觉得应该会有很多位
要么四舍五入,要么向下取整,保留两位
合理的均分方法可以固定小数位.
比如100元平均分成N份(保留2为小数)并计算尾差:
<code><?php header('Content-Type: text/plain; charset=utf-8'); function tail($num, $fen) { $avg = bcdiv($num, $fen, 2); //除 $tail = bcsub($num, $avg*($fen-1), 2); //减 echo $num.'='.str_repeat($avg.'+', $fen-1).$tail."\n"; echo "$num=$avg*($fen-1)+$tail\n"; return array($avg, $tail); } var_export(tail(100, 3)); var_export(tail(100, 6)); //输出: 100=33.33+33.33+33.34 100=33.33*(3-1)+33.34 array ( 0 => '33.33', 1 => '33.34', ) 100=16.66+16.66+16.66+16.66+16.66+16.70 100=16.66*(6-1)+16.70 array ( 0 => '16.66', 1 => '16.70', )</code>
4舍5入,没有什么好纠结的,相信老祖宗的智慧。
从统计学的角度上来看,在大规模的应用的情况下,你们金融系统多出来的和少掉的钱是近似的,同样的,用户多出来和少掉的钱也是近似的,没有必要纠结。
没有做过金融系统开发,权当抛砖引玉了。