浮動小数点数を小数点以下2桁に制限する


1691

13.95aに四捨五入したい。

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

round機能は、私が期待されるように動作しません。



6
うーん...あなたは通貨を表現しようとしていますか?もしそうなら、あなたはドルのためにフロートを使用するべきではありません。おそらく、ペニー、またはモデル化しようとしている通貨の最小共通単位が何であれ、浮動小数点数を使用できますが、ベストプラクティスは、HUAGHAGUAHが彼の答えで示唆したように、10進数表現を使用することです。
SingleNegationElimination 2009

63
通貨を浮動小数点で表現しないことが重要です。フロートは正確ではありません。しかし、ペニーまたはセントの金額は整数です。したがって、整数は通貨を表す正しい方法です。
Davoud Taghawi-Nejad

2
@ DavoudTaghawi-Nejadまたは要点... 10進数タイプ
基本

17
私はおそらくここに来るのが遅すぎますが、Pythonの開発者がこの問題を解決したのでしょうか?丸めを行うと(13.949999999999999、2)、13.95になるだけです。Python 2.7.6と3.4で試しました。できます。2009年に2.7があったかどうかはわかりません。たぶんそれはPython 2.5の問題でしょうか?
bad_keypoints 2015

回答:


1690

あなたはに実行されている古い問題ではない、すべての数字が正確に表現することができます浮動小数点数を持ちます。コマンドラインは、メモリから完全な浮動小数点形式を表示しているだけです。

浮動小数点表現では、丸められたバージョンは同じ数です。コンピュータはバイナリなので、浮動小数点数を整数として格納し、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. または、decimalのような固定小数点数を使用します

27
@Christian保存されている値とその値の表示方法には基本的な違いがあります。出力の書式設定など、必要に応じて、あなたはパディングを追加できるようにするだけでなく、カンマ区切り文字を追加する必要があります
基本

22
"%.2f" % round(a,2)printfだけでなく、str()
andilabsに

20
なぜ人々は常に浮動小数点の丸めで通貨を仮定するのですか?精度を下げて作業したい場合もあります。
2014年

9
@radtek:(タイプのfloat)バイナリ値は、10進数の最も近い利用可能な近似値(人間としてよく知られている)であることを理解する必要があります。0.245のような(有限に表現可能な)バイナリ値はありません。それは単に存在せず、数学的に存在できません。0.245に最も近いバイナリ値は0.245 よりわずかに小さいため、自然に切り捨てられます。同様に、バイナリには0.225のようなものはありませんが、0.225に最も近いバイナリ値は0.225 よりわずかに大きいため、当然切り上げられます。
John Y

12
@radtek:あなたは文字通り説明を求めました。最も簡単な解決策は確かにを使用することDecimalであり、これはこの回答で提示された解決策の1つでした。もう1つは、数量を整数に変換し、整数演算を使用することでした。これらのアプローチはどちらも、他の回答やコメントにも記載されています。
John Y

586

新しいフォーマット仕様、String Format Specification Mini-Languageがあります。

以下と同じことができます:

"{:.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

17
うまくすることができますとしてカンマを追加し'{0:,.2f}'.format(1333.949999999)た印刷物'1,333.95'
スティーブンブルム

@OnurYıldırım:はい、ただしでラップできfloat()ます。float("{0:.2f}".format(13.9499999))
ジョセフハルシュ14

5
@JossefHarush float()でラップできますが、何も得ていません。これでフロートが再び得られましたが、まったく同じ不正確さがありました。13.9499999999999と13.95は同じフロートです。
Ned Batchelder 14

4
@NedBatchelder:それらは等しいことに同意しますが、これにより浮動小数点数は小数点以下2桁に制限されます:)
Jossef Harush 14

8
ちなみに、Pythonの3.6以来、我々は、F-文字列を使用することができますf"Result is {result:.2f}"
アンドレイSemakin

289

ビルトインround()はPython 2.7以降で問題なく動作します。

例:

