2021-04-05に投稿

Python 標準ライブラリ decimal 10進数小数

読了目安:26分

10進数小数を取り扱うためのライブラリdecimalを使うと、
10進数を正確に計算できます。

Decimalオブジェクトの宣言

import decimal

decimal.Decimal() # => Decimal('0')
decimal.Decimal(0) # => Decimal('0')
decimal.Decimal('0') # => Decimal('0')
decimal.Decimal('3.141592653589793238462643383279502884197169399375105820974944592')
# => Decimal('3.141592653589793238462643383279502884197169399375105820974944592')
decimal.Decimal('Infinity') # => Decimal('Infinity')
decimal.Decimal('-Infinity') # => Decimal('-Infinity')
decimal.Decimal('NaN') # => Decimal('NaN') 無言 (quiet) NaN (Not a Number) 
decimal.Decimal('sNaN') # => Decimal('sNaN') 発信(signaling) NaN

Decimalのメソッド

adjusted () 仮数の整数部1桁にした場合の指数部

decimal.Decimal('667.4e-13').adjusted() # => -11

as_integer_ratio() 分数表示での整数ペア

decimal.Decimal('2.71828').as_integer_ratio() # => (67957, 25000)

as_tuple() 数値を示す名前付きタプル

decimal.Decimal('667.4e-13').as_tuple() # => DecimalTuple(sign=0, digits=(6, 6, 7, 4), exponent=-14)

copy_abs() 絶対値取得

decimal.Decimal('1.23').copy_abs() # => Decimal('1.23')
decimal.Decimal('-1.23').copy_abs() # => Decimal('1.23')

copy_abs() 符号反転

decimal.Decimal('1.23').copy_negate() # => Decimal('-1.23')
decimal.Decimal('-1.23').copy_negate() # => Decimal('1.23')

copy_abs() 符号のコピー

decimal.Decimal('1.23').copy_sign(decimal.Decimal('0.1')) # => Decimal('1.23')
decimal.Decimal('1.23').copy_sign(decimal.Decimal('-0.1')) # => Decimal('-1.23')
decimal.Decimal('-1.23').copy_sign(decimal.Decimal('0.1')) # => Decimal('1.23')
decimal.Decimal('-1.23').copy_sign(decimal.Decimal('-0.1')) # => Decimal('-1.23')

exp() 指定した数でのeのべき乗

decimal.Decimal(1).exp() # => Decimal('2.718281828459045235360287471')
decimal.Decimal(2).exp() # => Decimal('7.389056098930650227230427461')

from_float(f) 浮動小数点を正確に小数点で表示

decimal.Decimal.from_float(0.1) # => Decimal('0.1000000000000000055511151231257827021181583404541015625')
decimal.Decimal.from_float(0.25) # => Decimal('0.25')
decimal.Decimal.from_float(float('nan')) # => Decimal('NaN')
decimal.Decimal.from_float(float('inf')) # => Decimal('Infinity')
decimal.Decimal.from_float(float('-inf')) # => Decimal('-Infinity')

fma(other, third, context=None) 融合積和(fused multiply-add)

decimal.Decimal(3).fma(decimal.Decimal(7), decimal.Decimal(11))
# => Decimal('32')  3*7+11

is_finite() 有限値判定

decimal.Decimal('1').is_finite() # => True
decimal.Decimal('NaN').is_finite() # => False
decimal.Decimal('Infinity').is_finite() # => False

is_infinite() 無限判定

decimal.Decimal('1').is_infinite() # => False
decimal.Decimal('NaN').is_infinite() # => False
decimal.Decimal('Infinity').is_infinite() # => True

is_nan() NaN判定

decimal.Decimal('1').is_nan() # => False
decimal.Decimal('NaN').is_nan() # => True
decimal.Decimal('sNaN').is_nan() # => True
decimal.Decimal('Infinity').is_nan() # => False

is_normal(context=None) 正規(normal) の有限数値判定

decimal.Decimal('1').is_normal() # => True
decimal.Decimal('NaN').is_normal() # => False
decimal.Decimal('sNaN').is_normal() # => False
decimal.Decimal('Infinity').is_normal() # => False
decimal.Decimal(('0.1E-999999')).is_normal() # => False

is_qnan() 無言NaN判定

decimal.Decimal('1').is_qnan() # => False
decimal.Decimal('NaN').is_qnan() # => True
decimal.Decimal('sNaN').is_qnan() # => False
decimal.Decimal('Infinity').is_qnan() # => False

is_signed() 負号判定

