decimal --- 十進固定及び浮動小数点数の算術演算

ソースコード: Lib/decimal.py


decimal モジュールは正確に丸められた十進浮動小数点算術をサポートします。 decimal には、 float データ型に比べて、以下のような利点があります:

  • 「(Decimal は) 人々を念頭にデザインされた浮動小数点モデルを元にしており、必然的に最も重要な指針があります -- コンピュータは人々が学校で習った算術と同じように動作する算術を提供しなければならない」 -- 十進数演算仕様より。

  • Decimal numbers can be represented exactly. In contrast, numbers like 1.1 and 2.2 do not have exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.

  • The exactness carries over into arithmetic. In decimal floating point, 0.1 + 0.1 + 0.1 - 0.3 is exactly equal to zero. In binary floating point, the result is 5.5511151231257827e-017. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.

  • The decimal module incorporates a notion of significant places so that 1.30 + 1.20 is 2.50. The trailing zero is kept to indicate significance. This is the customary presentation for monetary applications. For multiplication, the "schoolbook" approach uses all the figures in the multiplicands. For instance, 1.3 * 1.2 gives 1.56 while 1.30 * 1.20 gives 1.5600.

  • ハードウェアによる 2 進浮動小数点表現と違い、decimal モジュールでは計算精度をユーザが変更できます(デフォルトでは 28 桁です)。この桁数はほとんどの問題解決に十分な大きさです:

    >>> from decimal import *
    >>> getcontext().prec = 6
    >>> Decimal(1) / Decimal(7)
    Decimal('0.142857')
    >>> getcontext().prec = 28
    >>> Decimal(1) / Decimal(7)
    Decimal('0.1428571428571428571428571429')
    
  • 二進と十進の浮動小数点は、いずれも広く公開されている標準仕様のもとに実装されています。組み込みの浮動小数点型では、標準仕様で提唱されている機能のほんのささやかな部分を利用できるにすぎませんが、decimal では標準仕様が要求している全ての機能を利用できます。必要に応じて、プログラマは値の丸めやシグナル処理を完全に制御できます。この中には全ての不正確な操作を例外でブロックして正確な算術を遵守させるオプションもあります。

  • decimal モジュールは「偏見なく、正確な丸めなしの十進算術(固定小数点算術と呼ばれることもある)と丸めありの浮動小数点数算術」(十進数演算仕様より引用)をサポートするようにデザインされました。

このモジュールは、十進数型、算術コンテキスト (context for arithmetic)、そしてシグナル (signal) という三つの概念を中心に設計されています。

A decimal number is immutable. It has a sign, coefficient digits, and an exponent. To preserve significance, the coefficient digits do not truncate trailing zeros. Decimals also include special values such as Infinity, -Infinity, and NaN. The standard also differentiates -0 from +0.

算術コンテキストとは、精度や値丸めの規則、指数部の制限を決めている環境です。この環境では、演算結果を表すためのフラグや、演算上発生した特定のシグナルを例外として扱うかどうかを決めるトラップイネーブラも定義しています。丸め規則には ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, および ROUND_05UP があります。

シグナルとは、演算の過程で生じる例外的条件です。個々のシグナルは、アプリケーションそれぞれの要求に従って、無視されたり、単なる情報とみなされたり、例外として扱われたりします。 decimal モジュールには、 Clamped, InvalidOperation, DivisionByZero, Inexact, Rounded, Subnormal, Overflow, Underflow, および FloatOperation といったシグナルがあります。

各シグナルには、フラグとトラップイネーブラがあります。演算上何らかのシグナルに遭遇すると、フラグは 1 にセットされます。このとき、もしトラップイネーブラが 1 にセットされていれば、例外を送出します。フラグの値は膠着型 (sticky) なので、演算によるフラグの変化をモニタしたければ、予めフラグをリセットしておかなければなりません。

参考

クイックスタートチュートリアル

普通、 decimal を使うときには、モジュールをインポートし、現在の演算コンテキストを getcontext() で調べ、必要なら、精度、丸め、有効なトラップを設定します:

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
        InvalidOperation])

>>> getcontext().prec = 7       # Set a new precision

Decimal instances can be constructed from integers, strings, floats, or tuples. Construction from an integer or a float performs an exact conversion of the value of that integer or float. Decimal numbers include special values such as NaN which stands for "Not a number", positive and negative Infinity, and -0:

>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')

FloatOperation シグナルがトラップされる場合、コンストラクタや順序比較において誤って decimal と float が混ざると、例外が送出されます:

>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True

バージョン 3.3 で追加.

新たな 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')

C バージョンの内部制限を超えた場合、decimal の構成は InvalidOperation を送出します:

>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

バージョン 3.3 で変更.

decimal はほとんどの場面で Python の他の機能とうまくやりとりできます。decimal 浮動小数点の空飛ぶサーカス (flying circus) をお見せしましょう:

>>> data = list(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.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')

いくつかの数学的関数も Decimal には用意されています:

>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')

The quantize() method rounds a number to a fixed exponent. This method is useful for monetary applications that often round results to a fixed number of places:

>>> 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=-999999, Emax=999999,
        capitals=1, clamp=0, 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

Contexts also have signal flags for monitoring exceptional conditions encountered during computations. The flags remain set until explicitly cleared, so it is best to clear the flags before each set of monitored computations by using the clear_flags() method.

>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])

The flags entry shows that the rational approximation to pi was rounded (digits beyond the context precision were thrown away) and that the result is inexact (some of the discarded digits were non-zero).

Individual traps are set using the dictionary in the traps attribute of a context:

>>> setcontext(ExtendedContext)
>>> 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 を操作できます。

Decimal オブジェクト

class decimal.Decimal(value='0', context=None)

value に基づいて新たな Decimal オブジェクトを構築します。

value は整数、文字列、タプル、 float および他の Decimal オブジェクトにできます。 value を指定しない場合、 Decimal('0') を返します。 value が文字列の場合、先頭と末尾の空白および全てのアンダースコアを取り除いた後には以下の 10進数文字列の文法に従わなければなりません:

