13

python小数比較

>>> from decimal import Decimal
>>> Decimal('1.0') > 2.0
True

2.0 が正しく変換されることを期待していましたが、PEP 327を読んだ後、float を Decimal に暗黙的に変換しない何らかの理由があることを理解しましたが、この場合のように TypeError を発生させるべきではありません。

>>> Decimal('1.0') + 2.0
Traceback (most recent call last):
  File "<string>", line 1, in <string>
TypeError: unsupported operand type(s) for +: 'Decimal' and 'float'

他のすべての演算子もそうです / - % // など

だから私の質問は

  1. これは正しい行動ですか?(cmpで例外を発生させないでください)
  2. 独自のクラスを派生させ、基本的に Decimal(repr(float_value)) の float コンバーターを正しく使用する場合、注意事項はありますか? 私のユースケースには、価格の比較のみが含まれます

システムの詳細: Ubuntu 8.04.1 上の Python 2.5.2

4

3 に答える 3

26

Re 1、それは確かに私たちが設計した動作です-それが正しいか間違っているかはわかりません(それがあなたのユースケースをつまずかせたら申し訳ありませんが、私たちは一般的にしようとしていました!)。

具体的には、すべての Python オブジェクトが他のすべてのオブジェクトとの不等比較の対象となる可能性があるというケースが長い間ありました。実際には比較できない型のオブジェクトは、任意に比較されます (特定の実行で一貫して、必ずしも複数の実行にまたがる必要はありません)。主な使用例は、異種のリストをソートして、その中の要素をタイプ別にグループ化することでした。

複素数のみに例外が導入され、何にも匹敵しなくなりましたが、それはまだ何年も前のことであり、完全に優れたユーザーコードを壊すことについて時折無頓着でした. 最近では、メジャー リリース内での下位互換性についてはより厳密になっています (たとえば、2.*ラインに沿って、または 1 つに沿って個別に、 2 と 3 の間の3.*非互換性は許容されます。実際、それがシリーズを持つことの全体的なポイントであり、3.*過去の設計を修正できます)。互換性のない方法でも決定します)。

恣意的な比較は、価値がある以上に面倒であることが判明し、ユーザーを混乱させました。タイプによるグループ化は、たとえば;へのkey=lambda x: str(type(x))引数を使用して簡単に取得できるようになりました。sortしたがって、Python 3 では、オブジェクト自体が比較メソッドで明確に許可しない限り、異なるタイプのオブジェクト間の比較で例外が発生します。

>>> decimal.Decimal('2.0') > 1.2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: Decimal() > float()

言い換えれば、Python 3 では、これはあなたが思っているとおりに動作します。しかし、Python 2 ではそうではありません (そして、どの Python でも決してそうなることはありません2.*)。

Re 2 では問題ありませんが、gmpyを調べて、Farey 木を使用して double を無限精度の分数に変換する興味深い方法を探してください。扱っている価格がセント単位で正確な場合は、'%.2f' % xではなくrepr(x)!-)を使用してください。

Decimal のサブクラスではなく、次のようなファクトリ関数を使用します。

def to_decimal(float_price):
    return decimal.Decimal('%.2f' % float_price)

一度生成されると、結果の Decimal は完全に普通のものになるからです。

于 2009-06-30T06:26:26.187 に答える
3

大なり比較は、デフォルトですべてのオブジェクトに対して機能するため、機能します。

>>> 'abc' > 123
True

Decimal仕様に正しく準拠しているという理由だけで正しいです。仕様が正しいアプローチであったかどうかは、別の問題です。:)

フロートを扱うときの通常の警告のみを簡単に要約すると、次のとおりです。負のゼロ、+/- 無限大、NaN などのエッジ ケースに注意し、(次のポイントに関連して) 等しいかどうかをテストしないでください。少し不正確。

>>> print (1.1 + 2.2 == 3.3)
False
于 2009-06-30T06:25:40.460 に答える
1

それが「正しい」かどうかは意見の問題ですが、自動変換がない理由は PEP に存在し、それが下された決定でした。基本的に、float と decimal の間で常に正確に変換できるとは限らないことに注意してください。したがって、変換は暗黙的であってはなりません。アプリケーションで、これが影響を与えるのに十分な有効数がないことがわかっている場合は、この暗黙的な動作を許可するクラスを作成しても問題ありません。

また、主な議論の 1 つは、実際の使用例は存在しないということです。どこでも Decimal を使用するだけで、より簡単になる可能性があります。

于 2009-06-30T06:24:55.097 に答える