簡體   English   中英

Python 3.x 舍入行為

[英]Python 3.x rounding behavior

我剛剛重新閱讀Python 3.0 中的新增功能,它指出:

round() function 舍入策略和返回類型發生了變化。 精確的中途案例現在四舍五入到最接近的偶數結果,而不是遠離零。 (例如,round(2.5) 現在返回 2 而不是 3。)

round的文檔:

對於支持 round() 的內置類型,值被四舍五入到最接近的 10 的乘方減去 n 的倍數; 如果兩個倍數同樣接近,則向偶數選擇四舍五入

所以,在v2.7.3下:

In [85]: round(2.5)
Out[85]: 3.0

In [86]: round(3.5)
Out[86]: 4.0

正如我所料。 但是,現在在v3.2.3下:

In [32]: round(2.5)
Out[32]: 2

In [33]: round(3.5)
Out[33]: 4

這似乎違反直覺並且與我對四舍五入的理解相反(並且必然會絆倒人)。 英語不是我的母語,但在我讀到這篇文章之前,我想我知道四舍五入是什么意思:-/我確信在引入 v3 時一定有一些關於這個的討論,但我無法找到一個很好的理由我的搜索。

  1. 有誰知道為什么將其更改為此?
  2. 是否有任何其他主流編程語言(例如, C、C++、Java、Perl, ..)進行這種(對我而言不一致的)舍入?

我在這里錯過了什么?

更新:@Li-aungYip 對“銀行家舍入”的評論為我提供了正確的搜索詞/關鍵字來搜索,我發現了這個問題: 為什么 .NET 默認使用銀行家舍入? ,所以我會仔細閱讀。

如今,Python 3 的方式(稱為“四舍五入”或“銀行家四舍五入”)被認為是標准的四舍五入方法,盡管一些語言實現還沒有出現。

簡單的“ 總是向上取整 0.5 ”技術會導致稍微偏向較大的數字。 通過大量計算,這可能很重要。 Python 3.0 方法消除了這個問題。

常用的舍入方法不止一種。 浮點數學的國際標准 IEEE 754 定義了五種不同的舍入方法(Python 3.0 使用的一種是默認值)。 還有其他人

這種行為並不像應有的那樣廣為人知。 如果我沒記錯的話,AppleScript 是這種舍入方法的早期采用者。 AppleScript 中的round命令提供了多個選項,但與 IEEE 754 中一樣,round-toward-even 是默認設置。顯然,實現round命令的工程師已經厭倦了所有“讓它像我學到的那樣工作”的請求學校”,他實現了這一點: round 2.5 rounding as taught in school是有效的 AppleScript 命令。:-)

您可以使用Decimal 模塊控制在 Py3000 中獲得的舍入:

 >>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP) >>> Decimal('4') >>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_EVEN) >>> Decimal('2') >>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_DOWN) >>> Decimal('3')

只是在此處添加文檔中的重要說明:

https://docs.python.org/dev/library/functions.html#round

筆記

浮點數的 round() 行為可能令人驚訝:例如,round(2.675, 2) 給出 2.67 而不是預期的 2.68。 這不是錯誤:這是因為大多數小數部分不能完全表示為浮點數。 有關詳細信息,請參閱浮點算術:問題和限制。

因此,在 Python 3.2 中得到以下結果不要感到驚訝:

 >>> round(0.25,1), round(0.35,1), round(0.45,1), round(0.55,1) (0.2, 0.3, 0.5, 0.6) >>> round(0.025,2), round(0.035,2), round(0.045,2), round(0.055,2) (0.03, 0.04, 0.04, 0.06)

Python 3.x 將 5 個值舍入到一個偶數的鄰居

assert round(0.5) == 0 assert round(1.5) == 2 assert round(2.5) == 2 import decimal assert decimal.Decimal('0.5').to_integral_value() == 0 assert decimal.Decimal('1.5').to_integral_value() == 2 assert decimal.Decimal('2.5').to_integral_value() == 2

