web-dev-qa-db-ja.com

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

a 13.95 に四捨五入したい。

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

round 関数は思ったようには動きません。

1355
kevin

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

浮動小数点では、丸められたバージョンは同じ番号です。コンピュータは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("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

通貨のように小数点以下2桁しかない場合は、2、3の選択肢があります。1)整数を使用し、ドルではなくセントで値を格納してから、100で割ってドルに変換します。 2)または decimal のような固定小数点数を使用します。

1368
Rex Logan

新しいフォーマット仕様があります、 文字列フォーマット仕様ミニ言語

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

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

上記は文字列を返すことに注意してください。フロートとして取得するには、単にfloat(...)でラップします。

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

float()でラップしても何も変わらない:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{0:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
493
Xolve

組み込みのround()はPython 2.7以降ではうまく動きます。

例:

>>> round(14.22222223, 2)
14.22

ドキュメンテーション をチェックしてください。

220
chribsen

最も簡単な方法はformat()関数を使うことだと私は思います。

例えば:

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

13.95

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

131
grant zukowski

ほとんどの数値は、floatで正確に表すことはできません。それがあなたの数式やアルゴリズムが必要とするものであるためにあなたが数を四捨五入したいなら、あなたは四捨五入を使いたいです。表示を一定の精度に制限したいだけの場合は、roundを使用せずに、単にその文字列としてフォーマットします。 (いくつかの代替丸め方法で表示したいが、トンがある場合は、2つの方法を組み合わせる必要があります。)

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

そして最後に、おそらく最も重要なことですが、もしあなたが exact /数学を望むのであれば、あなたはフロートを望んでいません。通常の例は、お金を扱い、「セント」を整数として格納することです。

89
Roger Pate

つかいます

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

の代わりに

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

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

78

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

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

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は preferred です。

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

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

参照:浮動小数点数を特定の精度に変換してから文字列にコピーする

51
A.J.

出力フォーマットは変更できます。

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
43
Greg Hewgill

TLDR;)

入出力の丸め問題は、Python 2.7.0によって最終的に解決されましたおよび3.1です。

正しく丸められた数は可逆的に前後に変換することができます。
str -> float() -> repr() -> float() ...またはDecimal -> float -> str -> Decimal
Decimal型は格納には不要です。

(もちろん、累積された最後のビットエラーを取り除くために丸められた数の加算または減算の結果を丸める必要があるかもしれません。明示的な10進数算術はまだ便利ですがstr()によるストリングへの変換極端な精度も極端な数の連続した算術演算も必要とされない場合、通常は十分に十分です。)

無限テスト

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+ :-)

ドキュメンテーション

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

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

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

関連する問題


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

38
hynekcer

Python 2.7では:

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

まだ誰も言及していないようなので、Python 3.6のf-string/template-stringフォーマットの例を挙げてみましょう。

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

これは、演算子を使って、親を必要としない、より長い例でもうまく動作します。

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

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

>>> 0.1
0.10000000000000001

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

>>> round(0.1, 1)
0.10000000000000001

問題は、“0.1”に格納されている2進浮動小数点値がすでに1/10への可能な限り最良の2進近似であったことです。

0.1は正確には1/10ではないので、0.1の10個の値を合計しても正確に1.0にならない可能性があります。

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

あなたの問題に対する一つの代替案と解決策は decimal モジュールを使うことです。

20
nosklo

Pythonでは小数点以下2桁まで値を丸めるために format 演算子を使用できます。

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

それはあなたがそれをするようにあなたが言ったことを正確にしていて、そして正しく働いています。 浮動小数点混乱についての詳細を読んでください そして代わりに decimal オブジェクトを試してください。

12
HUAGHAGUAH

@Mattが指摘したように、Python 3.6はf文字列を提供しますそしてそれらはネストされたパラメータを使うこともできます

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

これはresult: 2.35を表示します

11
toto_tico

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')
7
Siamand Maroufi
orig_float = 232569 / 16000.0

14.5355625

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

14.54

6
MikeL
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
weaming

1,2,3のように簡単です。

  1. 高速に丸められた10進数浮動小数点演算には decimal moduleを使用します。

    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))

OR

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. この回答を支持する:)

シモンズ:他人の批評:フォーマットは丸めていません。

3

このようなラムダ関数はどうでしょうか。

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

こうすればあなたはただできる:

arred(3.141591657,2)

そして得る

3.14
1

数値を決意に丸めるには、次の方法が最善の方法です。これは、任意の決議で有効です(小数点以下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
1
iblasi

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')
0
Jonathan L