>>> round(14.22222223, 2)
14.22

ドキュメントを確認しください。


1
これはPython 2.7の失敗であることを理解できますか?なぜそのような基本的な関数はv 2.7とv 3で異なる結果をもたらすのでしょうか?
MikeM 2017

しかしround(2.16, 1)2.2なぜPython がtruncatefuncを提供するのかを説明します
ジャモ2018年

あなたは2桁まで値2.675を丸めるしようとする場合たとえば、あなたはこの取得>>> round(2.675, 2) 2.67 docs.python.org/2/tutorial/floatingpoint.html
danger89

4
Python 3のドキュメントページから:Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
Richard Dally

この方法を使用して1.00000などの数値を出力しようとすると、指定した小数点の数に関係なく、1.0のみが出力されます。
Josh Correia

142

format()関数を使うのが一番簡単だと思います。

例えば:

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

13.95

これにより、浮動小数点数が小数点以下2桁に丸められたストリングとして生成されます。


97

使用する

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

の代わりに

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

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


2
これはナンセンスです。指定された2つのステートメントはPython 2.7でも同じように動作し、2番目のステートメントのみがPython 2.6で有効です。(どちらのステートメントも、Python 3またはPython <2.6では有効ではありません。)最初の形式には、簡潔さ以外に利点はありません。
マークディキンソン

1
つまり、print "{0:.2f} {0:.2f}"。format(a、b)を実行すると、出力に誤りが生じ、「a」の値が2回出力されます。印刷中 "{:.2f} {:.2f}"。format(a、b)は 'a'と 'b'の値を出力します。
Alexey Antonenko

2
Python 3の場合は、ブラケットprint(...)を追加するだけです。そしてそれらの中で私が書いたすべてが正しいです。
Alexey Antonenko、

"つまり、印刷" {0:.2f} {0:.2f} "。format(a、b)は、出力の誤りにつながります。ああ。まあ、それはまったく別の声明です!多分あなたはあなたの答えを編集する必要がありますか?(たとえば、現在の回答で「エラーを発生させる」とはどういう意味ですか?2番目のステートメントが例外を発生させたが、最初のステートメントは例外を発生させなかった場合の例を挙げられますか?)
Mark Dickinson

3
2つの変数がある場合、print( "{0:.2f} {1:.2f}"。format(a、b))の後になります
Hovo

95

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

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

そして最後に、おそらく最も重要なことですが、正確な数学が必要場合は、浮動小数点数はまったく必要ありません。通常の例では、お金を扱い、「セント」を整数として格納します。


68

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

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99

ただし、aの値は依然として不正確な浮動小数点数であることに注意してください。ここを見てください-repl.it/LJs(右側のセクションの上部にある[Run Session]をクリックします)。
2013年

3
このアプローチを採用する場合、より正確な表現のために0.5を追加する必要があります。int(a * 100 + 0.5)/ 100.0; math.ceilを使用することもできます。
arhuaco 2013年

3
@ShashankSawant:まあ、一つには、提示された答えは丸められず、切り捨てられます。最後に半分を追加するという提案は丸められroundますが、そもそも関数を使用するだけでは、これを行うメリットはありません。さらに、このソリューションは依然として浮動小数点を使用しているため、この「ソリューション」の「修正」バージョンでも、OPの元の問題が残っています。
John Y

3
-1、これはround(質問で使用された)関数の不必要な再実装です。
interjay 2014

4
@interjayはround()、OPが言及したとおりに機能しない場合に必要です。
ピティコス2015

57

TLDR;)

入力/出力の丸め問題は、Python 2.7.0および3.1で完全に解決れました

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


(当然のことながら、累積された最後のビットエラーを排除するために、丸められた数値の加算または減算の結果を丸めることが必要になる場合があります。明示的な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+ :-)

ドキュメンテーション

4番目の段落のリリースノート「Python 2.7-その他の言語の変更」を参照してください。

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

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

関連する問題


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