sign           ::=  '+' | '-'
digit          ::=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator      ::=  'e' | 'E'
digits         ::=  digit [digit]...
decimal-part   ::=  digits '.' [digits] | ['.'] digits
exponent-part  ::=  indicator [sign] digits
infinity       ::=  'Infinity' | 'Inf'
nan            ::=  'NaN' [digits] | 'sNaN' [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

他の Unicode 数字も上の digit の場所に使うことができます。つまり各書記体系における(アラビア-インド系やデーヴァナーガリーなど)の数字や、全角数字0('\uff10')から9('\uff19')までなどです。

If value is a tuple, it should have three components, a sign (0 for positive or 1 for negative), a tuple of digits, and an integer exponent. For example, Decimal((0, (1, 4, 1, 4), -3)) returns Decimal('1.414').

valuefloat にする場合、二進浮動小数点数値が損失なく正確に等価な Decimal に変換されます。この変換はしばしば 53 桁以上の精度を要求します。例えば、 Decimal(float('1.1'))Decimal('1.100000000000000088817841970012523233890533447265625') に変換されます。

context の精度 (precision) は、記憶される桁数には影響しません。桁数は value に指定した桁数だけから決定されます。例えば、演算コンテキストに指定された精度が 3 桁しかなくても、Decimal('3.00000') は 5 つのゼロを全て記憶します。

The purpose of the context argument is determining what to do if value is a malformed string. If the context traps InvalidOperation, an exception is raised; otherwise, the constructor returns a new Decimal with the value of NaN.

一度生成すると、 Decimal オブジェクトは変更不能 (immutable) になります。

バージョン 3.2 で変更: コンストラクタに対する引数に float インスタンスも許されるようになりました。

バージョン 3.3 で変更: FloatOperation トラップがセットされていた場合 float 引数は例外を送出します。デフォルトでトラップはオフです。

バージョン 3.6 で変更: コード中の整数リテラルや浮動小数点リテラルと同様に、アンダースコアを用いて桁をグルーピングできます。

十進浮動小数点オブジェクトは、 floatint のような他の組み込み型と多くの点で似ています。通常の数学演算や特殊メソッドを適用できます。また、 Decimal オブジェクトはコピーでき、pickle 化でき、print で出力でき、辞書のキーにでき、集合の要素にでき、比較、保存、他の型 (floatint) への型強制を行えます。

十進オブジェクトの算術演算と整数や浮動小数点数の算術演算には少々違いがあります。十進オブジェクトに対して剰余演算を適用すると、計算結果の符号は除数の符号ではなく 被除数 の符号と一致します:

>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')

整数除算演算子 // も同様に、実際の商の切り捨てではなく (0に近付くように丸めた) 整数部分を返します。そのため通常の恒等式 x == (x // y) * y + x % y が維持されます:

>>> -7 // 4
-2
>>> Decimal(-7) // Decimal(4)
Decimal('-1')

演算子 % と演算子 // は (それぞれ) 仕様にあるような 剰余 操作と 整数除算 操作を実装しています。

Decimal オブジェクトは一般に、算術演算で浮動小数点数や fractions.Fraction オブジェクトと組み合わせることができません。例えば、 Decimalfloat を足そうとすると、 TypeError が送出されます。ただし、Python の比較演算子を使って Decimal インスタンス x と別の数 y を比較することができます。これにより、異なる型の数間の等価比較の際に、紛らわしい結果を避けます。

バージョン 3.2 で変更: Decimal インスタンスと他の数値型が混在する比較が完全にサポートされるようになりました。

こうした標準的な数値型の特性の他に、十進浮動小数点オブジェクトには様々な特殊メソッドがあります:

adjusted()

仮数の先頭の一桁だけが残るように右側の数字を追い出す桁シフトを行い、その結果の指数部を返します: Decimal('321e+5').adjusted() は 7 を返します。最上桁の小数点からの相対位置を調べる際に使います。

as_integer_ratio()

与えられた Decimal インスタンスを、既約分数で分母が正数の分数として表現した整数のペア (n, d) を返します。

>>> Decimal('-3.14').as_integer_ratio()
(-157, 50)

変換は正確に行われます。無限大に対してはOverflowErrorを、NaNに対してはValueError を送出します。

バージョン 3.6 で追加.

as_tuple()

数値を表現するための 名前付きタプル: DecimalTuple(sign, digittuple, exponent) を返します。

canonical()

引数の標準的(canonical)エンコーディングを返します。現在のところ、 Decimal インスタンスのエンコーディングは常に標準的なので、この操作は引数に手を加えずに返します。

compare(other, context=None)

二つの Decimal インスタンスの値を比較します。 compare() は Decimal インスタンスを返し、被演算子のどちらかが NaN ならば結果は NaN です:

a or b is a NaN  ==> Decimal('NaN')
a < b            ==> Decimal('-1')
a == b           ==> Decimal('0')
a > b            ==> Decimal('1')
compare_signal(other, context=None)

この演算は compare() とほとんど同じですが、全ての NaN がシグナルを送るところが異なります。すなわち、どちらの比較対象も発信 (signaling) NaN でないならば無言 (quiet) NaN である比較対象があたかも発信 NaN であるかのように扱われます。

compare_total(other, context=None)

二つの対象を数値によらず抽象表現によって比較します。 compare() に似ていますが、結果は Decimal に全順序を与えます。この順序づけによると、数値的に等しくても異なった表現を持つ二つの Decimal インスタンスの比較は等しくなりません:

>>> Decimal('12.0').compare_total(Decimal('12'))
Decimal('-1')

無言 NaN と発信 NaN もこの全順序に位置付けられます。この関数の結果は、もし比較対象が同じ表現を持つならば Decimal('0') であり、一つめの比較対象が二つめより下位にあれば Decimal('-1')、上位にあれば Decimal('1') です。全順序の詳細については仕様を参照してください。

この演算はコンテキストに影響されず、静かです。すなわち、フラグは変更されず、丸めは行われません。例外として、2番目の比較対象の厳密な変換ができない場合、C バージョンのライブラリでは InvalidOperation 例外を送出するかもしれません。

compare_total_mag(other, context=None)

二つの対象を compare_total() のように数値によらず抽象表現によって比較しますが、両者の符号を無視します。 x.compare_total_mag(y)x.copy_abs().compare_total(y.copy_abs()) と等価です。

この演算はコンテキストに影響されず、静かです。すなわち、フラグは変更されず、丸めは行われません。例外として、2番目の比較対象の厳密な変換ができない場合、C バージョンのライブラリでは InvalidOperation 例外を送出するかもしれません。

conjugate()

self を返すだけです。このメソッドは十進演算仕様に適合するためだけのものです。

copy_abs()

引数の絶対値を返します。この演算はコンテキストに影響されず、静かです。すなわち、フラグは変更されず、丸めは行われません。

copy_negate()

引数の符号を変えて返します。この演算はコンテキストに影響されず、静かです。すなわち、フラグは変更されず、丸めは行われません。

copy_sign(other, context=None)

最初の演算対象のコピーに二つめと同じ符号を付けて返します。たとえば:

>>> Decimal('2.3').copy_sign(Decimal('-1.5'))
Decimal('-2.3')

この演算はコンテキストに影響されず、静かです。すなわち、フラグは変更されず、丸めは行われません。例外として、2番目の比較対象の厳密な変換ができない場合、C バージョンのライブラリでは InvalidOperation 例外を送出するかもしれません。

exp(context=None)

与えられた数での(自然)指数関数 e**x の値を返します。結果は ROUND_HALF_EVEN 丸めモードで正しく丸められます。

>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal(321).exp()
Decimal('2.561702493119680037517373933E+139')
classmethod from_float(f)

Alternative constructor that only accepts instances of float or int.

なお、Decimal.from_float(0.1)Decimal('0.1') と同じではありません。0.1 は二進浮動小数点数で正確に表せないので、その値は表現できる最も近い値、0x1.999999999999ap-4 として記憶されます。浮動小数点数での等価な値は 0.1000000000000000055511151231257827021181583404541015625 です。

注釈

Python 3.2 以降では、 Decimal インスタンスは float から直接構成できるようになりました。

>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_float(float('nan'))
Decimal('NaN')
>>> Decimal.from_float(float('inf'))
Decimal('Infinity')
>>> Decimal.from_float(float('-inf'))
Decimal('-Infinity')

バージョン 3.1 で追加.

fma(other, third, context=None)

融合積和(fused multiply-add)です。self*other+third を途中結果の積 self*other で丸めを行わずに計算して返します。

>>> Decimal(2).fma(3, 5)
Decimal('11')
is_canonical()

引数が標準的(canonical)ならば True を返し、そうでなければ False を返します。現在のところ、 Decimal のインスタンスは常に標準的なのでこのメソッドの結果はいつでも True です。

is_finite()

引数が有限の数値ならば True を、無限大か NaN ならば False を返します。

is_infinite()

引数が正または負の無限大ならば True を、そうでなければ False を返します。

is_nan()

引数が (無言か発信かは問わず) NaN であれば True を、そうでなければ False を返します。

is_normal(context=None)

引数が 正規(normal) の有限数値ならば True を返します。引数がゼロ、非正規(subnormal)、無限大または NaN であれば False を返します。

is_qnan()

引数が無言 NaN であれば True を、そうでなければ False を返します。

is_signed()

引数に負の符号がついていれば True を、そうでなければ False を返します。注意すべきはゼロや NaN なども符号を持ち得ることです。

is_snan()

引数が発信 NaN であれば True を、そうでなければ False を返します。

is_subnormal(context=None)

引数が非正規数(subnormal)であれば True を、そうでなければ False を返します。

is_zero()

引数が(正または負の)ゼロであれば True を、そうでなければ False を返します。

ln(context=None)

演算対象の自然対数(底 e の対数)を返します。結果は ROUND_HALF_EVEN 丸めモードで正しく丸められます。

log10(context=None)

演算対象の底 10 の対数を返します。結果は ROUND_HALF_EVEN 丸めモードで正しく丸められます。

logb(context=None)

非零の数値については、 Decimal インスタンスとして調整された指数を返します。演算対象がゼロだった場合、 Decimal('-Infinity') が返され DivisionByZero フラグが送出されます。演算対象が無限大だった場合、 Decimal('Infinity') が返されます。

logical_and(other, context=None)

logical_and() は二つの 論理引数 (論理引数 参照)を取る論理演算です。結果は二つの引数の数字ごとの and です。

logical_invert(context=None)

logical_invert() は論理演算です。結果は引数の数字ごとの反転です。

logical_or(other, context=None)

logical_or() は二つの 論理引数 (論理引数 参照)を取る論理演算です。結果は二つの引数の数字ごとの or です。

logical_xor(other, context=None)

logical_xor() は二つの 論理引数 (論理引数 参照)を取る論理演算です。結果は二つの引数の数字ごとの排他的論理和です。

max(other, context=None)

Like max(self, other) except that the context rounding rule is applied before returning and that NaN values are either signaled or ignored (depending on the context and whether they are signaling or quiet).

max_mag(other, context=None)

max() メソッドに似ていますが、比較は絶対値で行われます。

min(other, context=None)

Like min(self, other) except that the context rounding rule is applied before returning and that NaN values are either signaled or ignored (depending on the context and whether they are signaling or quiet).

min_mag(other, context=None)

min() メソッドに似ていますが、比較は絶対値で行われます。

next_minus(context=None)

与えられたコンテキスト(またはコンテキストが渡されなければ現スレッドのコンテキスト)において表現可能な、操作対象より小さい最大の数を返します。

next_plus(context=None)

与えられたコンテキスト(またはコンテキストが渡されなければ現スレッドのコンテキスト)において表現可能な、操作対象より大きい最小の数を返します。

next_toward(other, context=None)

二つの比較対象が等しくなければ、一つめの対象に最も近く二つめの対象へ近付く方向の数を返します。もし両者が数値的に等しければ、二つめの対象の符号を採った一つめの対象のコピーを返します。

normalize(context=None)

Normalize the number by stripping the rightmost trailing zeros and converting any result equal to Decimal('0') to Decimal('0e0'). Used for producing canonical values for attributes of an equivalence class. For example, Decimal('32.100') and Decimal('0.321000e+2') both normalize to the equivalent value Decimal('32.1').

number_class(context=None)

操作対象の クラス を表す文字列を返します。返されるのは以下の10種類のいずれかです。

  • "-Infinity", 負の無限大であることを示します。

  • "-Normal", 負の通常数であることを示します。

  • "-Subnormal", 負の非正規数であることを示します。

  • "-Zero", 負のゼロであることを示します。

  • "+Zero", 正のゼロであることを示します。

  • "+Subnormal", 正の非正規数であることを示します。

  • "+Normal", 正の通常数であることを示します。

  • "+Infinity", 正の無限大であることを示します。

  • "NaN", 無言 (quiet) NaN (Not a Number) であることを示します。

  • "sNaN", 発信(signaling) NaN であることを示します。

quantize(exp, rounding=None, context=None)

二つ目の操作対象と同じ指数を持つように丸めを行った、一つめの操作対象と等しい値を返します。

>>> Decimal('1.41421356').quantize(Decimal('1.000'))
Decimal('1.414')

他の操作と違い、打ち切り(quantize)操作後の係数の長さが精度を越えた場合には、 InvalidOperation がシグナルされます。これによりエラー条件がない限り打ち切られた指数が常に右側の引数と同じになることが保証されます。

同様に、他の操作と違い、quantize は Underflow を、たとえ結果が非正規になったり不正確になったとしても、シグナルしません。

二つ目の演算対象の指数が一つ目のそれよりも大きければ丸めが必要かもしれません。この場合、丸めモードは以下のように決められます。rounding 引数が与えられていればそれが使われます。そうでなければ context 引数で決まります。どちらの引数も渡されなければ現在のスレッドのコンテキストの丸めモードが使われます。

An error is returned whenever the resulting exponent is greater than Emax or less than Etiny().

radix()

Decimal(10) つまり Decimal クラスがその全ての算術を実行する基数を返します。仕様との互換性のために取り入れられています。

remainder_near(other, context=None)

selfother で割った剰余を返します。これは self % other とは違って、剰余の絶対値を小さくするように符号が選ばれます。より詳しく言うと、nself / other の正確な値に最も近い整数としたときの self - n * other が返り値になります。最も近い整数が2つある場合には偶数のものが選ばれます。

結果が0になる場合の符号は self の符号と同じになります。

>>> Decimal(18).remainder_near(Decimal(10))
Decimal('-2')
>>> Decimal(25).remainder_near(Decimal(10))
Decimal('5')
>>> Decimal(35).remainder_near(Decimal(10))
Decimal('-5')
rotate(other, context=None)

一つ目の演算対象の数字を二つ目で指定された量だけ巡回(rotate)した結果を返します。二つめの演算対象は -precision から precision までの範囲の整数でなければなりません。この二つ目の演算対象の絶対値を何桁ずらすかを決めます。そしてもし正の数ならば巡回の方向は左に、そうでなければ右になります。一つ目の演算対象の仮数部は必要ならば精度いっぱいまでゼロで埋められます。符号と指数は変えられません。

same_quantum(other, context=None)

Test whether self and other have the same exponent or whether both are NaN.

この演算はコンテキストに影響されず、静かです。すなわち、フラグは変更されず、丸めは行われません。例外として、2番目の比較対象の厳密な変換ができない場合、C バージョンのライブラリでは InvalidOperation 例外を送出するかもしれません。

scaleb(other, context=None)

二つ目の演算対象で調整された指数の一つ目の演算対象を返します。同じことですが、一つめの演算対象を 10**other 倍したものを返します。二つ目の演算対象は整数でなければなりません。

shift(other, context=None)

一つ目の演算対象の数字を二つ目で指定された量だけシフトした結果を返します。二つ目の演算対象は -precision から precision までの範囲の整数でなければなりません。この二つ目の演算対象の絶対値が何桁ずらすかを決めます。そしてもし正の数ならばシフトの方向は左に、そうでなければ右になります。一つ目の演算対象の係数は必要ならば精度いっぱいまでゼロで埋められます。符号と指数は変えられません。

sqrt(context=None)

引数の平方根を最大精度で求めます。

to_eng_string(context=None)

文字列に変換します。指数が必要なら工学表記が使われます。

工学表記法では指数は 3 の倍数になります。これにより、基数の小数部には最大で 3 桁までの数字が残されるとともに、末尾に 1 つまたは 2 つの 0 の付加が必要とされるかもしれません。

たとえば、Decimal('123E+1')Decimal('1.23E+3') に変換されます。

to_integral(rounding=None, context=None)

to_integral_value() メソッドと同じです。to_integral の名前は古いバージョンとの互換性のために残されています。

to_integral_exact(rounding=None, context=None)

最近傍の整数に値を丸め、丸めが起こった場合には Inexact または Rounded のシグナルを適切に出します。丸めモードは以下のように決められます。 rounding 引数が与えられていればそれが使われます。そうでなければ context 引数で決まります。どちらの引数も渡されなければ現在のスレッドのコンテキストの丸めモードが使われます。

to_integral_value(rounding=None, context=None)

InexactRounded といったシグナルを出さずに最近傍の整数に値を丸めます。 rounding が指定されていれば適用されます; それ以外の場合、値丸めの方法は context の設定か現在のコンテキストの設定になります。

論理引数

The logical_and(), logical_invert(), logical_or(), and logical_xor() methods expect their arguments to be logical operands. A logical operand is a Decimal instance whose exponent and sign are both zero, and whose digits are all either 0 or 1.

Context オブジェクト

コンテキスト (context) とは、算術演算における環境設定です。コンテキストは計算精度を決定し、値丸めの方法を設定し、シグナルのどれが例外になるかを決め、指数の範囲を制限しています。

多重スレッドで処理を行う場合には各スレッドごとに現在のコンテキストがあり、 getcontext()setcontext() といった関数でアクセスしたり設定変更できます:

decimal.getcontext()

アクティブなスレッドの現在のコンテキストを返します。

decimal.setcontext(c)

アクティブなスレッドのコンテキストを c に設定します。

with 文と localcontext() 関数を使って実行するコンテキストを一時的に変更することもできます。

decimal.localcontext(ctx=None)

with 文の入口でアクティブなスレッドのコンテキストを ctx のコピーに設定し、with 文を抜ける時に元のコンテキストに復旧する、コンテキストマネージャを返します。コンテキストが指定されなければ、現在のコンテキストのコピーが使われます。

たとえば、以下のコードでは精度を42桁に設定し、計算を実行し、そして元のコンテキストに復帰します:

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

新たなコンテキストは、以下で説明する Context コンストラクタを使って生成できます。その他にも、 decimal モジュールでは作成済みのコンテキストを提供しています:

class decimal.BasicContext

汎用十進演算仕様で定義されている標準コンテキストの一つです。精度は 9 桁に設定されています。丸め規則は ROUND_HALF_UP です。すべての演算結果フラグはクリアされています。 Inexact, Rounded, Subnormal を除く全ての演算エラートラップが有効 (例外として扱う) になっています。

多くのトラップが有効になっているので、デバッグの際に便利なコンテキストです。

class decimal.ExtendedContext

汎用十進演算仕様で定義されている標準コンテキストの一つです。精度は 9 桁に設定されています。丸め規則は ROUND_HALF_EVEN です。すべての演算結果フラグはクリアされています。トラップは全て無効(演算中に一切例外を送出しない) になっています。

Because the traps are disabled, this context is useful for applications that prefer to have result value of NaN or Infinity instead of raising exceptions. This allows an application to complete a run in the presence of conditions that would otherwise halt the program.

class decimal.DefaultContext

Context コンストラクタが新たなコンテキストを作成するさいに雛形にするコンテキストです。このコンテキストのフィールド (精度の設定など) を変更すると、 Context コンストラクタが生成する新たなコンテキストに影響を及ぼします。

このコンテキストは、主に多重スレッド環境で便利です。スレッドを開始する前に何らかのフィールドを変更しておくと、システム全体のデフォルト設定に効果を及ぼすことができます。スレッドを開始した後にフィールドを変更すると、競合条件を抑制するためにスレッドを同期化しなければならないので、推奨しません。

単一スレッドの環境では、このコンテキストを使わないよう薦めます。下で述べるように明示的にコンテキストを作成してください。

The default values are Context.prec=28, Context.rounding=ROUND_HALF_EVEN, and enabled traps for Overflow, InvalidOperation, and DivisionByZero.

上に挙げた三つのコンテキストに加え、 Context コンストラクタを使って新たなコンテキストを生成できます。

class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)

