fractionsモジュールを使うと、rational numbers、つまり整数の分子を整数の分母で割った分数を作成して扱うことができます。
たとえば、2/3を、おおよその値であるfloatの0.6666...ではなく、正確な分数として保存できます。
int、float、complexのような数値型とは違い、分数にはリテラル表現がありません。
ただし、分数のコンストラクターはとても柔軟です。
もっとも基本的なのは、2つの整数を渡す方法です。 共通因数は自動的に取り除かれ、分数は「最小形」(その分数を正確に表す最小の整数)に変換されます。
>>> from fractions import Fraction
>>> f1 = Fraction(2, 3) # 2/3
>>> f1
Fraction(2, 3)
>>> f2 = Fraction(6, 9)
>>> f2
Fraction(2, 3) # automatically simplified
>>> f1 == f2
True
分数のコンストラクターは、文字列として表された値も解析できます。
>>> f3 = Fraction('2/3')
>>> f3
Fraction(2, 3)
floatの引数を使うこともできますが、小数の値を内部的に2進数で表すという近似の性質から、問題が起きることがあります。
この表現の問題について詳しくは、0.30000000000000004のウェブサイトと、PythonのドキュメントにあるFloating Point Arithmetic: Issues and Limitations を参照してください。
分数とfloatを組み合わせるときに、より信頼できる結果が必要なら、<fraction>.limit_denominator()メソッドがあります。
.limit_denominator()は、特定の要件がある場合は整数の引数を指定できますが、デフォルト値(max_denominator=1000000)でも十分に機能し、許容できる単純な近似値を得られます。
>>> Fraction(1.2)
Fraction(5404319552844595, 4503599627370496)
>>> Fraction(1.2).limit_denominator()
Fraction(6, 5)
通常のarithmetic operatorsである+ - * / **は、他の数値型と同じように、分数でも使えます。
整数や他のFractionを含めることもでき、その結果はFractionになります。
式にfloatを含めると、出力はfloatになり、その結果として精度が失われる可能性があります。
>>> Fraction(2, 3) + Fraction(1, 4) # addition
Fraction(11, 12)
>>> Fraction(2, 3) * Fraction(6, 5) # multiply fractions
Fraction(4, 5)
>>> Fraction(2, 3) * 6 / 5 # fraction with integers
Fraction(4, 5)
>>> Fraction(2, 3) * 1.2 # fraction with float -> float
0.7999999999999999
>>> Fraction(2, 3) ** 2 # exponentiation with integer
Fraction(4, 9)
分数は、途中の計算で精度を保つのに最適ですが、最終的な出力としてはそのまま使いたくないこともあるでしょう。
分子と分母は、それぞれ個別に、あるいはタプルとして取得できます(tuplesについては、後のコンセプトで説明します)。
>>> Fraction(2, 3).numerator
2
>>> Fraction(2, 3).denominator
3
>>> Fraction(2, 3).as_integer_ratio()
(2, 3)
Pythonの標準的な数値関数の多くも、int型やfloat型を扱うときと同じような結果を返します。
>>> round(Fraction(11, 3))
4
>>> from math import floor, ceil
>>> floor(Fraction(11, 3))
3
>>> ceil(Fraction(11, 3))
4
>>> float(Fraction(11, 3))
3.6666666666666665