-2

次のコードを使用して、Pythonの数値を小数点以下2桁に丸めたい:

a = 3260
b = 0.000075
c =  a * b # // (0.24449999999999997)
result = round(a * b, 2)

しかし、私が得る結果は次のとおりです。0.23999999999999999

これを Excel VBA と比較していresultます。0.24

(a) 数値が切り捨てられない理由と、(b) 同等の VBA と異なる理由がわかりません。

WorksheetFunction.MRound(c, 0.01)

どんなヒントでも大歓迎です!

編集: VS2010 および python 2.6 用の python ツールを使用しています。

4

1 に答える 1

2

値 0.24 は、IEEE 2 進浮動小数点数として正確に表すことはできません。そのため、 0.23999999999999999 が得られます。VBA が同じ形式を使用しているかどうかは 100% わかりません。もしそうなら、それは 0.23999999999999999 が 0.24 に近すぎることに「気づき」、後者を表示している可能性があります。ただし表示時のみ。この IEEE 形式には正確な値 0.24が存在しないため、内部的には不正確な数値が保存されます。

結果を小数点以下 2 桁で表示することにより、VBA と同様の動作を強制することができます。書式設定ルーチンは、文字列表現に丸められるため、この意味でより良い仕事をします。これは、"2.40" (数値ではなく文字列として) を確実にサポートします。

print( "%.2f" % 0.23999999999999999 )

もう 1 つの解決策は、10 進数を完全な精度 (2 進数ではなく) で表すことができる 10 進浮動小数点または固定小数点演算パッケージを使用することです。Python の標準パッケージdecimalは非常にうまく機能し、両方をサポートしています。

3 番目の解決策は、特定の方法で、そのようなパッケージを単純で個人的な方法で実装することですが、非常に労力のかかる方法です。すべての数値を小数点以下 2 桁で格納する必要があると仮定すると、数値を 100 倍にして整数として格納できます。例:

a =  1326048  # /100=  13260.48 ; s=2
b =   234493  # /100=   2344.93 ; s=2
c = 34756334  # /100= 347563.34 ; s=2
# All three numbers are in the same scale, so they can be added directly.  Scale of the result is the same as the numbers (s=2)
d = a + b + c  # /100; s=2
# In multiplication, scale of the result is the sum of the scale of the factors. 
# This has the advantage that the scale of operands can be different.
e = a * b  # /10000; s=4
# But we want to go back to 2 decimals quickly.  So, round to 2 decimals.  And yes, division subtracts scales.
e = ( e + 50 ) // 100  # /100 s=2

これ(または次の「解決策」)はまったくお勧めしません。この種のパッケージがどのように機能するかを最小限に説明するためだけにここにいます。

別の変数でスケールを追跡し、実行時に必要なスケール調整を計算することもできますが、これは前述のパッケージの 1 つを自分でビルドすることと完全に同等です。あなたの特定のケースでは、

a_m= 326
a_s= -1   # a= a_m / 10**a_s = 326 / 10**-1 = 3260
b_m= 75
b_s= 6    # b= b_m / 10**b_s = 75 / 10**6 = 0.000075
c_m= a_m * b_m  # =24450
c_s= a_s + b_s  # = -1 + 6 = 5  ;  c= c_m / 10**c_s = 24450 / 10**5 = 0.24450
# Round to 2 decimals
r= 2
d_m= ( c_m + 10**(c_s-r)//2 ) // 10**(c_s-r)
# d_m = ( 24450 + 10**(5-2)//2 ) // 10**(5-2) = ( 24450 + 500 ) // 1000 = 24
d_s= r  # = 2  ;  d= dm / 10**ds = 24 / 10**2 24 / 100 = 0.24

この時点で、「スケーリングされていない」バージョンの を出力したいと考えていますc。2 つの選択肢は次のとおりです。

print( ("%d.%0"+str(c_s)+"d") % ( c // 100 , c % 100 ) )  # Which is the same as...
print( ("%d.%02d") % ( c // 100 , c % 100 ) )  # The case c_s < 0 requires a different expression

または浮動小数点の方法に行く

print( "%.2f" % c / 100 )
于 2013-08-15T06:07:12.787 に答える