分数(有理数)の計算

分数(有理数)の計算

有理数型

 除算演算子で割り算をすると誤差が生じることがあるので、データを 分数の形に保存したままで計算したい 場面があります。Python で分数計算を行なうためには、fractionsモジュールの Fractionクラス (有理数型) を呼び出します。

Fractionクラス

 fractions.Fraction(a, b) を使って、有理数 (Fraction クラスのオブジェクト) を生成できます。引数に 2 つの整数値を与えると、第 1 引数を分子、第 2 引数を分母とした有理数型データが定義されます。分母を省略すると 1 とみなされます。

# FRACTION_01-1

# Fraction クラスをインポート
from fractions import Fraction

# Fractionインスタンスを生成
a = Fraction(1,3)

print(a)
1/3

 引数に浮動小数点数 (float) を渡して有理数 (Fraction) に変換することもできます。

# FRACTION_01-2

# 0.125 を分数に変換
a = Fraction(0.125)

print(a)
1/8

 

分母と分子の取得

 Fractionクラスの属性 Fraction.numerator もしくは Fraction.denominator から、分子と分母の値を取得することができます。

# FRACTION_01-3

x = Fraction(19,33)

# 分子を取得
a = x.numerator

# 分母を取得
b = x.denominator

print(a, b)
19 33

 

分数同士の加減乗除

 分数同士の加減乗除を試してみます。

# FRACTION_01-4

# 1/2+1/3
a = Fraction(1,2) + Fraction(1,3)

# 1/2-1/3
b = Fraction(1,2)-Fraction(1,3)

# (1/2)×(1/3)
c = Fraction(1,2)*Fraction(1,3)

# (1/2)÷(1/3)
d = Fraction(1,2)/Fraction(1,3)

print(a, b, c, d)
5/6 1/6 1/6 3/2

 

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

新品価格
¥2,592から
(2019/8/6 17:55時点)

小数の近似分数

 Fractionクラスの limit_denominatorメソッドを使うと、指定した引数に最も近い分母をもつ近似分数を得ることができます。

 mathモジュールから円周率の値をインポートして、その近似分数を求めてみます。

# FRACTION_02-1

# 円周率の値をインポート
from math import pi

# 有理数クラスをインポート
from fractions import Fraction

# 円周率の値を分数に変換
x = Fraction(pi)

# 円周率の近似分数を取得
f_pi = x.limit_denominator(1000)

print(f_pi)
355/113

 ちなみに、この近似分数のことを「密率」とよびます。大昔の中国人が発見したそうです。
 密率は小数点以下 6 桁まで一致する精度がありますが、もう少し手軽に計算に使える「約率」も求めておきましょう。

# FRACTION_02-2

# 円周率の値を分数に変換
x = Fraction(pi)

# 円周率の近似分数を取得
f_pi = x.limit_denominator(10)

print(f_pi)
22/7

 

級数の計算

 分数計算の応用です。次のような級数

  1 + 1/2 + 1/3 + 1/4 + 1/5 + 1/6 + ......

を 20 項まで計算してみます。

# FRACTION_03

from fractions import Fraction

x = 0
m = 0

for ct in range(20):
    m += 1
    x += Fraction(1, m)

print(x)
55835135/15519504

 このサンプルコードでは、m の値を 1 つずつ増やしながら Fraction を作り、それを次々と足し合わせています。
 

SymPy 有理数演算

Rationalクラス

 SymPy をインポートすると、コンストラクタ sympy.Rational() を使って、有理数 (sympy.core.numbers.Rational クラスのオブジェクト) を扱えるようになります。

 sympy.Rational(p, q=None, gcd=None)

 p, q に整数を渡すと、p を分子、q を分母とする分数が生成されます。

# FRACTION_04-1

# SymPyをインポート
from sympy import *

# 有理数オブジェクトを生成
x = Rational(1, 3)
y = Rational(1, 5)

print(x + y)
8/15

 p に浮動小数点数を渡すと分数に変換されます。
 しかし、たとえば p=0.2 を指定しても、期待している値 (1/5) は得られません。

# FRACTION_04-2

# 浮動小数点数0.2を分数に変換
x = Rational(.2)

print(x)
3602879701896397/18014398509481984

 これは浮動小数点数 0.2 を有限桁の 2 進数で表せないことに起因しています。
 渡した値が「0.2 の近似値」ではなく、「正確な 0.2」であることを明示するときには文字列型の ".2" を渡します。

# FRACTION_04-3

# 浮動小数点数0.2を分数表式に変換
x = Rational(".2")

print(x)
1/5

分数のタプル表記

 SymPy の fraction()関数は受け取った式を (分子, 分母) のタプルで返します。

# FRACTION_05-1

from sympy import *

# a,b,c,dを記号として定義
var ("a:d")

# 分数をタプルに変換
x = fraction((a+b)/c)

print(x)
(a + b, c)

 Rational をタプルに変換することもできます。

# FRACTION_05-2

# 有理数を生成
x = Rational(5, 11)

# 有理数をタプルに変換
y = fraction(x)

print(y)
(5, 11)

 指数関数の指数部分にマイナス符号がついていれば、指数関数を分母にします。

# FRACTION_05-3

# exp(-a)をタプルに変換
x = fraction(exp(-a))

print(x)
(1, exp(a))

 SymPy の有理数演算に関しては以下の記事も参考にしてください。