新たなコンテキストを生成します。あるフィールドが定義されていないか None であれば、 DefaultContext からデフォルト値をコピーします。 flags フィールドが設定されていいか None の場合には、全てのフラグがクリアされます。

prec is an integer in the range [1, MAX_PREC] that sets the precision for arithmetic operations in the context.

rounding オプションは、節 丸めモード で挙げられる定数の一つです。

traps および flags フィールドには、セットしたいシグナルを列挙します。一般的に、新たなコンテキストを作成するときにはトラップだけを設定し、フラグはクリアしておきます。

The Emin and Emax fields are integers specifying the outer limits allowable for exponents. Emin must be in the range [MIN_EMIN, 0], Emax in the range [0, MAX_EMAX].

The capitals field is either 0 or 1 (the default). If set to 1, exponents are printed with a capital E; otherwise, a lowercase e is used: Decimal('6.02e+23').

The clamp field is either 0 (the default) or 1. If set to 1, the exponent e of a Decimal instance representable in this context is strictly limited to the range Emin - prec + 1 <= e <= Emax - prec + 1. If clamp is 0 then a weaker condition holds: the adjusted exponent of the Decimal instance is at most Emax. When clamp is 1, a large normal number will, where possible, have its exponent reduced and a corresponding number of zeros added to its coefficient, in order to fit the exponent constraints; this preserves the value of the number but loses information about significant trailing zeros. For example:

