13.95a
に四捨五入したい。
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
round
機能は、私が期待されるように動作しません。
13.95a
に四捨五入したい。
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
round
機能は、私が期待されるように動作しません。
回答:
あなたはに実行されている古い問題ではない、すべての数字が正確に表現することができます浮動小数点数を持ちます。コマンドラインは、メモリから完全な浮動小数点形式を表示しているだけです。
浮動小数点表現では、丸められたバージョンは同じ数です。コンピュータはバイナリなので、浮動小数点数を整数として格納し、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桁のみの場合(たとえば、通貨の値を表示する場合)は、より適切な選択肢がいくつかあります。
"%.2f" % round(a,2)
printfだけでなく、str()
float
)バイナリ値は、10進数の最も近い利用可能な近似値(人間としてよく知られている)であることを理解する必要があります。0.245のような(有限に表現可能な)バイナリ値はありません。それは単に存在せず、数学的には存在できません。0.245に最も近いバイナリ値は0.245 よりわずかに小さいため、自然に切り捨てられます。同様に、バイナリには0.225のようなものはありませんが、0.225に最も近いバイナリ値は0.225 よりわずかに大きいため、当然切り上げられます。
Decimal
であり、これはこの回答で提示された解決策の1つでした。もう1つは、数量を整数に変換し、整数演算を使用することでした。これらのアプローチはどちらも、他の回答やコメントにも記載されています。
新しいフォーマット仕様、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
'{0:,.2f}'.format(1333.949999999)
た印刷物'1,333.95'
。
float()
ます。float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
round(2.16, 1)
、2.2
なぜPython がtruncate
funcを提供するのかを説明します
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
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.
使用する
print"{:.2f}".format(a)
の代わりに
print"{0:.2f}".format(a)
後者の場合、複数の変数を出力しようとすると、出力エラーが発生する可能性があるためです(コメントを参照)。
ほとんどの数値は、浮動小数点数で正確に表すことができません。それがあなたの数式またはアルゴリズムが必要とするものであるので、あなたが数を丸めたいならば、あなたは丸めを使いたいでしょう。表示を特定の精度に制限したいだけの場合は、丸めを使用せず、その文字列としてフォーマットするだけです。(別の丸め方法で表示したい場合で、トン数がある場合は、2つの方法を組み合わせる必要があります。)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
そして最後に、おそらく最も重要なことですが、正確な数学が必要な場合は、浮動小数点数はまったく必要ありません。通常の例では、お金を扱い、「セント」を整数として格納します。
以下のコードを試してください:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
round
ますが、そもそも関数を使用するだけでは、これを行うメリットはありません。さらに、このソリューションは依然として浮動小数点を使用しているため、この「ソリューション」の「修正」バージョンでも、OPの元の問題が残っています。
round
(質問で使用された)関数の不必要な再実装です。
round()
、OPが言及したとおりに機能しない場合に必要です。
入力/出力の丸め問題は、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コンストラクタ。数値フォーマット;
marshal
、pickle
および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以降では何も必要ありません。
float
(倍精度)とnormal round
に関するものでした。プレーンなPythonの丸めは、Python 2.7よりも優れた方法で行うことはできません。回答のほとんどは2.7より前に書かれたものですが、もともと非常に優れていたものの、時代遅れになっています。これが私の答えの理由です。
1
「段階的アンダーフロー」時を除いて、暗黙的に「隠しビット」を含めると53ビット。
a*b
vs b*a
でした。リンクをありがとう-ノスタルジア。
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の詳細については、このリンクで十分であり、さまざまなフラグに関する情報があります。
リファレンス:浮動小数点数を特定の精度に変換してから文字列にコピーする
numvar=12.456
、結果は"{:.2f}".format(numvar)
得られます12.46
が"{:2i}".format(numvar)
、エラーが発生し、期待してい12
ます。
出力形式を変更できます。
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
ここではまだ誰も言及していないようですので、Python 3.6のf-string / template-string形式の例を挙げましょう。
>>> f'{a:.2f}'
演算子を使用し、括弧を必要としない、より長い例でもうまく機能します。
>>> print(f'Completed in {time.time() - start:.2f}s')
pythonでは、フォーマット演算子を使用して、小数点以下2桁まで値を丸めることができます。
print(format(14.4499923, '.2f')) // output is 14.45
Python 2.7の場合:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
とまったく同じ値を持っているa
ので、最後の行のprint a
代わりに書き込んだ方がよいかもしれませんprint output
。
13.95
ます。しかしprint a
、この特定の値のa
場合、Python 2.7でも同様です。そのため、フォーマット手順のポイントが何であったかは明確ではありません。
a == output
表示したコードを試しましたか?それはTrue
私に与えてくれますし、あなたにもそうだと思います。
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
モジュールを使用することです。
@Mattが指摘したように、Python 3.6はf-stringsを提供し、ネストされたパラメーターを使用することもできます。
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
表示されます result: 2.35
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')
getcontext().prec = 6
関数のスコープだけで機能するのか、それともすべての場所で機能するのか?
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'
これは、1,2,3のように単純です。
10進モジュールを使用して、正しく丸められた10進浮動小数点演算を高速化します。
d = 10進数(10000000.0000009)
丸めを達成するには:
d.quantize(Decimal('0.01'))
結果は Decimal('10000000.00')
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)
PS:他の人の批評:フォーマットは丸めではありません。
数値を分解能に丸めるには、次の方法が最適です。これは、任意の分解能で機能します(小数点以下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
numpy.round
正確さ/正確さに起因していることがわかります。したがって、解像度と乗算する前に、それをintとして定義する必要があります。コードを更新しました。有難うございます!
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に関する詳細情報も私の回答に追加されました。もともとは派手なものではありませんでした。
int
あなたの代わりにfloat
@szeitlinの例にも使用できることを確認しました。追加のコメントありがとうございます。(申し訳ありませんが、私はあなたに反対票を投じませんでした)
私が使用する方法は、文字列スライスの方法です。比較的速くて簡単です。
まず、フロートを文字列に変換し、希望の長さを選択します。
float = str(float)[:5]
上記の1行では、値を文字列に変換し、文字列を最初の4桁または文字(両端を含む)のみに保持しました。
お役に立てば幸いです。