Pythonのdecimalモジュール徹底解説!sqrt・exp・log・compareなど主要関数の使い方
Pythonには、10進浮動小数点数(decimal floating point)を扱うためのdecimalモジュールが標準ライブラリとして用意されています。このモジュールを使うと、正しく丸められた高精度な浮動小数点演算が可能になります。
通常のfloat型は内部で2進数によって数値を表現するため、「0.1 + 0.2」が厳密には0.3にならないといった誤差が発生します。decimalモジュールは、金額計算など厳密な精度が求められる場面で特に役立ちます。
利用するには、まずdecimalモジュールをインポートします。
import decimal
本記事では、decimalモジュールで使える重要な関数を順番に見ていきましょう。
平方根を求めるsqrt()と指数を求めるexp()
sqrt()メソッドは、Decimal型オブジェクトの平方根を計算します。exp()メソッドは、与えられた値xに対してexの値をDecimal型として返します。
サンプルコード
# sqrt() と exp() メソッドの実行例
import decimal
my_dec = decimal.Decimal(25.36)
print(my_dec)
# 10進数の平方根を求める
print('Square Root is: ' + str(my_dec.sqrt()))
# e^x を求める
print('e^x is: ' + str(my_dec.exp()))
実行結果
25.3599999999999994315658113919198513031005859375 Square Root is: 5.035871324805668565859161094 e^x is: 103206740212.7314661465187086
実行結果を見ると、「25.36」と入力したはずの値が非常に長い小数に展開されていることに気づくでしょう。これはfloat値からDecimalを生成した際、float側の誤差まで引き継いでしまうためです。意図した通りの値を扱いたい場合は、文字列で渡すことが推奨されます。
my_dec = decimal.Decimal('25.36') # 文字列で指定すれば余計な誤差が出ない
対数を求めるln()とlog10()
decimalモジュールには複数の対数関数が用意されており、ここではそのうちの2つを紹介します。
- ln():自然対数(底がe)の値を求める
- log10():底が10の対数の値を求める
サンプルコード
# ln() と log10() メソッドの実行例
import decimal
my_dec = decimal.Decimal(25.36)
print(my_dec)
# 底eの対数値を求める
print('ln(x) is: ' + str(my_dec.ln()))
# 底10の対数値を求める
print('log(x) is: ' + str(my_dec.log10()))
実行結果
25.3599999999999994315658113919198513031005859375 ln(x) is: 3.233173129569025152000878282 log(x) is: 1.404149249209695070459909761
as_tuple()とfma()メソッド
as_tuple()メソッドは、10進数を3つの要素を持つタプル形式で表現します。要素はsign(符号)、digits(各桁の数字)、exponent(指数)です。signが0の場合は正の数、1の場合は負の数を意味します。
fma()メソッドはfusioned multiplication and add(融合積和演算)と呼ばれるもので、fma(x, y)と呼び出すと (number * x) + y を計算します。このとき中間結果の (number * x) の部分は丸められないため、より高精度な計算が可能です。
サンプルコード
# as_tuple() と fma() メソッドの実行例
import decimal
my_dec1 = decimal.Decimal(5.3)
print(my_dec1)
my_dec2 = decimal.Decimal(-9.23)
print(my_dec2)
# 10進数をタプルとして表示
print('\nmy_dec1 as tuple: ' + str(my_dec1.as_tuple()))
print('\nmy_dec2 as tuple: ' + str(my_dec2.as_tuple()))
# 融合積和演算を実行
print('\n(x*5)+8 is: ' + str(my_dec1.fma(5, 8)))
実行結果
5.29999999999999982236431605997495353221893310546875 -9.230000000000000426325641456060111522674560546875 my_dec1 as tuple: DecimalTuple(sign=0, digits=(5, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 2, 2, 3, 6, 4, 3, 1, 6, 0, 5, 9, 9, 7, 4, 9, 5, 3, 5, 3, 2, 2, 1, 8, 9, 3, 3, 1, 0, 5, 4, 6, 8, 7, 5), exponent=-50) my_dec2 as tuple: DecimalTuple(sign=1, digits=(9, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 6, 3, 2, 5, 6, 4, 1, 4, 5, 6, 0, 6, 0, 1, 1, 1, 5, 2, 2, 6, 7, 4, 5, 6, 0, 5, 4, 6, 8, 7, 5), exponent=-48) (x*5)+8 is: 34.49999999999999911182158030
compare()メソッド
compare()メソッドは、2つの10進数を比較するためのものです。両者が等しい場合は0を返し、最初の数が大きい場合は+1、最初の引数が小さい場合は-1を返します。
サンプルコード
# compare() メソッドの実行例
import decimal
# 両者が等しい場合の比較
print('Compare value: ' + str(decimal.Decimal(-5.3).compare(decimal.Decimal(-5.3))))
# 最初の数が小さい場合の比較
print('Compare value: ' + str(decimal.Decimal(-5.3).compare(decimal.Decimal(9.26))))
# 最初の数が大きい場合の比較
print('Compare value: ' + str(decimal.Decimal(-5.3).compare(decimal.Decimal(-13.25))))
実行結果
Compare value: 0 Compare value: -1 Compare value: 1
コピー系の関数
decimalオブジェクトを別のオブジェクトへコピーするためのメソッドもいくつか用意されています。
- copy_abs():10進数の絶対値を取得する
- copy_negate():元の数の符号を反転してコピーする
- copy_sign():第2引数から符号を取り出し、第1引数の値に適用して返す
サンプルコード
# copy_abs() / copy_negate() / copy_sign() の実行例
import decimal
my_dec = decimal.Decimal(-25.36)
print(my_dec)
# 絶対値をコピー
temp_dec = my_dec.copy_abs()
print('Absolute is: ' + str(temp_dec))
# 符号を反転してコピー
my_dec = decimal.Decimal(7.26)
temp_dec = my_dec.copy_negate()
print('Negate of 7.26 is: ' + str(temp_dec))
# 第2引数の符号を第1引数に適用
my_dec = decimal.Decimal(-25.36)
temp_dec = my_dec.copy_sign(decimal.Decimal(12.5))
print('Copy sign from second argument: ' + str(temp_dec))
実行結果
-25.3599999999999994315658113919198513031005859375 Absolute is: 25.3599999999999994315658113919198513031005859375 Negate of 7.26 is: -7.2599999999999997868371792719699442386627197265625 Copy sign from second argument: 25.3599999999999994315658113919198513031005859375
max()とmin()メソッド
max()とmin()は非常にシンプルなメソッドで、それぞれ2つの数のうち大きい方・小さい方を返します。
サンプルコード
# max() と min() メソッドの実行例
import decimal
my_dec1 = decimal.Decimal(5.3)
print(my_dec1)
my_dec2 = decimal.Decimal(-9.23)
print(my_dec2)
# 最小値と最大値を表示
print('Minimum: ' + str(my_dec1.min(my_dec2)))
print('Maximum: ' + str(my_dec2.max(my_dec1)))
実行結果
5.29999999999999982236431605997495353221893310546875 -9.230000000000000426325641456060111522674560546875 Minimum: -9.230000000000000426325641456 Maximum: 5.299999999999999822364316060
まとめ
decimalモジュールを使えば、float型では避けられない2進数由来の誤差を抑え、高精度な10進演算を実現できます。平方根や対数などの数学関数から、比較・コピー・最大最小の取得といった操作まで、豊富なメソッドが揃っています。金額計算や誤差が許容できない処理では、ぜひ活用してみてください。なお、float値からDecimalを生成すると誤差が混入するため、実務では文字列からの生成を心がけるとよいでしょう。
-
Pythonのstatisticsモジュール徹底解説!mean・median・modeなど統計関数の使い方
Pythonでは、statisticsモジュールをインポートするだけで、数式や統計データの処理を手軽に行うことができます。平均値・中央値・最頻値など、さまざまな種類の統計演算や数学的操作を簡単に実装できるのが魅力です。 以下の関数は、標本または母集団のデータから代表値(平均的な値)を算出するために使用されます。 mean()データの算術平均(平均値)を返します。 harmonic_mean()データの調和平均を返します。 median()データの中央値(中間値)を返します。 median_low()データの低い側の中央値を返します。 median_high()データの高い側の中央値を返しま
-
Pythonの無名関数(ラムダ式)とは?基本構文と実用的な使い方をわかりやすく解説
Pythonにおける無名関数とは Pythonにおける無名関数(匿名関数)とは、その名のとおり「関数名を持たない関数」のことです。通常の関数は def キーワードを使って定義しますが、無名関数は lambda キーワードを使って定義します。このため、無名関数は「ラムダ関数」あるいは「ラムダ式」とも呼ばれています。 ラムダ式の基本的な構文 ラムダ式は次のような形式で記述します。 lambda 引数: 式 引数を受け取り、コロン(:)以降の式の評価結果を自動的に返り値として返します。return 文を書く必要がない点が特徴です。 # 通常の関数定義 def square(x): ret