你有用對型別存金額嗎?

先說個冷知識,你知道根據 RFC 4217 的定義,新臺幣可以到小數點(decimal point)後 2 位嗎?

數值一但牽扯到小數點,就會有所謂的浮點數精度問題(floating-point precision issues), 因為浮點數沒有精確的 2 進制表示法,所以它其實是 1 個極度近似值,你以為數值的 0.3 ,對電腦而言可能是 0.30000000000000004 。

這種問題會對電商、加密貨幣交易所帶來困擾(比特幣可以到小數點後 8 位數,這個單位又稱 satoshi, 也就是中本聰的聰 ),畢竟金額、價格應該多少就該多少,不能多也不能少,所以在儲存金額、價格時都要特別注意。

資料庫儲存金額數值(monetary values)有 2 種方法:

  1. 使用 Decimal 型別,有別於 Float, Double 這類型別, Decimal 型別不會產生浮點數精度問題,使用 Decimal 可以定義精度,例如 Decima(5, 2) 就代表可以顯示 5 位數,包含小數點後 2 位數,所以可以儲存數值 -999.99 到 999.99 。

  2. 使用 Integer 型別,這個解法的思路就是把產生問題的小數點給解決掉。具體怎麼解決?例如金額 10.25 ,就將金額乘以 100 變成 1025 存起來,要使用的時候再除以 100 還原即可。

這 2 種解法各有優缺,用 Decimal 的讀寫效率比用 Integer 差一些,但是用 Integer 的話會在需要增加小數點位數時,對資料庫的資料以及程式碼做變動,譬如從 2 位變 3 位時,資料庫所有數值都得再額外乘以 10 更新,程式碼在存數值之前或讀數值之後都得改為乘以 1,000 或除以 1,000 。

此外,還有 1 種情況也是用 Integer 需要注意的,例如訂單金額算出來是 3.2 USD, 手續費是 0.1 USD 時,當你在程式碼中做加總顯示總金額時,就有可能再遇到浮點數精度問題,這個可以用以下 Python 程式碼示範:

>>> 320/100 + 10/100
3.3000000000000003

當然,最好這種加總可以也先算好 330 再存進去資料庫避免浮點數精度問題,或者交給資料庫計算,例如 MySQL 對於 320/100 這種運算會預設轉為 Decimal, 所以加總也不會有浮點數問題,見圖 1, 圖 2 。

圖 1:

fig1

圖 2:

fig-2

以上,就是關於如何儲存金額的探討。

FOLLOW US

對抗久坐職業傷害

研究指出每天增加 2 小時坐著的時間,會增加大腸癌、心臟疾病、肺癌的風險,也造成肩頸、腰背疼痛等常見問題。

然而對抗這些問題,卻只需要工作時定期休息跟伸展身體即可!

你想輕鬆改變現狀嗎?試試看我們的 PomodoRoll 番茄鐘吧! PomodoRoll 番茄鐘會根據你所設定的專注時間,定期建議你 1 項辦公族適用的伸展運動,幫助你打敗久坐所帶來的傷害!

贊助我們的創作

看完這篇文章了嗎? 休息一下,喝杯咖啡吧!

如果你覺得 MyApollo 有讓你獲得實用的資訊,希望能看到更多的技術分享,邀請你贊助我們一杯咖啡,讓我們有更多的動力與精力繼續提供高品質的文章,感謝你的支持!