decimal.Decimal('1').is_signed() # => False
decimal.Decimal('NaN').is_signed() # => False
decimal.Decimal('sNaN').is_signed() # => False
decimal.Decimal('Infinity').is_signed() # => False
decimal.Decimal('-1').is_signed() # => True
decimal.Decimal('-NaN').is_signed() # => True
decimal.Decimal('-sNaN').is_signed() # => True
decimal.Decimal('-Infinity').is_signed() # => True

is_snan() 発信Nan判定

decimal.Decimal('1').is_snan() # => False
decimal.Decimal('NaN').is_snan() # => False
decimal.Decimal('sNaN').is_snan() # => True
decimal.Decimal('Infinity').is_snan() # => False

is_subnormal(context=None) 非正規判定

decimal.Decimal('1').is_subnormal() # => False
decimal.Decimal('NaN').is_subnormal() # => False
decimal.Decimal('sNaN').is_subnormal() # => False
decimal.Decimal('Infinity').is_subnormal() # => False
decimal.Decimal('0.1E-999999').is_subnormal() # => True

is_zero() ゼロ判定

decimal.Decimal('0').is_zero() # => True
decimal.Decimal('+0').is_zero() # => True
decimal.Decimal('-0').is_zero() # => True
decimal.Decimal('1').is_zero() # => False
decimal.Decimal('NaN').is_zero() # => False
decimal.Decimal('sNaN').is_zero() # => False
decimal.Decimal('Infinity').is_zero() # => False

ln(context=None) 自然対数

decimal.Decimal('2.718281828').ln() # => Decimal('0.9999999998311266953289851341')

log10(context=None) 常用対数

decimal.Decimal('2').log10() # => Decimal('0.3010299956639811952137388947')
decimal.Decimal('100').log10() # => Decimal('2')
decimal.Decimal('Infinity').log10() # => Decimal('Infinity')

logb(context=None) 指数

decimal.Decimal('2').logb() # => Decimal('0')
decimal.Decimal('100').logb() # => Decimal('2')
decimal.Decimal('Infinity').logb() # => Decimal('Infinity')

logical_and(other, context=None) 論理積

decimal.Decimal('1100').logical_and(decimal.Decimal('1010')) # => Decimal('1000')

logical_invert(context=None) 論理反転

decimal.Decimal('1010').logical_invert() # => Decimal('1111111111111111111111110101')

logical_or(other, context=None) 論理和

decimal.Decimal('1100').logical_or(decimal.Decimal('1010')) # => Decimal('1110')

logical_xor(other, context=None) 排他的論理和

decimal.Decimal('1100').logical_xor(decimal.Decimal('1010')) # => Decimal('110')

max(other, context=None) 大きい方

decimal.Decimal('123.4').max(decimal.Decimal('123.5')) # => Decimal('123.5')

max_mag(other, context=None) 絶対値の大きい方

decimal.Decimal('123.4').max_mag(decimal.Decimal('-123.5')) # => Decimal('-123.5')

min(other, context=None) 小さい方

decimal.Decimal('123.4').min(decimal.Decimal('123.5')) # => Decimal('123.4')

min_mag(other, context=None) 絶対値の小さい方

decimal.Decimal('123.4').min_mag(decimal.Decimal('-123.5')) # => Decimal('123.4')

next_minus(context=None) 対象より小さい最大の数

decimal.Decimal('123.4').next_minus() # => Decimal('123.3999999999999999999999999')

next_plus(context=None) 対象より大きい最小の数

decimal.Decimal('123.4').next_plus() # => Decimal('123.4000000000000000000000001')

next_toward(other, context=None) 対象の数に近づく元の数に最も近い数

decimal.Decimal('123.4').next_toward(decimal.Decimal('123.5')) # => Decimal('123.4000000000000000000000001')
decimal.Decimal('123.4').next_toward(decimal.Decimal('123.3')) # => Decimal('123.3999999999999999999999999')

normalize(context=None) 正規化

decimal.Decimal('0').normalize() # => Decimal('0')
decimal.Decimal('123.4').normalize() # => Decimal('123.4')
decimal.Decimal('123.400').normalize() # => Decimal('123.4')
decimal.Decimal('1.234e2').normalize() # => Decimal('123.4')

number_class(context=None) 数のクラスを表す文字列

decimal.Decimal('0').number_class() # => '+Zero'
decimal.Decimal('+0').number_class() # => '+Zero'
decimal.Decimal('-0').number_class() # => '-Zero'
decimal.Decimal('Infinity').number_class() # => '+Infinity'
decimal.Decimal('-Infinity').number_class() # => '-Infinity'
decimal.Decimal('1.2345').number_class() # => '+Normal'
decimal.Decimal('-1.2345').number_class() # => '-Normal'
decimal.Decimal('0.1E-999999').number_class() # => '+Subnormal'
decimal.Decimal('-0.1E-999999').number_class() # => '-Subnormal'
decimal.Decimal('NaN').number_class() # => 'NaN'
decimal.Decimal('sNaN').number_class() # => 'sNaN'

quantize(exp, rounding=None, context=None) 対象数字と同じように丸める

decimal.Decimal('1.23456789').quantize(decimal.Decimal('1.000')) # => Decimal('1.235')

remainder_near(other, context=None) 剰余(絶対値を小さくする、同じなら偶数を採用)

decimal.Decimal('14').remainder_near(decimal.Decimal('3')) # => Decimal('-1') 14-5*3 = -1
decimal.Decimal('13').remainder_near(decimal.Decimal('3')) # => Decimal('1')  13-4*3 =  1
decimal.Decimal('13').remainder_near(decimal.Decimal('2')) # => Decimal('1')  13-6*2 =  1
decimal.Decimal('15').remainder_near(decimal.Decimal('2')) # => Decimal('-1') 15-8*2 = -1

rotate(other, context=None) 数字の巡回

decimal.Decimal('10101').rotate(decimal.Decimal('0')) # => Decimal('10101')
decimal.Decimal('10101').rotate(decimal.Decimal('1')) # => Decimal('101010')
decimal.Decimal('10101').rotate(decimal.Decimal('2')) # => Decimal('1010100')
decimal.Decimal('10101').rotate(decimal.Decimal('-1')) # => Decimal('1000000000000000000000001010')

same_quantum(other, context=None) 指数比較(または両方NaN)

decimal.Decimal('1.234e2').same_quantum(decimal.Decimal('567')) # => False
decimal.Decimal('1.23e2').same_quantum(decimal.Decimal('5.67e2')) # => True
decimal.Decimal('1.234e2').same_quantum(decimal.Decimal('567.8')) # => True
decimal.Decimal('NaN').same_quantum(decimal.Decimal('567.8')) # => False
decimal.Decimal('NaN').same_quantum(decimal.Decimal('NaN')) # => True

scaleb(other, context=None) 指数の調整

decimal.Decimal('1.23e2').scaleb(decimal.Decimal('10')) # => Decimal('1.23E+12')
decimal.Decimal('1.23e2').scaleb(decimal.Decimal('1')) # => Decimal('1.23E+3')
decimal.Decimal('1.23e2').scaleb(decimal.Decimal('0')) # => Decimal('123')
decimal.Decimal('1.23e2').scaleb(decimal.Decimal('-1')) # => Decimal('12.3')

shift(other, context=None) シフト

decimal.Decimal('1.23e2').shift(decimal.Decimal('10')) # => Decimal('1230000000000')
decimal.Decimal('1.23e2').shift(decimal.Decimal('1')) # => Decimal('1230')
decimal.Decimal('1.23e2').shift(decimal.Decimal('0')) # => Decimal('123')
decimal.Decimal('1.23e2').shift(decimal.Decimal('-1')) # => Decimal('12')

sqrt(context=None) 平方根

decimal.Decimal('25').sqrt() # => Decimal('5')
decimal.Decimal('2').sqrt() # => Decimal('1.414213562373095048801688724')

to_eng_string(context=None) 工学表記

decimal.Decimal('123456789123.456789').to_eng_string() # => '123456789123.456789'
decimal.Decimal('1.23456789123456789e11').to_eng_string() # => '123456789123.456789'
decimal.Decimal('123e1').to_eng_string() # => '1.23E+3'
decimal.Decimal('12.3e1').to_eng_string() # => '123'
decimal.Decimal('1.23e1').to_eng_string() # => '12.3'

to_integral(rounding=None, context=None) 整数丸め(to_integral_valueと同じ)

decimal.Decimal('123456789123.456789').to_integral() # => Decimal('123456789123')

to_integral_exact(rounding=None, context=None) 整数丸め(シグナルあり)

decimal.Decimal('123456789123.456789').to_integral_exact() # => Decimal('123456789123')

to_integral_value(rounding=None, context=None) 整数丸め

decimal.Decimal('123456789123.456789').to_integral_value() # => Decimal('123456789123')

Context オブジェクト 環境設定

decimalの計算では、コンテキストというオブジェクトに保存されている有効桁数などの環境情報が参照されている。
Contextを変更することで有効桁数等の指定を変更できる。