>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999')
Decimal('1.23000E+999')

A clamp value of 1 allows compatibility with the fixed-width decimal interchange formats specified in IEEE 754.

The Context class defines several general purpose methods as well as a large number of methods for doing arithmetic directly in a given context. In addition, for each of the Decimal methods described above (with the exception of the adjusted() and as_tuple() methods) there is a corresponding Context method. For example, for a Context instance C and Decimal instance x, C.exp(x) is equivalent to x.exp(context=C). Each Context method accepts a Python integer (an instance of int) anywhere that a Decimal instance is accepted.

clear_flags()

Resets all of the flags to 0.

clear_traps()

Resets all of the traps to 0.

バージョン 3.3 で追加.

copy()

コンテキストの複製を返します。

copy_decimal(num)

Decimal インスタンス num のコピーを返します。

create_decimal(num)

self をコンテキストとする新たな Decimal インスタンスを num から生成します。 Decimal コンストラクタと違い、数値を変換する際にコンテキストの精度、値丸め方法、フラグ、トラップを適用します。

定数値はしばしばアプリケーションの要求よりも高い精度を持っているため、このメソッドが役に立ちます。また、値丸めを即座に行うため、例えば以下のように、入力値に値丸めを行わないために合計値にゼロの加算を追加するだけで結果が変わってしまうといった、現在の精度よりも細かい値の影響が紛れ込む問題を防げるという恩恵もあります。以下の例は、丸められていない入力を使うということは和にゼロを加えると結果が変わり得るという見本です:

>>> getcontext().prec = 3
>>> Decimal('3.4445') + Decimal('1.0023')
Decimal('4.45')
>>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023')
Decimal('4.44')

このメソッドは IBM 仕様の to-number 演算を実装したものです。引数が文字列の場合、前や後ろに余計な空白を付けたり、アンダースコアを含めたりすることは許されません。

create_decimal_from_float(f)

浮動小数点数 f から新しい Decimal インスタンスを生成しますが、 self をコンテキストとして丸めます。 Decimal.from_float() クラスメソッドとは違い、変換にコンテキストの精度、丸めメソッド、フラグ、そしてトラップが適用されます。

>>> context = Context(prec=5, rounding=ROUND_DOWN)
>>> context.create_decimal_from_float(math.pi)
Decimal('3.1415')
>>> context = Context(prec=5, traps=[Inexact])
>>> context.create_decimal_from_float(math.pi)
Traceback (most recent call last):
    ...
decimal.Inexact: None

バージョン 3.1 で追加.

Etiny()

Emin - prec + 1 に等しい値を返します。演算結果の劣化が起こる桁の最小値です。アンダーフローが起きた場合、指数は Etiny に設定されます。

Etop()

Emax - prec + 1 に等しい値を返します。

Decimal を使った処理を行う場合、通常は Decimal インスタンスを生成して、算術演算を適用するというアプローチをとります。演算はアクティブなスレッドにおける現在のコンテキストの下で行われます。もう一つのアプローチは、コンテキストのメソッドを使った特定のコンテキスト下での計算です。コンテキストのメソッドは Decimal クラスのメソッドに似ているので、ここでは簡単な説明にとどめます。

abs(x)

x の絶対値を返します。

add(x, y)

xy の和を返します。

canonical(x)

同じ Decimal オブジェクト x を返します。

compare(x, y)

xy を数値として比較します。

compare_signal(x, y)

二つの演算対象の値を数値として比較します。

compare_total(x, y)

二つの演算対象を抽象的な表現を使って比較します。

compare_total_mag(x, y)

二つの演算対象を抽象的な表現を使い符号を無視して比較します。

copy_abs(x)

x のコピーの符号を 0 にセットして返します。

copy_negate(x)

x のコピーの符号を反転して返します。

copy_sign(x, y)

y から x に符号をコピーします。

divide(x, y)

xy で除算した値を返します。

divide_int(x, y)

xy で除算した値を整数に切り捨てて返します。

divmod(x, y)

二つの数値間の除算を行い、結果の整数部を返します。

exp(x)

e ** x を返します。

fma(x, y, z)

xy 倍したものに z を加えて返します。

is_canonical(x)

x が標準的(canonical)ならば True を返します。そうでなければ False です。

is_finite(x)

x が有限ならば True を返します。そうでなければ False です。

is_infinite(x)

x が無限ならば True を返します。そうでなければ False です。

is_nan(x)

x が qNaN か sNaN であれば True を返します。そうでなければ False です。

is_normal(x)

x が通常の数ならば True を返します。そうでなければ False です。

is_qnan(x)

x が無言 NaN であれば True を返します。そうでなければ False です。

is_signed(x)

x が負の数であれば True を返します。そうでなければ False です。

is_snan(x)

x が発信 NaN であれば True を返します。そうでなければ False です。

is_subnormal(x)

x が非正規数であれば True を返します。そうでなければ False です。

is_zero(x)

x がゼロであれば True を返します。そうでなければ False です。

ln(x)

x の自然対数(底 e の対数)を返します。

log10(x)

x の底 10 の対数を返します。

logb(x)

演算対象の MSD の大きさの指数部を返します。

logical_and(x, y)

それぞれの桁に論理演算 and を当てはめます。

logical_invert(x)

x の全ての桁を反転させます。

logical_or(x, y)

それぞれの桁に論理演算 or を当てはめます。

logical_xor(x, y)

それぞれの桁に論理演算 xor を当てはめます。

max(x, y)

二つの値を数値として比較し、大きいほうを返します。

max_mag(x, y)

値を符号を無視して数値として比較します。

min(x, y)

二つの値を数値として比較し、小さいほうを返します。

min_mag(x, y)

値を符号を無視して数値として比較します。

minus(x)

Python における単項マイナス演算子に対応する演算です。

multiply(x, y)

xy の積を返します。

next_minus(x)

x より小さい最大の表現可能な数を返します。

next_plus(x)

x より大きい最小の表現可能な数を返します。

next_toward(x, y)

xy の方向に向かって最も近い数を返します。

normalize(x)

x をもっとも単純な形にします。

number_class(x)

x のクラスを指し示すものを返します。

plus(x)

Python における単項のプラス演算子に対応する演算です。コンテキストにおける精度や値丸めを適用するので、等値 (identity) 演算とは 違います

power(x, y, modulo=None)

xy 乗を計算します。modulo が指定されていればモジュロを取ります。

引数が 2 つの場合、 x**y を計算します。x が負の場合、 y は整数でなければなりません。y が整数、結果が有限、結果が 'precision' 桁で正確に表現できる、という条件をすべて満たさない場合、結果は不正確になります。結果はコンテキストの丸めモードを使って丸められます。結果は常に、Python バージョンにおいて正しく丸められます。

Decimal(0) ** Decimal(0) results in InvalidOperation, and if InvalidOperation is not trapped, then results in Decimal('NaN').

バージョン 3.3 で変更: C モジュールは power() を適切に丸められた exp() および ln() 関数によって計算します。結果は well-defined ですが、「ほとんどの場合には適切に丸められる」だけです。

引数が 3 つの場合、 (x**y) % modulo を計算します。この 3 引数の形式の場合、引数には以下の制限が課せられます。

  • 全ての引数は整数

  • y は非負でなければならない

  • xy の少なくともどちらかはゼロでない

  • modulo は非零で大きくても 'precision' 桁

Context.power(x, y, modulo) で得られる値は (x**y) % modulo を精度無制限で計算して得られるものと同じ値ですが、より効率的に計算されます。結果の指数は x, y, modulo の指数に関係なくゼロです。この計算は常に正確です。

quantize(x, y)

x に値丸めを適用し、指数を y にした値を返します。

radix()

単に 10 を返します。何せ十進ですから :)

remainder(x, y)

整数除算の剰余を返します。

剰余がゼロでない場合、符号は割られる数の符号と同じになります。

remainder_near(x, y)

x - y * n を返します。ここで nx / y の正確な値に一番近い整数です (この結果が 0 ならばその符号は x の符号と同じです)。

rotate(x, y)

xy 回巡回したコピーを返します。

same_quantum(x, y)

2つの演算対象が同じ指数を持っている場合に True を返します。

scaleb(x, y)

一つめの演算対象の指数部に二つめの値を加えたものを返します。

shift(x, y)

xy 回シフトしたコピーを返します。

sqrt(x)

x の平方根を精度いっぱいまで求めます。

subtract(x, y)

xy の間の差を返します。

to_eng_string(x)

文字列に変換します。指数が必要なら工学表記が使われます。

工学表記法では指数は 3 の倍数になります。これにより、基数の小数部には最大で 3 桁までの数字が残されるとともに、末尾に 1 つまたは 2 つの 0 の付加が必要とされるかもしれません。

to_integral_exact(x)

最近傍の整数に値を丸めます。

to_sci_string(x)

数値を科学表記で文字列に変換します。

定数

この節の定数は C モジュールにのみ意味があります。互換性のために、pure Python 版も含まれます。

32-bit

64-bit

decimal.MAX_PREC

425000000

999999999999999999

decimal.MAX_EMAX

425000000

999999999999999999

decimal.MIN_EMIN

-425000000

-999999999999999999

decimal.MIN_ETINY

-849999999

-1999999999999999997

decimal.HAVE_THREADS

値は True です。現在のPythonは常にスレッドを持っているので、非推奨になりました。

バージョン 3.9 で非推奨.

decimal.HAVE_CONTEXTVAR

The default value is True. If Python is configured using the --without-decimal-contextvar option, the C version uses a thread-local rather than a coroutine-local context and the value is False. This is slightly faster in some nested context scenarios.

バージョン 3.9 で追加: 3.7 と 3.8 にバックポートされました。

丸めモード

decimal.ROUND_CEILING

Round towards Infinity.

decimal.ROUND_DOWN

ゼロ方向に丸めます。

decimal.ROUND_FLOOR

Round towards -Infinity.

decimal.ROUND_HALF_DOWN

近い方に、引き分けはゼロ方向に向けて丸めます。

decimal.ROUND_HALF_EVEN

近い方に、引き分けは偶数整数方向に向けて丸めます。

decimal.ROUND_HALF_UP

近い方に、引き分けはゼロから遠い方向に向けて丸めます。

decimal.ROUND_UP

ゼロから遠い方向に丸めます。

decimal.ROUND_05UP

ゼロ方向に丸めた後の最後の桁が 0 または 5 ならばゼロから遠い方向に、そうでなければゼロ方向に丸めます。

シグナル

シグナルは、計算中に生じた様々なエラー条件を表現します。各々のシグナルは一つのコンテキストフラグと一つのトラップイネーブラに対応しています。

コンテキストフラグは、該当するエラー条件に遭遇するたびにセットされます。演算後にフラグを調べれば、演算に関する情報 (例えば計算が厳密だったかどうか) がわかります。フラグを調べたら、次の計算を始める前にフラグを全てクリアするようにしてください。

あるコンテキストのトラップイネーブラがあるシグナルに対してセットされている場合、該当するエラー条件が生じると Python の例外を送出します。例えば、 DivisionByZero が設定されていると、エラー条件が生じた際に DivisionByZero 例外を送出します。

class decimal.Clamped

値の表現上の制限に沿わせるために指数部が変更されたことを通知します。

Typically, clamping occurs when an exponent falls outside the context's Emin and Emax limits. If possible, the exponent is reduced to fit by adding zeros to the coefficient.

class decimal.DecimalException

他のシグナルの基底クラスで、 ArithmeticError のサブクラスです。

class decimal.DivisionByZero

有限値をゼロで除算したときのシグナルです。

Can occur with division, modulo division, or when raising a number to a negative power. If this signal is not trapped, returns Infinity or -Infinity with the sign determined by the inputs to the calculation.

class decimal.Inexact

値の丸めによって演算結果から厳密さが失われたことを通知します。

このシグナルは値丸め操作中にゼロでない桁を無視した際に生じます。演算結果は値丸め後の値です。シグナルのフラグやトラップは、演算結果の厳密さが失われたことを検出するために使えるだけです。

class decimal.InvalidOperation

無効な演算が実行されたことを通知します。

Indicates that an operation was requested that does not make sense. If not trapped, returns NaN. Possible causes include:

Infinity - Infinity
0 * Infinity
Infinity / Infinity
x % 0
Infinity % x
sqrt(-x) and x > 0
0 ** 0
x ** (non-integer)
x ** Infinity
class decimal.Overflow

数値オーバフローを示すシグナルです。

Indicates the exponent is larger than Context.Emax after rounding has occurred. If not trapped, the result depends on the rounding mode, either pulling inward to the largest representable finite number or rounding outward to Infinity. In either case, Inexact and Rounded are also signaled.

class decimal.Rounded

情報が全く失われていない場合も含み、値丸めが起きたときのシグナルです。

Signaled whenever rounding discards digits; even if those digits are zero (such as rounding 5.00 to 5.0). If not trapped, returns the result unchanged. This signal is used to detect loss of significant digits.

class decimal.Subnormal

Exponent was lower than Emin prior to rounding.

演算結果が微小である場合 (指数が小さすぎる場合) に発生します。このシグナルをトラップしなければ、演算結果をそのまま返します。

class decimal.Underflow

演算結果が値丸めによってゼロになった場合に生じる数値アンダフローです。

演算結果が微小なため、値丸めによってゼロになった場合に発生します。 Inexact および Subnormal シグナルも同時に発生します。

class decimal.FloatOperation

float と Decimal の混合の厳密なセマンティクスを有効にします。

シグナルがトラップされなかった場合 (デフォルト)、Decimal コンストラクタ、 create_decimal() 、およびすべての比較演算子において float と Decimal の混合が許されます。変換も比較も正確です。コンテキストフラグ内に FloatOperation を設定することで、混合操作は現れるたびに暗黙に記録されます。 from_float()create_decimal_from_float() による明示的な変換はフラグを設定しません。

そうでなければ (シグナルがトラップされれば)、等価性比較および明示的な変換のみが静かにに行われ、その他の混合演算は FloatOperation を送出します。

これらのシグナルの階層構造をまとめると、以下の表のようになります:

exceptions.ArithmeticError(exceptions.Exception)
    DecimalException
        Clamped
        DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
        Inexact
            Overflow(Inexact, Rounded)
            Underflow(Inexact, Rounded, Subnormal)
        InvalidOperation
        Rounded
        Subnormal
        FloatOperation(DecimalException, exceptions.TypeError)

浮動小数点数に関する注意

精度を上げて丸め誤差を抑制する

The use of decimal floating point eliminates decimal representation error (making it possible to represent 0.1 exactly); however, some operations can still incur round-off error when non-zero digits exceed the fixed precision.

値丸めによる誤差の影響は、桁落ちを生じるような、ほとんど相殺される量での加算や減算によって増幅されます。Knuth は、十分でない計算精度の下で値丸めを伴う浮動小数点演算を行った結果、加算の結合則や分配則における恒等性が崩れてしまう例を二つ示しています:

# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8

>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')

>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')

decimal モジュールでは、最下桁を失わないように十分に計算精度を広げることで、上で問題にしたような恒等性をとりもどせます:

>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')

特殊値

The number system for the decimal module provides special values including NaN, sNaN, -Infinity, Infinity, and two zeros, +0 and -0.

無限大 (Infinity) は Decimal('Infinity') で直接構築できます。また、 DivisionByZero をトラップせずにゼロで除算を行った場合にも出てきます。同様に、 Overflow シグナルをトラップしなければ、表現可能な最大の数値の制限を越えた値を丸めたときに出てきます。

無限大には符号があり (アフィン: affine であり)、算術演算に使用でき、非常に巨大で不確定の(indeterminate)値として扱われます。例えば、無限大に何らかの定数を加算すると、演算結果は別の無限大になります。

Some operations are indeterminate and return NaN, or if the InvalidOperation signal is trapped, raise an exception. For example, 0/0 returns NaN which means "not a number". This variety of NaN is quiet and, once created, will flow through other computations always resulting in another NaN. This behavior can be useful for a series of computations that occasionally have missing inputs --- it allows the calculation to proceed while flagging specific results as invalid.

A variant is sNaN which signals rather than remaining quiet after every operation. This is a useful return value when an invalid result needs to interrupt a calculation for special handling.

The behavior of Python's comparison operators can be a little surprising where a NaN is involved. A test for equality where one of the operands is a quiet or signaling NaN always returns False (even when doing Decimal('NaN')==Decimal('NaN')), while a test for inequality always returns True. An attempt to compare two Decimals using any of the <, <=, > or >= operators will raise the InvalidOperation signal if either operand is a NaN, and return False if this signal is not trapped. Note that the General Decimal Arithmetic specification does not specify the behavior of direct comparisons; these rules for comparisons involving a NaN were taken from the IEEE 854 standard (see Table 3 in section 5.7). To ensure strict standards-compliance, use the compare() and compare_signal() methods instead.

アンダフローの起きた計算は、符号付きのゼロ (signed zero) を返すことがあります。符号は、より高い精度で計算を行った結果の符号と同じになります。符号付きゼロの大きさはやはりゼロなので、正のゼロと負のゼロは等しいとみなされ、符号は単なる参考にすぎません。

二つの符号付きゼロが区別されているのに等価であることに加えて、異なる精度におけるゼロの表現はまちまちなのに、値は等価とみなされるということがあります。これに慣れるには多少時間がかかります。正規化浮動小数点表現に目が慣れてしまうと、以下の計算でゼロに等しい値が返っているとは即座に分かりません:

>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')

スレッドを使った処理

関数 getcontext() は、スレッド毎に別々の Context オブジェクトにアクセスします。別のスレッドコンテキストを持つということは、複数のスレッドが互いに影響を及ぼさずに (getcontext().prec=10 のような) 変更を適用できるということです。

同様に、setcontext() 関数は自動的に引数のコンテキストを現在のスレッドのコンテキストに設定します。

getcontext() を呼び出す前に setcontext() が呼び出されていなければ、現在のスレッドで使うための新たなコンテキストを生成するために getcontext() が自動的に呼び出されます。

新たなコンテキストは、DefaultContext と呼ばれる雛形からコピーされます。アプリケーションを通じて全てのスレッドに同じ値を使うようにデフォルトを設定したければ、DefaultContext オブジェクトを直接変更します。 getcontext() を呼び出すスレッド間で競合条件が生じないようにするため、DefaultContext への変更はいかなるスレッドを開始するよりも 前に 行わなければなりません。以下に例を示します:

# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)

# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
 . . .

レシピ

Decimal クラスの利用を実演している例をいくつか示します。これらはユーティリティ関数としても利用できます:

def moneyfmt(value, places=2, curr='', sep=',', dp='.',
             pos='', neg='-', trailneg=''):
    """Convert Decimal to a money formatted string.

    places:  required number of places after the decimal point
    curr:    optional currency symbol before the sign (may be blank)
    sep:     optional grouping separator (comma, period, space, or blank)
    dp:      decimal point indicator (comma or period)
             only specify as blank when places is zero
    pos:     optional sign for positive numbers: '+', space or blank
    neg:     optional sign for negative numbers: '-', '(', space or blank
    trailneg:optional trailing minus indicator:  '-', ')', space or blank

    >>> d = Decimal('-1234567.8901')
    >>> moneyfmt(d, curr='$')
    '-$1,234,567.89'
    >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
    '1.234.568-'
    >>> moneyfmt(d, curr='$', neg='(', trailneg=')')
    '($1,234,567.89)'
    >>> moneyfmt(Decimal(123456789), sep=' ')
    '123 456 789.00'
    >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
    '<0.02>'

    """
    q = Decimal(10) ** -places      # 2 places --> '0.01'
    sign, digits, exp = value.quantize(q).as_tuple()
    result = []
    digits = list(map(str, digits))
    build, next = result.append, digits.pop
    if sign:
        build(trailneg)
    for i in range(places):
        build(next() if digits else '0')
    if places:
        build(dp)
    if not digits:
        build('0')
    i = 0
    while digits:
        build(next())
        i += 1
        if i == 3 and digits:
            i = 0
            build(sep)
    build(curr)
    build(neg if sign else pos)
    return ''.join(reversed(result))

def pi():
    """Compute Pi to the current precision.

    >>> print(pi())
    3.141592653589793238462643383

    """
    getcontext().prec += 2  # extra digits for intermediate steps
    three = Decimal(3)      # substitute "three=3.0" for regular floats
    lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
    while s != lasts:
        lasts = s
        n, na = n+na, na+8
        d, da = d+da, da+32
        t = (t * n) / d
        s += t
    getcontext().prec -= 2
    return +s               # unary plus applies the new precision

def exp(x):
    """Return e raised to the power of x.  Result type matches input type.

    >>> print(exp(Decimal(1)))
    2.718281828459045235360287471
    >>> print(exp(Decimal(2)))
    7.389056098930650227230427461
    >>> print(exp(2.0))
    7.38905609893
    >>> print(exp(2+0j))
    (7.38905609893+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num = 0, 0, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 1
        fact *= i
        num *= x
        s += num / fact
    getcontext().prec -= 2
    return +s

def cos(x):
    """Return the cosine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(cos(Decimal('0.5')))
    0.8775825618903727161162815826
    >>> print(cos(0.5))
    0.87758256189
    >>> print(cos(0.5+0j))
    (0.87758256189+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

def sin(x):
    """Return the sine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(sin(Decimal('0.5')))
    0.4794255386042030002732879352
    >>> print(sin(0.5))
    0.479425538604
    >>> print(sin(0.5+0j))
    (0.479425538604+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

Decimal FAQ

Q. decimal.Decimal('1234.5') などと打ち込むのは煩わしいのですが、対話式インタプリタを使う際にタイプ量を少なくする方法はありませんか?

A. コンストラクタを1文字に縮める人もいるようです:

>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')

Q. 小数点以下2桁の固定小数点数のアプリケーションの中で、いくつかの入力が余計な桁を保持しているのでこれを丸めなければなりません。その他のものに余計な桁はなくそのまま使えます。どのメソッドを使うのがいいでしょうか?

A. The quantize() method rounds to a fixed number of decimal places. If the Inexact trap is set, it is also useful for validation:

>>> TWOPLACES = Decimal(10) ** -2       # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
   ...
Inexact: None

Q. 正当な2桁の入力が得られたとして、その正当性をアプリケーション実行中も変わらず保ち続けるにはどうすればいいでしょうか?

A. Some operations like addition, subtraction, and multiplication by an integer will automatically preserve fixed point. Others operations, like division and non-integer multiplication, will change the number of decimal places and need to be followed-up with a quantize() step:

>>> a = Decimal('102.72')           # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b                           # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42                          # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES)     # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES)     # And quantize division
Decimal('0.03')

In developing fixed-point applications, it is convenient to define functions to handle the quantize() step:

>>> def mul(x, y, fp=TWOPLACES):
...     return (x * y).quantize(fp)
>>> def div(x, y, fp=TWOPLACES):
...     return (x / y).quantize(fp)
>>> mul(a, b)                       # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')

Q. There are many ways to express the same value. The numbers 200, 200.000, 2E2, and .02E+4 all have the same value at various precisions. Is there a way to transform them to a single recognizable canonical value?

A. The normalize() method maps all equivalent values to a single representative:

>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]

Q. ある種の十進数値はいつも指数表記で表示されます。指数表記以外の表示にする方法はありますか?

A. For some values, exponential notation is the only way to express the number of significant places in the coefficient. For example, expressing 5.0E+3 as 5000 keeps the value constant but cannot show the original's two-place significance.

もしアプリケーションが有効数字の追跡を等閑視するならば、指数部や末尾のゼロを取り除き、有効数字を忘れ、しかし値を変えずにおくことは容易です:

>>> def remove_exponent(d):
...     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

Q. 普通の float を Decimal に変換できますか?

A. はい。どんな 2 進浮動小数点数も Decimal として正確に表現できます。ただし、正確な変換は直感的に考えたよりも多い桁になることがあります:

>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

Q. 複雑な計算の中で、精度不足や丸めの異常で間違った結果になっていないことをどうやって保証すれば良いでしょうか。

A. decimal モジュールでは検算は容易です。一番良い方法は、大きめの精度や様々な丸めモードで再計算してみることです。大きく異なった結果が出てきたら、精度不足や丸めの問題や悪条件の入力、または数値計算的に不安定なアルゴリズムを示唆しています。

Q. コンテキストの精度は計算結果には適用されていますが入力には適用されていないようです。様々に異なる精度の入力値を混ぜて計算する時に注意すべきことはありますか?

A. はい。原則として入力値は正確であると見做しておりそれらの値を使った計算も同様です。結果だけが丸められます。入力の強みは "what you type is what you get" (打ち込んだ値が得られる値)という点にあります。入力が丸められないということを忘れていると結果が奇妙に見えるというのは弱点です:

>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')

解決策は、精度を増やすか、単項プラス演算子を使って入力の丸めを強制することです:

>>> getcontext().prec = 3
>>> +Decimal('1.23456789')      # unary plus triggers rounding
Decimal('1.23')

もしくは、入力を Context.create_decimal() を使って生成時に丸めてしまうこともできます:

>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')

Q. CPython 実装は大きな数に対しても速いでしょうか?

A. はい。CPython 実装と PyPy3 実装では、 C/CFFI 版の decimal モジュールは、任意精度の正しい丸めを行う 10 進浮動小数点演算のための高速な libmpdec ライブラリを統合しています。libmpdecKaratsuba multiplication を中程度のサイズの数に対して使い、 Number Theoretic Transform を非常に大きな数に対して使います。

The context must be adapted for exact arbitrary precision arithmetic. Emin and Emax should always be set to the maximum values, clamp should always be 0 (the default). Setting prec requires some care.

The easiest approach for trying out bignum arithmetic is to use the maximum value for prec as well 2:

>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')

For inexact results, MAX_PREC is far too large on 64-bit platforms and the available memory will be insufficient:

>>> Decimal(1) / 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

On systems with overallocation (e.g. Linux), a more sophisticated approach is to adjust prec to the amount of available RAM. Suppose that you have 8GB of RAM and expect 10 simultaneous operands using a maximum of 500MB each:

>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  decimal.Inexact: [<class 'decimal.Inexact'>]

In general (and especially on systems without overallocation), it is recommended to estimate even tighter bounds and set the Inexact trap if all calculations are expected to be exact.

1

バージョン 3.3 で追加.

2

バージョン 3.9 で変更: This approach now works for all exact results except for non-integer powers.