fractions模块可以让我们创建并处理rational numbers:分子是整数、分母也是整数的分数。
例如,我们可以把2/3保存为精确的分数,而不是近似的float值0.6666...。
分数和int、float、complex这些数值类型不同,它没有字面量形式。
不过,分数的构造函数相当灵活。
最明显的是,它可以接受两个整数。 公因数会被自动约去,把分数化为“最简形式”(能够准确表示该分数的最小整数):
>>> 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参数,但这可能会遇到问题:十进制值在内部以二进制表示,本身就带有近似性。
关于这个表示问题的更多内容,可以访问 0.30000000000000004 网站,以及 Python 文档中的浮点数运算:问题和局限。
用浮点数参与分数运算时,如果想得到更可靠的结果,可以使用<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