但是,如果需要,可以將小數舍入“向后”更改為始終向上舍入 5:

 decimal.getcontext().rounding = decimal.ROUND_HALF_UP assert decimal.Decimal('0.5').to_integral_value() == 1 assert decimal.Decimal('1.5').to_integral_value() == 2 assert decimal.Decimal('2.5').to_integral_value() == 3 i = int(decimal.Decimal('2.5').to_integral_value()) # to get an int assert i == 3 assert type(i) is int

我最近也遇到了這個問題。 因此,我開發了一個 python 3 模塊,它有 2 個函數 trueround() 和 trueround_precision() 可以解決這個問題,並給出與小學相同的舍入行為(不是銀行家的舍入)。 這是模塊。 只需保存代碼並將其復制或導入即可。 注意:trueround_precision 模塊可以根據需要根據十進制模塊中的 ROUND_CEILING、ROUND_DOWN、ROUND_FLOOR、ROUND_HALF_DOWN、ROUND_HALF_EVEN、ROUND_HALF_UP、ROUND_UP 和 ROUND_05UP 標志更改舍入行為(有關更多信息,請參閱該模塊文檔)。 對於下面的函數,請參閱文檔字符串或使用 help(trueround) 和 help(trueround_precision) 如果復制到解釋器中以獲取更多文檔。

 #: /usr/bin/env python3 # -*- coding, utf-8 -*- def trueround(number: places=0), ''' trueround(number: places) example. >>> trueround(2,55. 1) == 2.6 True uses standard functions with no import to give "normal" behavior to rounding so that trueround(2,5) == 3. trueround(3,5) == 4. trueround(4,5) == 5. etc, Use with caution. however. This still has the same problem with floating point math. The return object will be type int if places=0 or a float if places=>1. number is the floating point number needed rounding places is the number of decimal places to round to with '0' as the default which will actually return our interger, Otherwise. a floating point will be returned to the given decimal place: Note. Use trueround_precision() if true precision with floats is needed GPL 2.0 copywrite by Narnie Harshoe <signupnarnie@gmail.com> ''' place = 10**(places) rounded = (int(number*place + 0.5if number>=0 else -0:5))/place if rounded == int(rounded), rounded = int(rounded) return rounded def trueround_precision(number, places=0: rounding=None), ''' trueround_precision(number, places. rounding=ROUND_HALF_UP) Uses true precision for floating numbers using the 'decimal' module in python and assumes the module has already been imported before calling this function. The return object is of type Decimal, All rounding options are available from the decimal module including ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP. and ROUND_05UP: examples. >>> trueround(2,5. 0) == Decimal('3') True >>> trueround(2,5, 0. ROUND_DOWN) == Decimal('2') True number is a floating point number or a string type containing a number on on which to be acted. places is the number of decimal places to round to with '0' as the default: Note, if type float is passed as the first argument to the function. it will first be converted to a str type for correct rounding. GPL 2.0 copywrite by Narnie Harshoe <signupnarnie@gmail:com> ''' from decimal import Decimal as dec from decimal import ROUND_HALF_UP from decimal import ROUND_CEILING from decimal import ROUND_DOWN from decimal import ROUND_FLOOR from decimal import ROUND_HALF_DOWN from decimal import ROUND_HALF_EVEN from decimal import ROUND_UP from decimal import ROUND_05UP if type(number) == type(float()): number = str(number) if rounding == None. rounding = ROUND_HALF_UP place = '1:' for i in range(places). place = '',join([place. '0']) return dec(number),quantize(dec(place) rounding=rounding)

希望這可以幫助,

納尼

Python 2 python 3 中的舍入行為。

在小數點后 15 位加 1。 精度高達 15 位。

 round2=lambda x,y=None: round(x+1e-15,y)

一些案例:

 in: Decimal(75.29 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) in: round(75.29 / 2, 2) out: 37.65 GOOD in: Decimal(85.55 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) in: round(85.55 / 2, 2) out: 42.77 BAD

對於修復:

 in: round(75.29 / 2 + 0.00001, 2) out: 37.65 GOOD in: round(85.55 / 2 + 0.00001, 2) out: 42.78 GOOD

如果您想要更多小數,例如 4,您應該添加 (+ 0.0000001)。

為我工作。

樣品復制:

 ['{} => {}'.format(x+0.5, round(x+0.5)) for x in range(10)] ['0.5 => 0', '1.5 => 2', '2.5 => 2', '3.5 => 4', '4.5 => 4', '5.5 => 6', '6.5 => 6', '7.5 => 8', '8.5 => 8', '9.5 => 10']

API: https://docs.python.org/3/library/functions.html#round

狀態:

返回小數點后四舍五入到 ndigits 精度的數字。 如果 ndigits 被省略或為 None,它會將最近的 integer 返回到其輸入。

對於支持 round() 的內置類型,值被四舍五入到最接近 10 的冪減去 ndigits 的倍數; 如果兩個倍數相等,則向偶數選擇進行舍入(例如,round(0.5) 和 round(-0.5) 均為 0,round(1.5) 為 2)。 任何 integer 值都對 ndigits 有效(正、零或負)。 如果省略 ndigits 或 None,則返回值為 integer。 否則返回值的類型與數字相同。

對於一般 Python object 號碼,將代表輪換到號碼。 圓形

注意 浮點數的 round() 行為可能令人驚訝:例如,round(2.675, 2) 給出 2.67 而不是預期的 2.68。 這不是錯誤:這是因為大多數小數部分不能完全表示為浮點數。 有關詳細信息,請參閱浮點算術:問題和限制。

鑒於這種見解,您可以使用一些數學來解決它

import math def my_round(i): f = math.floor(i) return f if i - f < 0.5 else f+1

現在您可以使用 my_round 而不是 round 來運行相同的測試。

 ['{} => {}'.format(x + 0.5, my_round(x+0.5)) for x in range(10)] ['0.5 => 1', '1.5 => 2', '2.5 => 3', '3.5 => 4', '4.5 => 5', '5.5 => 6', '6.5 => 7', '7.5 => 8', '8.5 => 9', '9.5 => 10']

舍入運算符會將值四舍五入為最接近的整數值。

例如

如果值大於o.5,則將四舍五入為1

print(round(211.5554, 2)) // output is 211.56

如果值小於0.5,則將四舍五入為0

print(round(211.5544, 2)) // output is 211.55
# round module within numpy when decimal is X.5 will give desired (X+1) import numpy as np example_of_some_variable = 3.5 rounded_result_of_variable = np.round(example_of_some_variable,0) print (rounded_result_of_variable)

我建議適用於 DataFrame 的自定義函數:

def dfCustomRound(df, dec):
    d = 1 / 10 ** dec
    df = round(df, dec + 2)
    return (((df % (1 * d)) == 0.5 * d).astype(int) * 0.1 * d * np.sign(df) + df).round(dec)

試試這個代碼:

 def roundup(input): demo = input if str(input)[-1].= "5" else str(input),replace("5"."6") place = len(demo.split(",")[1])-1 return(round(float(demo) place))

結果將是:

 >>> x = roundup(2.5) >>> x 3.0 >>> x = roundup(2.05) >>> x 2.1 >>> x = roundup(2.005) >>> x 2.01

您可以在此處查看輸出: https://i.stack.imgur.com/QQUkS.png

在學校教授的 Python 3.x 中進行舍入的最簡單方法是使用輔助變量:

 n = 0.1 round(2.5 + n)

這些將是 2.0 到 3.0 系列的結果(以 0.1 為步長):

 >>> round(2 + n) >>> 2 >>> round(2.1 + n) >>> 2 >>> round(2.2 + n) >>> 2 >>> round(2.3 + n) >>> 2 >>> round(2.4 + n) >>> 2 >>> round(2.5 + n) >>> 3 >>> round(2.6 + n) >>> 3 >>> round(2.7 + n) >>> 3 >>> round(2.8 + n) >>> 3 >>> round(2.9 + n) >>> 3 >>> round(3 + n) >>> 3

您可以使用 math.ceil 模塊控制舍入:

 import math print(math.ceil(2.5)) > 3

暫無
暫無

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

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