なぜ反対票を投じたのですか?問題は、numpy.doubleとその文字列への変換ではなく、Python float(倍精度)とnormal roundに関するものでした。プレーンなPythonの丸めは、Python 2.7よりも優れた方法で行うことはできません。回答のほとんどは2.7より前に書かれたものですが、もともと非常に優れていたものの、時代遅れになっています。これが私の答えの理由です。
hynekcer

1「段階的アンダーフロー」時を除いて、暗黙的に「隠しビット」を含めると53ビット。
リックジェームズ

それは、丸のせいではなく、表示のせいです。
リックジェームズ

はい、それはよく知られています。しかし、Python 2.7リリースノートや私のテキストで何かに異議を唱えたり、まったく何にも反対したりしないと、コンテキストがありません。この質問の目的に必要以上に複雑です。それに起因して、文字列から浮動小数点への変換は、Python 2.7で修正されたことを追加しなければならない特定の32ビットIntelチップ上のバグを丸め、その「ラウンド()関数でもある、正しく丸められました」。(リリースノート-2.7にバックポートされた3.1の機能)。同意できますか?
hynekcer

1
おっと、それはa*bvs b*aでした。リンクをありがとう-ノスタルジア。
リックジェームズ

52

Python <3(例:2.6または2.7)では、2つの方法があります。

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

ただし、Pythonのバージョンが3を超える場合(3.2または3.3など)、オプション2が推奨されます。

オプション2の詳細については、Pythonドキュメントの文字列フォーマットに関するこのリンクをお勧めします

オプション1の詳細については、このリンクで十分であり、さまざまなフラグに関する情報があります。

リファレンス:浮動小数点数を特定の精度に変換してから文字列にコピーする


どのように整数を表現しますか?「{i3}」。format(numvar)を使用すると、エラーが発生します。
skytux 2013

これが私の言いたいことです。もしの場合numvar=12.456、結果は"{:.2f}".format(numvar)得られます12.46"{:2i}".format(numvar)、エラーが発生し、期待してい12ます。
skytux 2013


47

ここではまだ誰も言及していないようですので、Python 3.6のf-string / template-string形式の例を挙げましょう。

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

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

>>> print(f'Completed in {time.time() - start:.2f}s')

39

pythonでは、フォーマット演算子を使用して、小数点以下2桁まで値を丸めることができます。

print(format(14.4499923, '.2f')) // output is 14.45

4
これは文字列を返します
Jemshit Iskenderov

29

Python 2.7の場合:

a = 13.949999999999999
output = float("%0.2f"%a)
print output

1
これはまったく役に立ちません。outputまったく同じ値を持っているaので、最後の行のprint a代わりに書き込んだ方がよいかもしれませんprint output
マークディキンソン

@MarkDickinsonもう一度試してください。それは私のコンパイラで期待どおりに実行されているためです。
Shashank Singh 2018

1
あなたは私のポイントを逃しています。はい、コードで印刷され13.95ます。しかしprint a、この特定の値のa場合、Python 2.7でも同様です。そのため、フォーマット手順のポイントが何であったかは明確ではありません。
マークディキンソン

@MarkDickinsonコードを編集しました。「print a」は「print output」と同じ値を印刷することに同意します。ただし、「a == output」を比較すると、フォーマットのステップでは浮動小数点値「a」が小数点以下2桁に丸められるため、結果は「False」になります。
Shashank Singh 2018

1
実際にa == output表示したコードを試しましたか?それはTrue私に与えてくれますし、あなたにもそうだと思います。
マークディキンソン

22

Pythonチュートリアルには、「浮動小数点演算:問題と制限」という付録があります。それを読んで。何が起こっているのか、なぜPythonが最善を尽くしているのかを説明しています。あなたに合った例さえあります。少し引用させてください:

>>> 0.1
0.10000000000000001

このround() 関数を使用して、期待する1桁に戻すように誘惑されるかもしれません。しかし、それでも違いはありません。

>>> round(0.1, 1)
0.10000000000000001

