python 正確四捨五入的姿勢

說起python中的四捨五入的問題,可能還有部分童鞋不太清楚,會說四捨五入有啥可說道的,round 大法走天下。如果你在金融,電商等相關領域有過開發經驗的話,可能對我說的這個問題,有過深刻的理解,畢竟這個問題折磨的可不止python從業者。

假設有這麼一個場景, 用戶在電商網站挑選商品,根據商品價格 (price),購買數量 (quantity),

計算用戶應付金額 (pay)

你會怎麼做呢。

price * quantity = pay

這個公式相信大家都會的,但是如果你直接把得出的pay 不加處理的話,肯定是會有問題的。

比如price = 1.25 quantity = 1.3 那麼應付的錢數為 1.25 * 1.3 = 1.625

但是由於錢的最小單位是 分, 所以小數點後兩位為有效數字。即1.63 才是我們想要的數字。

那麼1.625 怎麼正確的變為1.63 就是今天要和大家討論的話題。

方案一: round

大家都知道python 中的round 是專門用來四捨五入的,第一時間都相到了用round.

於是, 但是大家通過round計算發現 round(1.625, 2) = 1.62

python 正確四捨五入的姿勢

這是什麼原因呢。有人說 round 遵循 四捨六入五平分,啥意思呢,也就是如果最後

一位是5的情況下,是進一位還是捨棄這兩種情況五五開。其實也不難理解計算機是二進制

的,有些浮點數在計算機中不能被正確的表達,它可能是一個近似值,所以就出現了這種情況。

所以說round不太適合做精確的四捨五入。

估計會有童鞋抬槓,說不是還有一種方法嗎,將數值放大100倍

就可以實現保留2位小數的精確四捨五入。咱也不廢話,直接上圖。

python 正確四捨五入的姿勢

1.115 通過round普通方法,缺失會出現四捨五入的問題。但是 通過數值放大100倍處理

我們發現,缺失能正確的四捨五入了。但是通過這種方法計算本例中的1.625, 會發現依然

沒有奏效。

也不曉得是不是還要更為有效的辦法,能夠解決這個問題

反正自從我知道這個問題,並嘗試改進round無法奏效後就放棄了round

方案二: decimal

這是網上呼聲最高的解決方案了。我們先來看下效果。

python 正確四捨五入的姿勢

一切似乎是對的。但是在作者使用過程中,發現依然會產生該進位的沒進位的情況。

python 正確四捨五入的姿勢

似乎沒比round高級到哪裡去呢。帶著疑問我們去網上找資料,但是網上一堆博客文章

都在講decimal是專門用來高精度計算的,如何如何。既然吹的牛皮震天響,那麼怎麼解決

這個問題呢。

python 正確四捨五入的姿勢

我們觀察到上圖有這麼一句話

getcontext().rounding = "ROUND_HALF_UP"

這句話的作用就是設置decimal的舍入方式為真正的四捨五入的。

那麼默認的舍入方式是什麼呢

python 正確四捨五入的姿勢

我們發現默認的舍入方式 是ROUND_HALF_EVEN, 大概也能猜出來,即前面猜的五平分的意思

那麼rounding 還有那些值呢。

ROUND_HALF_DOWN:5,則做進位操作;否則捨棄;

ROUND_HALF_UP:末位大於等於5,則做進位操作;否則捨棄;

ROUND_HALF_EVEN:默認情況看下圖,摘抄互聯網。

python 正確四捨五入的姿勢

還有一些其它值,感興趣的可以看下官方文檔

https://docs.python.org/zh-cn/3/library/decimal.html

看到有人說通過decimal還可以設置精度。

某博客是這樣說的

python 正確四捨五入的姿勢

getcontext().prec = 2

按照這樣的理解,這樣就保留小數點後兩位,事實真的如此嗎。

python 正確四捨五入的姿勢

貌似不起作用嘛,那麼這個prec該怎麼理解才是正確的呢

我們注意到官方文檔有這麼一段

python 正確四捨五入的姿勢

看到了嗎,該屬性,盡在運算的時候才發揮作用,而且也不是小數點後的精度,

它表示的是幾位有效數字。

由此看來 decimal 不愧是用做精確運算的。

作者之前雖然知道decimal, 但是在解決問題中,遇到四捨五入的問題避開了,

手動寫了個處理方法,與這種方式相比麻煩許多,但是程序經過節假日大促的考驗,

倒也沒出過錯,大概思路就是把小數轉化為字符串,然後把小數點前後數字拆開,通過

整數運算後,在拼成字符串,然後轉換成float 或其它想要的類型。再次就不獻醜了。

如果有更好的更簡單的方案,歡迎大家下發留言討論。

"


分享到:


相關文章: