普通、decimal を使うときには、モジュールを import し、現在の 演算コンテキストを getcontext() で調べ、必要に応じて 精度や丸めを設定し、演算エラーのトラップを有効にします:
>>> from decimal import * >>> getcontext() Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[Overflow, InvalidOperation, DivisionByZero]) >>> getcontext().prec = 7 # 新たな精度を設定
Decimal のインスタンスは、整数、文字列またはタプルから生成 できます。Decimal を float から生成したければ、まず 文字列型に変換せねばなりません。そうすることで、変換方法の詳細を (representation error も含めて) 明示的に残せます。 Decimal は ``数値ではない (Not a Number)'' を表す NaN や正負の Infinity (無限大)、 -0 といった特殊な値も表現できます。
>>> Decimal(10) Decimal("10") >>> Decimal("3.14") Decimal("3.14") >>> Decimal((0, (3, 1, 4), -2)) Decimal("3.14") >>> Decimal(str(2.0 ** 0.5)) Decimal("1.41421356237") >>> Decimal("NaN") Decimal("NaN") >>> Decimal("-Infinity") Decimal("-Infinity")
新たな Decimal 型数値の有効桁数は入力した数の桁数だけで決まります。 演算コンテキストにおける精度や値丸めの設定が影響するのは算術操作の 中だけです。
>>> getcontext().prec = 6 >>> Decimal('3.0') Decimal("3.0") >>> Decimal('3.1415926535') Decimal("3.1415926535") >>> Decimal('3.1415926535') + Decimal('2.7182818285') Decimal("5.85987") >>> getcontext().rounding = ROUND_UP >>> Decimal('3.1415926535') + Decimal('2.7182818285') Decimal("5.85988")
Decimal 型数値はほとんどの場面で Python の他の機能とうまく やりとりできます。 Decimal 浮動小数点小劇場 (flying circus) を示しましょう:
>>> data = map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()) >>> max(data) Decimal("9.25") >>> min(data) Decimal("0.03") >>> sorted(data) [Decimal("0.03"), Decimal("1.00"), Decimal("1.34"), Decimal("1.87"), Decimal("2.35"), Decimal("3.45"), Decimal("9.25")] >>> sum(data) Decimal("19.29") >>> a,b,c = data[:3] >>> str(a) '1.34' >>> float(a) 1.3400000000000001 >>> round(a, 1) # round() は値をまず二進の浮動小数点数に変換します 1.3 >>> int(a) 1 >>> a * 5 Decimal("6.70") >>> a * b Decimal("2.5058") >>> c % a Decimal("0.77")
quantize() メソッドは位を固定して数値を丸めます。このメソッドは、 計算結果を固定の桁数で丸めることがよくある、通貨を扱うアプリケーションで 便利です:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN) Decimal("7.32") >>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP) Decimal("8")
前述のように、getcontext() 関数を使うと現在の演算コンテキスト にアクセスでき、設定を変更できます。ほとんどのアプリケーションはこの アプローチで十分です。
より高度な作業を行う場合、Context() コンストラクタを使って 別の演算コンテキストを作っておくと便利なことがあります。 別の演算コンテキストをアクティブにしたければ、setcontext() を使います。
Decimal モジュールでは、標準仕様に従って、すぐ利用できる 二つの標準コンテキスト、BasicContext および ExtendedContext を提供しています。後者はほとんどのトラップが 有効になっており、とりわけデバッグの際に便利です:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN) >>> setcontext(myothercontext) >>> Decimal(1) / Decimal(7) Decimal("0.142857142857142857142857142857142857142857142857142857142857") >>> ExtendedContext Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[]) >>> setcontext(ExtendedContext) >>> Decimal(1) / Decimal(7) Decimal("0.142857143") >>> Decimal(42) / Decimal(0) Decimal("Infinity") >>> setcontext(BasicContext) >>> Decimal(42) / Decimal(0) Traceback (most recent call last): File "<pyshell#143>", line 1, in -toplevel- Decimal(42) / Decimal(0) DivisionByZero: x / 0
演算コンテキストには、演算中に遭遇した例外的状況をモニタするための シグナルフラグがあります。フラグが一度セットされると、明示的に クリアするまで残り続けます。そのため、フラグのモニタを行いたいような 演算の前にはclear_flags() メソッドでフラグをクリアして おくのがベストです。
>>> setcontext(ExtendedContext) >>> getcontext().clear_flags() >>> Decimal(355) / Decimal(113) Decimal("3.14159292") >>> getcontext() Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[Inexact, Rounded], traps=[])
flags エントリから、Pi の有理数による近似値が丸められた (コンテキスト内で決められた精度を超えた桁数が捨てられた) ことと、 計算結果が厳密でない (無視された桁の値に非ゼロのものがあった) ことが わかります。
コンテキストの traps フィールドに入っている辞書を使うと、 個々のトラップをセットできます:
>>> Decimal(1) / Decimal(0) Decimal("Infinity") >>> getcontext().traps[DivisionByZero] = 1 >>> Decimal(1) / Decimal(0) Traceback (most recent call last): File "<pyshell#112>", line 1, in -toplevel- Decimal(1) / Decimal(0) DivisionByZero: x / 0
ほとんどのプログラムでは、開始時に一度だけ現在の演算コンテキストを 修正します。また、多くのアプリケーションでは、データから Decimal への変換はループ内で一度だけキャストして行います。コンテキストを設定し、 Decimal オブジェクトを生成できたら、ほとんどのプログラムは 他の Python 数値型と全く変わらないかのようにDecimal を操作できます。
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。