問題は、に格納された2進浮動小数点値“0.1” がすでにへの可能な最高の2進近似であったため1/10、再度丸めることはそれを改善することはできません。

もう1つの結果は、0.1 が正確1/10ではないため、の10個の値を合計しても正確に0.1は得られない場合があること 1.0です。

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

問題の1つの代替策と解決策は、decimalモジュールを使用することです。




11

Decimalオブジェクトとround()メソッドの組み合わせを使用します。

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')

7

PythonやJavaScriptなどの型動的言語の浮動小数点を修正するために、この手法を使用します

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

Decimalを次のように使用することもできます。

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')

1
getcontext().prec = 6関数のスコープだけで機能するのか、それともすべての場所で機能するのか?
Julio Marins、2017年

1
コンテキストは算術演算のための環境です。これらは精度を管理し、丸めのルールを設定し、どの信号を例外として扱うかを決定し、指数の範囲を制限します。各スレッドには独自の現在のコンテキストがあります@JulioMarins
Siamand

7
from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

結果:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'

6
orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54


5

このようなラムダ関数についてはどうですか?

arred = lambda x,n : x*(10**n)//1/(10**n)

この方法であなたはただ行うことができます:

arred(3.141591657,2)

そして得る

3.14

4

これは、1,2,3のように単純です。

  1. 10進モジュールを使用して、正しく丸められた10進浮動小数点演算を高速化します。

    d = 10進数(10000000.0000009)

丸めを達成するには:

   d.quantize(Decimal('0.01'))

結果は Decimal('10000000.00')

  1. 上記のDRYを作る:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

または

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. この回答を賛成してください:)

PS:他の人の批評:フォーマットは丸めではありません。


2

数値を分解能に丸めるには、次の方法が最適です。これは、任意の分解能で機能します(小数点以下2桁に対して0.01、またはその他のステップ)。

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0

python 3.4.3とnumpy 1.9.1では動作しませんか?>>> numpyをnpとしてインポート>>> res = 0.01 >>>値= 0.184 >>> np.round(value / res)* res 0.17999999999999999
szeitlin

1
ドキュメンテーションを探していると、問題がnumpy.round正確さ/正確さに起因していることがわかります。したがって、解像度と乗算する前に、それをintとして定義する必要があります。コードを更新しました。有難うございます!
iblasi

必要なのはnumpy.float64、np.roundの結果をに変換するfloatか、単にを使用することだけround(value, 2)です。13.949999999999999(= 1395 / 100.)と3.950000000000001(= 1395 * .01)の間には、有効なIEEE 754番号はありません。あなたの方法が最高だと思うのはなぜですか?元の値13.949999999999999289(= value = round(value、2))は、13.95000000000000178(np.float96で出力)よりも正確です。numpyに関する詳細情報も私の回答に追加されました。もともとは派手なものではありませんでした。
hynekcer

@hynekcer私の答えは最高だとは思いません。制限フロートの例をn桁に追加したかったが、定義された解像度に最も近い。私はあなたが言ったように、intあなたの代わりにfloat@szeitlinの例にも使用できることを確認しました。追加のコメントありがとうございます。(申し訳ありませんが、私はあなたに反対票を投じませんでした)
iblasi '15

数値処理(パンダ)にまったく新しい依存関係を追加することが「最善の方法」ですか?
Hejazzman


-13

私が使用する方法は、文字列スライスの方法です。比較的速くて簡単です。

まず、フロートを文字列に変換し、希望の長さを選択します。

float = str(float)[:5]

上記の1行では、値を文字列に変換し、文字列を最初の4桁または文字(両端を含む)のみに保持しました。

お役に立てば幸いです。


2
複数の質問に同じ回答を投稿しないでください。
保管庫2015

18
WOW ... tdh ...会計ソフトウェアは絶対に作成しないでください...数字が113.94になった場合はどうなりますか?これにより113.9が発生します... 0.04が失われます...また、これには5年以上前の回答があります...
Angry 84
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.