簡體   English   中英

將 python 小數舍入到最接近的 0.05

[英]Round python decimal to nearest 0.05

我試圖將十進制中的貨幣數字四舍五入到最接近的 0.05。 現在,我正在這樣做:

def round_down(amount):
    amount *= 100
    amount = (amount - amount % 5) / Decimal(100)
    return Decimal(amount)

def round_up(amount):
    amount = int(math.ceil(float(100 * amount) / 5)) * 5 / Decimal(100)
    return Decimal(amount)

有沒有什么辦法可以更優雅地做到這一點,而無需使用 python Decimals(可能使用 quantize)處理浮點數?

對於浮動,只需使用round(x * 2, 1) / 2 但是,這並不能控制舍入方向。

使用Decimal.quantize您還可以完全控制舍入的類型和方向(Python 3.5.1):

>>> from decimal import Decimal, ROUND_UP

>>> x = Decimal("3.426")
>>> (x * 2).quantize(Decimal('.1'), rounding=ROUND_UP) / 2
Decimal('3.45')

>>> x = Decimal("3.456")
>>> (x * 2).quantize(Decimal('.1'), rounding=ROUND_UP) / 2
Decimal('3.5')

首先要注意(四舍五入意外),只是有時會出現此問題時,數字緊接下面(左側),你要四舍五入到數字有5

>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01

但是有一個簡單的解決方案,我發現它似乎總是有效,並且不依賴於其他庫的import 解決方案是添加一個1e-X ,其中X是您嘗試在 plus 1上使用round的數字字符串的長度。

>>> round(0.075,2)

0.07

>>> round(0.075+10**(-2*6),2)

0.08

啊哈! 所以基於此我們可以制作一個方便的包裝函數,它是獨立的,不需要額外的import調用......

def roundTraditional(val,digits):
   return round(val+10**(-len(str(val))-1))

基本上,這會增加一個值,該值保證小於您嘗試使用round入的字符串的最小給定數字。 通過添加這個小數量,它在大多數情況下保留了round的行為,同時確保如果低於被四舍五入的數字是5則向上舍入,如果是4則向下舍入。

使用10**(-len(val)-1)是經過深思熟慮的,因為它是您可以添加的最大小數以強制轉換,同時還確保您添加的值永遠不會改變舍入,即使是小數. 不見了。 我可以只使用10**(-len(val))和條件if (val>1)再減去1 ......但總是減去1更簡單,因為這不會改變適用范圍此解決方法可以正確處理十進制數。 如果您的值達到類型的限制,則此方法將失敗,這將失敗,但對於幾乎整個有效十進制值范圍,它都應該有效。

您也可以使用十進制庫來完成此操作,但我建議的包裝器更簡單,並且在某些情況下可能是首選。


編輯:感謝Blckknght指出5邊緣情況僅發生在此處的某些值。

適用於任何舍入基數的更通用的解決方案。

from decimal import ROUND_DOWN
def round_decimal(decimal_number, base=1, rounding=ROUND_DOWN):
    """
    Round decimal number to the nearest base

    :param decimal_number: decimal number to round to the nearest base
    :type decimal_number: Decimal
    :param base: rounding base, e.g. 5, Decimal('0.05')
    :type base: int or Decimal
    :param rounding: Decimal rounding type
    :rtype: Decimal
    """
    return base * (decimal_number / base).quantize(1, rounding=rounding)

例子:

>>> from decimal import Decimal, ROUND_UP

>>> round_decimal(Decimal('123.34'), base=5)
Decimal('120')
>>> round_decimal(Decimal('123.34'), base=6, rounding=ROUND_UP)
Decimal('126')
>>> round_decimal(Decimal('123.34'), base=Decimal('0.05'))
Decimal('123.30')
>>> round_decimal(Decimal('123.34'), base=Decimal('0.5'), rounding=ROUND_UP)
Decimal('123.5')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM