216

Python 3.0の新機能を読み直したところ、次のように記載されています。

round()関数の丸め戦略と戻り値のタイプが変更されました。正確な中間のケースは、ゼロから離れるのではなく、最も近い偶数の結果に丸められるようになりました。(たとえば、round(2.5)は3ではなく2を返すようになりました。)

およびラウンドのドキュメント:

round()をサポートする組み込み型の場合、値は10の最も近い倍数からnを引いた値に丸められます。2つの倍数が等しく近い場合、丸めは偶数の選択に向けて行われます

したがって、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のコメントre"Banker's rounding"は、検索する正しい検索用語/キーワードを与えてくれました。私はこのSOの質問を見つけました:なぜ.NETは銀行家の丸めをデフォルトとして使用するのですか?、だから私はそれを注意深く読んでいきます。

4

11 に答える 11

195

Python 3の方法(「半分から偶数への丸め」または「バンカーの丸め」と呼ばれる)は、最近では標準の丸め方法と見なされていますが、一部の言語実装はまだバス上にありません。

単純な「常に0.5を切り上げる」手法では、数値が高くなる方向にわずかにバイアスがかかります。計算数が多い場合、これは重要になる可能性があります。Python 3.0のアプローチでは、この問題が解消されます。

一般的に使用される丸めには複数の方法があります。浮動小数点演算の国際標準であるIEEE754は、5つの異なる丸め方法を定義しています(Python 3.0で使用される方法がデフォルトです)。そして他にもあります

この動作は、本来あるべきほど広く知られていません。AppleScriptは、私が正しく覚えていれば、この丸め方法を早期に採用したものでした。roundAppleScriptのコマンドにはいくつかのオプションがありますが、IEEE 754の場合と同様に、ラウンドトゥワードがデフォルトです。roundコマンドを実装したエンジニアは、「学校で学んだように機能させる」というすべての要求にうんざりしていたようです。彼がそれを実装したこと:round 2.5 rounding as taught in schoolは有効なAppleScriptコマンドです。:-)

于 2012-05-31T00:24:15.787 に答える
46

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')
于 2012-05-31T01:59:12.920 に答える
20

ここにドキュメントからの重要なメモを追加するだけです:

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

ノート

floatのround()の動作は驚くべきものになる可能性があります。たとえば、round(2.675、2)は、期待される2.68ではなく2.67を返します。これはバグではありません。ほとんどの小数部を浮動小数点数として正確に表すことができないという事実の結果です。詳細については、浮動小数点演算:問題と制限を参照してください。

したがって、Python3.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)
于 2014-07-02T14:54:47.203 に答える
10

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
于 2018-10-02T11:29:25.617 に答える
8

私も最近これに問題がありました。したがって、私はこれに対処し、小学校から(銀行家の丸めではなく)使用されていたのと同じ丸め動作を与える2つの関数trueround()とtrueround_precision()を持つpython3モジュールを開発しました。これがモジュールです。コードを保存してコピーするか、インポートするだけです。注:trueround_precisionモジュールは、10進モジュールの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)

お役に立てれば、

ナルニア国物語

于 2012-12-20T00:31:32.473 に答える
4

Python3でのPython2の丸め動作。

小数点以下15桁に1を加算します。15桁までの精度。

round2=lambda x,y=None: round(x+1e-15,y)
于 2017-07-03T14:55:40.747 に答える
2

ある場合:

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)を追加する必要があります。

私のために働いてください。

于 2018-11-07T08:30:49.100 に答える
0

サンプルの複製:

['{} => {}'.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

州:

小数点以下n桁の精度に丸められた数値を返します。ndigitsが省略されているか、Noneの場合、入力に最も近い整数を返します。

round()をサポートする組み込み型の場合、値は10の最も近い倍数からn桁を引いた値に丸められます。2つの倍数が等しく近い場合、丸めは偶数の選択肢に向かって行われます(たとえば、round(0.5)とround(-0.5)は両方とも0で、round(1.5)は2です)。任意の整数値は、n桁(正、ゼロ、または負)に対して有効です。ndigitsが省略されている場合、またはNoneの場合、戻り値は整数です。それ以外の場合、戻り値は数値と同じタイプになります。

一般的なPythonオブジェクト番号の場合、デリゲートを数値に丸めます。ラウンド

注floatのround()の動作は驚くべきものになる可能性があります。たとえば、round(2.675、2)は、期待される2.68ではなく2.67を返します。これはバグではありません。ほとんどの小数部を浮動小数点数として正確に表すことができないという事実の結果です。詳細については、浮動小数点演算:問題と制限を参照してください。

この洞察を与えられて、あなたはそれを解決するためにいくつかの数学を使うことができます

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

これで、roundの代わりにmy_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']
于 2019-01-14T22:34:55.573 に答える
-3

学校で教えられているPython3.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
于 2020-01-05T09:43:55.950 に答える
-4

このコードを試してください:

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

于 2020-01-02T17:03:54.607 に答える
-6

math.ceilモジュールを使用して、丸めを制御できます。

import math
print(math.ceil(2.5))
> 3
于 2020-02-14T15:44:48.710 に答える