2017-09-06 12 views
-1

を与える:代わりに1.0を返すのPythonの小数は、私は次の計算に問題があるんだ、誤った結果に

Decimal(3)*(Decimal(1)/Decimal(3)) 

を、それが0.999を返す...

これは、いくら私の場合残っていませんDecimalモジュールの精度を上げてください。ここで

は完全なコードです:皮肉なこと

from decimal import Decimal 
from decimal import getcontext 
getcontext().prec = 800 
print Decimal(3)*(Decimal(1)/Decimal(3)) 

、 "ネイティブ" floatは、問題を解決使用して:回答

print float(3)*(float(1)/float(3)) 

言うまでもないが、私はより複雑なため、ここでDecimalを使用しています大きい数のべき乗を含む計算。この問題にぶつかった後、私は上記の例にそれを最小限に抑えることができました。

ありがとうございます。

+4

10進数は、分母が3の分数を単純に表すことはできません。有理数についての正確な計算のために、 'fractions'モジュールを見てください。 –

+0

10進数とコンピュータの素晴らしい世界へようこそ。コンピュータで小数を使って複数の計算を行うときの精度の損失を最小限に抑える方法を示すために教えられた数値メソッドのコースがあります。 – LhasaDad

+0

@LhasaDad:私が言ったように、私はずっと複雑な計算をしています。私の質問の例は問題の最小化に過ぎません。実際の計算は 'Decimal(x)*((1 + Decimal(y)/ Decimal(z))**(Decimal(w)/ 1000000) - 1)'であり、目的は実装された式をエミュレートすることです別の(非pythonic)プラットフォーム上で。この目的のために、私はこの計算を精度のために最適化することは許されていません(あるいは、他の方法でそれを変更することはできません)。 – goodvibration

答えて

0

私はparanthesisを変更すると思う:

from decimal import Decimal 
from decimal import getcontext 
getcontext().prec = 800 
print (Decimal(3)*Decimal(1))/Decimal(3) 

出力は、私のコメントに少し拡大1

4

上記のために私のために、1:

のPythonの10進数は、文字通り一種でありますあなたが手で書き留めるかもしれない数の重要なのは、再帰の概念を理解していないため、1/3のような無限に繰り返される部分は、正確さの点までは0.333333333333..と表されます。これに3を乗算すると、0.99999..が得られます。これは実際には0.33333333..が切り捨てられた後に1/3だったことを実際に知ることができないため、分かりやすい動作です。 Decimalは、分割するときの丸めによって精度が低下することがよくあります(実際には、2または5以外の因子で割ります)。分割を行うことができることが重要である場合、分子と分母によって、任意の精度の損失なしに、任意の有理数を表すFractionを使用:

In [1]: from fractions import Fraction 

In [2]: Fraction(3) * Fraction(1, 3) 
Out[2]: Fraction(1, 1) 

In [3]: print(_) 
1 

画分が自動的に単純化するであろう。

あなたの浮動小数点数では、丸め誤差がキャンセルされたのはちょうど運が良かったと思います。 floatまたはDecimalは、の絶対値がの精度が必要な場合を除き、おそらく十分です(この場合、Fractionなどが推奨されます)。あなたが頻繁になりません実際にはたいした、0.99999991の違いをシミュレーションのようなものをやっている場合は

In [4]: "{:.2f}".format(Decimal(3) * (Decimal(1)/Decimal(3))) 
Out[4]: '1.00' 

:あなたは常にそれが少なくとも少しきれいに見えるようにする醜い数締めくくることができます。

もう1つの方法は、分子が分母で割り切れることが保証されるように操作の順序を入れ替えることです。これは Anilkumarの答えです。可能であれば、これは良い解決策ですが、これを行うことができない機会があるかもしれません。例えば、結果が小数であることを期待している場合や、ある種のブラックボックスから分数被乗数を得る場合などです。この時点で、Decimal分子と分母の両方を追跡することが可能になります。そして、あなたはそれがFractionのクラスであることを認識しますが、手間は少なくなります。

Fractionは、Decimalで実行できるものはすべて重要ですが、より重要なことに使用できます。表現可能な10進数も小数です(10の累乗を超える仮数)。例えば:

In [2]: Fraction("3.141") 
Out[2]: Fraction(3141, 1000) 

当然のことながら、これはいくつかの失われたパフォーマンスにつながる - 画分は、より多くのデータを追跡する必要があり、より多くの計算を行うと、おそらくやや抽象的です。

有理数を非整数の累乗にすると、結果は合理的でない可能性があるので、途中で分数を失う可能性があることに注意してください。例:

>>> Fraction(1, 2) ** 4 
Fraction(1, 16) 
>>> Fraction(1, 2) ** 0.5 
0.7071067811865476 

式を評価する文脈の中では、すべてを記号的に試して保存することはあまり意味がありません。これは、しばしば十分に良いと思われるfloatという考えに戻ってきます。あなたが本当にsurd出力形式のいくつかの種類を望んでいた場合、あなたはsympyに打撃を与えることができる:

In [1]: from sympy import * 

In [2]: sqrt(Integer(1)/Integer(2)) 
Out[2]: sqrt(2)/2 

をこれはもちろん、さらにあなたを遅くします。

+0

ありがとうございます、私は今あなたの提案をチェックしています。完了したら更新されます。 – goodvibration

+1

私が言ったように、私ははるかに複雑な計算をしています、私の質問の例は問題の最小化に過ぎません。実際の計算は 'Decimal(x)*((1 + Decimal(y)/ Decimal(z))**(Decimal(w)/ 1000000)-1)'です。別の(非pythonic)プラットフォーム。この目的を考えれば、式の順序を変更することはできないので、並べ替えの提案は私の問題ではありません。 – goodvibration

+0

ありがとうございます。この 'Fraction'モジュールには、ある種の不正確さがあるようです。たとえば、 'Fraction(9999999999999999999999999999999223)*(1)**(Fraction(10)/ Fraction(9))'は、 '9999999999999999455752309870428160'を返します。ここで指数が1であることを認識すれば、この特定のシナリオを簡単に回避できます。しかし、私はこの例のような特殊なケースを調べ始めることはできません。どのようにこれを解決するためのアイデア? – goodvibration

関連する問題