また、計算時に丸めや有効精度落ちなどが発生した場合「フラグ(flags)」に設定がされるようになっている。

「トラップ(traps)」という属性もあり、こちらはシグナル発生時にエラーとするかの設定に使う。
(例えば、trapsDivisionByZeroのトラップを有効にすると0除算でエラーとなり、
トラップを無効にするとエラーとならずDecimal('Infinity')やDecimal('-Infinity')が返却される)

コンストラクタ

# decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)
# prec 算術演算の計算精度
# rounding 丸めモード
# traps 捕まえたいシグナル
# flags コンテキストで送出されたシグナル
# Emin 指数の下限
# Emax 指数の上限
# capitals 指数表記の大文字小文字 0(デフォルト):大文字E 0:小文字e
# clamp 指数範囲の設定
decimal.Context()
decimal.Context(prec=10)

用意されている作成済みのContext

## デバッグ用
## 精度9桁、丸め規則ROUND_HALF_UP、エラートラップはInexact, Rounded, Subnormal以外有効
decimal.BasicContext
# => Context(prec=9, rounding=ROUND_HALF_UP, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[Clamped, InvalidOperation, DivisionByZero, Overflow, Underflow])

## エラー送出なし停止させたくないプログラム用
## 精度9桁、丸め規則ROUND_HALF_EVEN、エラートラップは全て無効
decimal.ExtendedContext
# => Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[])

## 多重スレッド環境用
## 精度28桁、丸め規則ROUND_HALF_EVEN、エエラートラップはOverflow, InvalidOperation, DivisionByZeroが有効
## decimal.Contextコンストラクタ仕様時の雛形
decimal.DefaultContext
# => Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])

decimal.Contextのメソッド

getcontext() コンテキストの取得

context = decimal.getcontext()

setcontext(c) コンテキストの設定

context = decimal.Context()
decimal.setcontext(context)

localcontext(ctx=None) with文内でのみ有効なコンテキストの作成

print(decimal.getcontext().prec) # => 28
with decimal.localcontext() as ctx:
    ctx.prec = 30
    print(ctx.prec) # => 30
    print(decimal.getcontext().prec) # => 30

print(decimal.getcontext().prec) # => 28

decimal.Contextのメソッド使用例

# copy() コンテキストの複製
context = decimal.ExtendedContext.copy()
context
# => Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[])

# コンテキスト設定
decimal.setcontext(context)

# 0除算のフラグ確認
context.flags[decimal.DivisionByZero] # => False

# create_decimal_from_float(f)  浮動小数点数fからDecimalインスタンス生成
decimal_zero = decimal.Decimal('0')

# DivisionByZero発生のため指数計算
decimal_zero.logb() # => Decimal('-Infinity')

# 0除算のフラグ確認
context.flags[decimal.DivisionByZero] # => True

# clear_flags() フラグを全て0にリセット
context.clear_flags()

# 0除算のフラグ確認
context.flags[decimal.DivisionByZero] # => False

# トラップ追加
context.traps[decimal.DivisionByZero]= True

## コンテキスト確認
context
# => Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[])

# DivisionByZero発生のため指数計算
try:
    decimal_zero.logb() # => DivisionByZero エラー発生
except Exception as e:
    print(e)

## コンテキスト確認
context
# => Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[DivisionByZero], traps=[DivisionByZero])

# clear_traps() トラップを全て 0 にリセット
context.clear_traps()

# clear_flags() フラグを全て0にリセット
context.clear_flags()

# DivisionByZero発生のため指数計算
try:
    decimal_zero.logb() # => Decimal('-Infinity') エラーなし
except Exception as e:
    print(e)

## コンテキスト確認
context
# => Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[DivisionByZero], traps=[])

create_decimal、copy_decimalのContextによる挙動の違い例

decimal.Contxtのメソッドcreate_decimal、copy_decimalは
コンテキストの環境情報に応じたDecimal値を返却する。

context = decimal.ExtendedContext.copy()
context
# => Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[])

# コンテキスト設定
decimal.setcontext(context)
# create_decimal(num) コンテキスト使用してDecimalインスタンス生成
d1 = context.create_decimal(123.45)
d1 #= > Decimal('123.4500000000000028421709430')

# copy_decimal(num) Decimalインスタンスnumコピー
d2 = context.copy_decimal(d1)
d2 # => Decimal('123.450000')
context = decimal.Context(prec=10)
context
# => Context(prec=10, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])

# コンテキスト設定
decimal.setcontext(context)
# create_decimal(num) コンテキスト使用してDecimalインスタンス生成
d1 = context.create_decimal(123.45)
d1 #= > Decimal('123.4500000')

