# 3 `decimal` -- 10進浮動小数点数の算術演算

バージョン 2.4 で 新たに追加 された仕様です。

`decimal` モジュールは10 進の浮動小数点算術をサポートします。 `decimal` には、 `float()` データ型に比べて、以下のような 利点があります:

- 10 進数を正確に表現できます。`1.1` のような数は、2 進数の 浮動小数点型では正しく表現できません。エンドユーザは普通、 2 進数における`1.1` の近似値が`1.1000000000000001` だからといって、そのように表示してほしいとは考えないものです。

- 値の正確さは算術にも及びます。10 進の浮動小数点による計算では、 "`0.1 + 0.1 + 0.1 - 0.3`" は厳密にゼロに等しくなります。 2 進浮動小数点では`5.5511151231257827e-017` になってしまいます。 ゼロに近い値とはいえ、この誤差は数値間の等価性テストの信頼性を阻害します。 また、誤差が蓄積されることもあります。こうした理由から、数値間の等価性を 厳しく保たねばならないようなアプリケーションを考えるなら、10 進数による 数値表現が望ましいということになります。

- `decimal` モジュールでは、有効桁数の表記が取り入れられており、 例えば "`1.30 + 1.20`" は `2.50` になります。すなわち、 末尾のゼロは有効数字を示すために残されます。こうした仕様は通貨計算を行う アプリケーションでは慣例です。乗算の場合、「教科書的な」アプローチでは、 乗算の被演算子すべての桁数を使います。 例えば、"`1.3 * 1.2`" は `1.56` になり、 "`1.30 * 1.20`" は `1.5600` になります。

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

      >>> getcontext().prec = 6
      >>> Decimal(1) / Decimal(7)
      Decimal("0.142857")
      >>> getcontext().prec = 28
      >>> Decimal(1) / Decimal(7)
      Decimal("0.1428571428571428571428571429")

- 2 進と 10 進の浮動小数点は、いずれも広く公開されている標準仕様の もとに実装されています。組み込みの浮動小数点型では、標準仕様で提唱されている 機能のほんのささやかな部分を利用できるにすぎませんが、 `decimal` では標準仕様が要求している全ての機能を利用できます。必要に応じて、 プログラマは値の丸めやシグナル処理を完全に制御できます。

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

10 進数型は変更不可能な型です。この型には符号部、仮数部、そして指数部 があります。有効桁数を残すために、仮数部の末尾にあるゼロの切り詰めは 行われません。 `decimal` では、 `Infinity`, `-Infinity`, および `NaN` といった特殊な値も定義されています。 標準仕様では `-0` と `+0` も区別しています。

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

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

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

参考:

IBM による汎用 10 進演算仕様、 The General Decimal Arithmetic Specification。

IEEE 標準化仕様 854-1987, IEEE 854 に関する非公式のテキスト。