これは古典的な浮動小数点精度の問題だと思いますが1//0.01、Python 3.7.5 で実行すると、この結果に頭を悩ませようとしています99。
期待どおりの結果だと思いますが、使用int(1/f)する方が安全1//fかどうかを判断する方法はありますか?
round()、使用しない//か、または使用することにより、99.99%の期待どおりに機能しint()ます。リンクされた質問は、浮動小数点数の比較については切り捨てとは関係がなく、そのような簡単な修正はありません。
これは古典的な浮動小数点精度の問題だと思いますが1//0.01、Python 3.7.5 で実行すると、この結果に頭を悩ませようとしています99。
期待どおりの結果だと思いますが、使用int(1/f)する方が安全1//fかどうかを判断する方法はありますか?
round()、使用しない//か、または使用することにより、99.99%の期待どおりに機能しint()ます。リンクされた質問は、浮動小数点数の比較については切り捨てとは関係がなく、そのような簡単な修正はありません。
回答:
この結果の理由は、あなたが述べているようなものであり、浮動小数点演算は壊れていますか?および他の多くの同様のQ&A。
分子と分母の小数の数がわかっている場合、より信頼性の高い方法は、最初にこれらの数値を乗算して整数として処理できるようにし、次に整数除算を実行することです。
したがって、あなたのケースで1//0.01は最初に1*100//(0.01*100)100に変換する必要があります。
さらに極端な場合でも、「予期しない」結果が得られる可能性があります。round整数除算を実行する前に、分子と分母の呼び出しを追加する必要がある場合があります。
1 * 100000000000 // round(0.00000000001 * 100000000000)
ただし、これが固定小数点(金額、セント)の処理に関するものである場合は、セントをunitとして処理することを検討してください。これにより、すべての演算を整数演算として実行できます。時にメインの通貨単位(ドル)のみ変換 I / O。
あるいは、decimalのような10進数用のライブラリを使用します。
...正しく丸められた高速の10進浮動小数点演算をサポートします。
from decimal import Decimal
cent = Decimal(1) / Decimal(100) # Contrary to floating point, this is exactly 0.01
print (Decimal(1) // cent) # 100
あなたが考慮しなければならないの//は、それがfloor演算子であるため、最初に100に落ちる確率が99と同じであるかのように考える必要があります(*)(操作は正確に100.00を得る可能性がある場合100 ± epsilonにepsilon>0行われるため)..0は非常に低いです。)
同じことがマイナス記号で確認できます
>>> 1//.01
99.0
>>> -1//.01
-100.0
そして、あなたは(驚かないように)驚かれるはずです。
一方、 int(-1/.01)最初に除算を実行してから、int()inを適用します。これは、床ではなく0への切り捨てです!つまり、その場合、
>>> 1/.01
100.0
>>> -1/.01
-100.0
したがって、
>>> int(1/.01)
100
>>> int(-1/.01)
-100
ただし、四捨五入すると、この演算子の期待どおりの結果が得られます。これも、これらの数値では誤差が小さいためです。
(*)確率が同じであると言っているのではなく、浮動小数点演算を使用してそのような計算を実行するとき、得られているものの推定値であるということを単にアプリオリと言っているだけです。
浮動小数点数はほとんどの10進数を正確に表すことができないため、浮動小数点リテラルを入力すると、実際にはそのリテラルの概算が得られます。入力した数値よりも近似値が大きくなる場合と小さくなる場合があります。
浮動小数点数の正確な値は、それをDecimalまたはFractionにキャストすることで確認できます。
>>> from decimal import Decimal
>>> Decimal(0.01)
Decimal('0.01000000000000000020816681711721685132943093776702880859375')
>>> from fractions import Fractio
>>> Fraction(0.01)
Fraction(5764607523034235, 576460752303423488)
Fraction型を使用して、不正確なリテラルによって引き起こされたエラーを見つけることができます。
>>> float((Fraction(1)/Fraction(0.01)) - 100)
-2.0816681711721685e-15
また、numpyからnextafterを使用することにより、100前後の粒度の倍精度浮動小数点数がどの程度かを確認することもできます。
>>> from numpy import nextafter
>>> nextafter(100,0)-100
-1.4210854715202004e-14
これから、に最も近い浮動小数点数1/0.01000000000000000020816681711721685132943093776702880859375は実際には100であると推測できます。
違い1//0.01とはint(1/0.01)丸めです。1 // 0.01は、正確な結果を1つのステップで次の整数に切り捨てます。したがって、結果は99になります。
一方、int(1 / 0.01)は2段階で丸めます。最初に結果を最も近い倍精度浮動小数点数(正確には100)に丸め、次にその浮動小数点数を次の整数(これは再び正確に100)。
int(0.9) == 0およびint(-0.9) == 0
以下を実行すると
from decimal import *
num = Decimal(1) / Decimal(0.01)
print(num)
出力は次のようになります。
99.99999999999999791833182883
これを切り捨てて、それが内部的に表されます方法ですが//得られます99
Decimal(0.01)あなたは手遅れです、エラーはすでにあなたが呼び出す前にこっそりDecimal。これが質問への答えであるかどうかはわかりません... Decimal(1) / Decimal(100)私が私の答えで示したように、最初にで正確な0.01を計算する必要があります。