# copy_decimal(num) Decimalインスタンスnumコピー
d2 = context.copy_decimal(d1)
d2 # => Decimal('123.4500000')

コンテキストのフラグ・トラップで指定できる内容

フラグやトラップに指定できるエラー条件は以下の通り。

  • decimal.Clamped 指数部変更
  • decimal.DecimalException 他シグナルの基底
  • decimal.DivisionByZero 0除算 トラップしない場合Infinityか-Infinityを返却
  • decimal.Inexact 丸め精度落ち
  • decimal.InvalidOperation 無効な演算
  • decimal.Overflow 数値オーバーフロー
  • decimal.Rounded 丸め有効桁数減少
  • decimal.Subnormal 指数が小さい
  • decimal.Underflow 丸め0数値アンダーフロー
  • decimal.FloatOperation floatとDecimalの混合

丸めモード

コンテキストのroundingに設定できる丸めの種類は次の通り。

  • decimal.ROUND_CEILING Infinityにまるめ
  • decimal.ROUND_DOWN ゼロに丸め
  • decimal.ROUND_FLOOR -Infinityにまるめ
  • decimal.ROUND_HALF_DOWN 近い方にまるめ(中央はゼロにまるめ)
  • decimal.ROUND_HALF_EVEN 近い方にまるめ(中央は偶数にまるめ)
  • decimal.ROUND_HALF_UP 近い方にまるめ(中央はゼロから遠くにまるめ)
  • decimal.ROUND_UP ゼロから遠い方向に丸め
  • decimal.ROUND_05UP ゼロに丸め、末尾の桁が0・5ならばゼロから遠くに、そうでなければゼロにまるめ

decimal.Contextにあるdecimalと同様のメソッド

各種計算を行うDecimalのメソッドとほぼ同様のものがContextにも定義されている。
計算はコンテキストの有効桁数やフラグ設定を参照して行われる。

  • abs(x) 絶対値
  • add(x, y) 和
  • canonical(x) 同じDecimalオブジェクト
  • compare(x, y) 比較
  • compare_signal(x, y) 比較(シグナルあり)
  • compare_total(x, y) 比較(表現)
  • compare_total_mag(x, y) 比較(表現、負号無視)
  • copy_abs(x) 絶対値
  • copy_negate(x) 反転
  • copy_sign(x, y) 負号コピー
  • divide(x, y) 除算
  • divide_int(x, y) 除算(整数切り捨て)
  • divmod(x, y) 除算(整数部)
  • exp(x) e ** x
  • fma(x, y, z) x*y + z
  • is_canonical(x) 標準的(canonical)判定
  • is_finite(x) 有限判定
  • is_infinite(x) 無限判定
  • is_nan(x) NaN判定
  • is_normal(x) 通常の数字判定
  • is_qnan(x) 無言NaN判定
  • is_signed(x) 負判定
  • is_snan(x) 発信NaN判定
  • is_subnormal(x) 非正規数判定
  • is_zero(x) ゼロ判定
  • ln(x) 自然対数
  • log10(x) 常用対数
  • logb(x) 指数の大きさ
  • logical_and(x, y) 桁論理積
  • logical_invert(x) 桁反転
  • logical_or(x, y) 桁論理和
  • logical_xor(x, y) 桁排他的論理和
  • max(x, y) 大きい方
  • max_mag(x, y) 絶対値大きい方
  • min(x, y) 小さい方
  • min_mag(x, y) 絶対値小さい方
  • minus(x) ひく
  • multiply(x, y) 積
  • next_minus(x) 小さい最大の数
  • next_plus(x) 大きい最小の数
  • next_toward(x, y) yの方向に向かって最もxに近い数
  • normalize(x) x 正規化
  • number_class(x) 数字のクラス
  • plus(x) たす
  • power(x, y, modulo=None) x**y
  • quantize(x, y) xを丸めてyに表現をそろえる
  • remainder(x, y) 整数除算の剰余
  • remainder_near(x, y) 剰余
  • rotate(x, y) 巡回
  • same_quantum(x, y) 指数の比較
  • scaleb(x, y) 指数の加算
  • shift(x, y) シフト
  • sqrt(x) 平方根
  • subtract(x, y) 差
  • to_eng_string(x) 工学表記
  • to_integral_exact(x) 整数表記
  • to_sci_string(x) 科学表記
Originally published at marusankakusikaku.jp
ツイッターでシェア
みんなに共有、忘れないようにメモ

maru3kaku4kaku

Pythonこつこつ学習中。よく忘れる。

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント