フロートを小数点以下2桁に制限する

2009年01月19日に質問されました。  ·  閲覧回数 3.6M回  ·  ソース

kevin picture
2009年01月19日

a13.95に丸めたい。

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

round関数が期待どおりに機能しません。

回答

Rex Logan picture
2009年01月19日
1822

すべての数値を正確に表すことができないという浮動小数点数の古い問題に直面しています。 コマンドラインは、メモリからの完全な浮動小数点形式を表示しているだけです。

浮動小数点表現では、丸められたバージョンは同じ数値です。 コンピューターは2進数であるため、浮動小数点数を整数として格納し、それを2の累乗で除算します。したがって、13.95は125650429603636838 /(2 ** 53)と同様の方法で表されます。

倍精度数の精度は53ビット(16桁)で、通常の浮動小数点数の精度は24ビット(8桁)です。 Python使用して値を格納します。

例えば、

>>> 125650429603636838/(2**53)
13.949999999999999

>>> 234042163/(2**24)
13.949999988079071

>>> a = 13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a, 2))
13.95
>>> print("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999

小数点以下2桁だけの場合(たとえば、通貨値を表示する場合)、いくつかのより良い選択肢があります。

  1. 整数を使用し、値をドルではなくセントで格納してから、100で割ってドルに変換します。
  2. または、 10進数などの固定小数点数を使用し
Xolve picture
2011年07月01日
629

新しいフォーマット仕様、文字列フォーマット仕様ミニランゲージがあります:

あなたは同じことをすることができます:

"{:.2f}".format(13.949999999999999)

注1:上記は文字列を返します。 フロートとして取得するには、 float(...)ラップするだけです。

float("{:.2f}".format(13.949999999999999))

注2: float()ラッピングしても、何も変わりません。

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
chribsen picture
2016年12月31日
313

組み込みのround()は、Python2.7以降で問題なく動作します。

例:

>>> round(14.22222223, 2)
14.22

ドキュメントを確認し

grant zukowski picture
2015年01月26日
147

最も簡単なアプローチはformat()関数を使用することだと思います。

例えば:

a = 13.949999999999999
format(a, '.2f')

13.95

これにより、小数点以下2桁に丸められた文字列として浮動小数点数が生成されます。

Alexey Antonenko picture
2017年08月04日
99

使用する

print"{:.2f}".format(a)

の代わりに

print"{0:.2f}".format(a)

後者は、複数の変数を出力しようとすると出力エラーにつながる可能性があるためです(コメントを参照)。

Roger Pate picture
2009年01月19日
98

ほとんどの数値は、浮動小数点数で正確に表すことはできません。 数式やアルゴリズムに必要な数値を丸めたい場合は、roundを使用します。 表示を特定の精度に制限したいだけの場合は、roundを使用せずに、その文字列としてフォーマットするだけです。 (別の丸め方法で表示したいが、トンがある場合は、2つのアプローチを組み合わせる必要があります。)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

そして最後に、おそらく最も重要なことですが、正確な計算が必要

ax003d picture
2013年08月26日
68

以下のコードを試してください。

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
Matt Fletcher picture
2017年12月12日
65

ここではまだ誰も言及していないようですので、Python3.6のf-string / template-string形式で例を挙げましょう。これは、美しくきれいだと思います。

>>> f'{a:.2f}'

これは、演算子を使用し、親を必要としない、より長い例でもうまく機能します。

>>> print(f'Completed in {time.time() - start:.2f}s')
hynekcer picture
2016年02月01日
59

TLDR;)

入出力の丸め問題は、 Python2.7.0および3.1によって明確に解決

正しく丸められた数値は、可逆的に前後に変換できます。
str -> float() -> repr() -> float() ...またはDecimal -> float -> str -> Decimal
10進型はストレージに必要なくなりました。


(当然、累積されたラストビットエラーを排除するために、丸められた数値の加算または減算の結果を丸める必要がある場合があります。明示的な10進演算は依然として便利ですが、 str()による文字列への変換(つまり、有効な12桁に丸める)は、通常、極端な精度や連続する算術演算の極端な数が必要ない場合に十分です。)

無限のテスト

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

ドキュメンテーション

リリースノートPython2.7を参照してください

浮動小数点数と文字列の間の変換は、ほとんどのプラットフォームで正しく丸められるようになりました。 これらの変換は、さまざまな場所で発生します。浮動小数点数と複素数のstr()。 floatおよびcomplexコンストラクター。 数値フォーマット; marshalpickle 、およびjsonモジュールを使用して、浮動小数点数と複素数をシリアル化および逆シリアル化します。 Pythonコードでのfloatおよび虚数リテラルの解析。 10進数から浮動小数点への変換。

これに関連して、浮動小数点数xのrepr()は、正しい丸めの下でxに丸め最短の10進文字列に基づいた結果を返すようになりました(丸めの半分から偶数の丸めモードを使用)。 以前は、xを10進数の17桁に丸めることに基づいて文字列を提供していました。

関連する問題


詳細: Python 2.7より前のfloatのフォーマットは、現在のnumpy.float64と同様IEEE754倍精度を使用します。 大きな違いは、 np.float64.__repr__が過剰な10進数で頻繁にフォーマットされるため、ビットが失われることはありませんが、13.949999999999999と13.950000000000001の間に有効なIEEE754番号が存在しないことです。 結果は良くなく、変換repr(float(number_as_string))はnumpyで元に戻せません。 一方、 float.__repr__は、すべての桁が重要になるようにフォーマットされています。 シーケンスにはギャップがなく、変換は可逆的です。 簡単に言うと、numpy.float64の数値がある場合は、数値プロセッサではなく人間向けにフォーマットするために、通常のfloatに変換します。それ以外の場合は、Python2.7以降では何も必要ありません。

Greg Hewgill picture
2009年01月19日
53

出力形式は次のように変更できます。

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95