如何将十进制数转换为分数?


77

我想知道如何在Python中将小数转换为最低形式的分数。

例如:

0.25  -> 1/4
0.5   -> 1/2
1.25  -> 5/4
3     -> 3/1

将0.25转换为25/100,然后找出最大公因子?
Lev Levitsky

Answers:


136

您有两种选择:

  1. 用途float.as_integer_ratio()

    >>> (0.25).as_integer_ratio()
    (1, 4)
    

    (从Python 3.6开始,您可以decimal.Decimal()对象执行相同的操作。)

  2. 使用fractions.Fraction()类型

    >>> from fractions import Fraction
    >>> Fraction(0.25)
    Fraction(1, 4)
    

后者具有非常有用的str()转换:

>>> str(Fraction(0.25))
'1/4'
>>> print Fraction(0.25)
1/4

由于浮点值可能不精确,因此您可能会得到“奇怪”的分数;限制分母以某种程度“简化”分数,方法是Fraction.limit_denominator()

>>> Fraction(0.185)
Fraction(3332663724254167, 18014398509481984)
>>> Fraction(0.185).limit_denominator()
Fraction(37, 200)

如果您仍在使用Python 2.6,则Fraction()尚不支持float直接传递,但是您可以将上述两种技术结合使用:

Fraction(*0.25.as_integer_ratio())

或者,您可以只使用Fraction.from_float()class方法

Fraction.from_float(0.25)

本质上是做同样的事情,例如,取整数比元组并将其作为两个单独的参数传递。

以及一个带有示例值的小演示:

>>> for f in (0.25, 0.5, 1.25, 3.0):
...     print f.as_integer_ratio()
...     print repr(Fraction(f)), Fraction(f)
... 
(1, 4)
Fraction(1, 4) 1/4
(1, 2)
Fraction(1, 2) 1/2
(5, 4)
Fraction(5, 4) 5/4
(3, 1)
Fraction(3, 1) 3

无论是fractions模块和float.as_integer_ratio()方法在Python 2.6是新的。


1
谢谢!选项1有效,但是选项2(Fraction(0.25))给我错误:“ TypeError:'float'对象无法解释为索引”。你能告诉我为什么吗?
user2370460 2014年

1
@ user2370460:您正在使用哪个版本的Python?
马丁·皮特斯

5
@ user2370460:嗯,是的,仅2.7版及更高版本支持传递浮点或十进制类型;Fraction(*(0.25).as_integer_ratio())在这种情况下使用代替。
马丁·彼得

1
请注意,fractions模块和float.as_integer_ratio都是在Python 2.6中添加的。如果您运行的是旧版本的Python,则这些功能将不可用。
IceArdor 2014年

3
@ user2370460:我完全设法错过了可用的Fraction.from_float()类方法,更加清楚了。Fraction.from_float(0.25)
的Martijn Pieters的

9
from fractions import Fraction

print(Fraction(0.25))
print(Fraction(0.5))
print(Fraction(1.25))
print(Fraction(3))

#1/4
#1/2
#5/4
#3

谢谢,但这给了我:“ TypeError:'float'对象无法解释为索引”。你能告诉我为什么吗?
user2370460

1
很好的建议,但我想补充一下:一元参数的构造函数对某些数字有效,但对另一些数字则无效。例如,Fraction(.2)变为Fraction(3602879701896397, 18014398509481984)。最好使用两个参数的构造函数,例如。Fraction(2,10)
凯文(Kevin)

3
@Kevin:这是因为.2无法用浮点数精确表示。解决方法请参阅我的答案;限制分母,您可以立即将其恢复为2/10。
马丁·彼得斯

9

由于更复杂的浮子固有的不精确性,因此可以扩展Martijn Pieters的出色答案,并提供其他选项。例如:

>>> f = 0.8857097
>>> f.as_integer_ratio()
(1994440937439217, 2251799813685248)          # mathematically wrong
>>> Fraction(f)
Fraction(1994440937439217, 2251799813685248)  # same result but in a class
>>> Fraction(f).limit_denominator()
Fraction(871913, 984423)                      # still imprecise

所需的数学结果是8857097/10000000可以通过将其转换为字符串然后进行操作来实现的。

编辑回应

我找到了一种解决精度问题的简单得多的方法。

>>> Fraction(str(f))
Fraction(8857097, 10000000)

强制转换为字符串还允许精确的十进制实例

>>> Decimal(f).as_integer_ratio()
(1994440937439217, 2251799813685248)
>>> Decimal(str(f)).as_integer_ratio()
(8857097, 10000000)

原始回应

def float_to_ratio(flt):
    if int(flt) == flt:        # to prevent 3.0 -> 30/10
        return int(flt), 1
    flt_str = str(flt)
    flt_split = flt_str.split('.')
    numerator = int(''.join(flt_split))
    denominator = 10 ** len(flt_split[1])
    return numerator, denominator

现在让我们测试一下:

>>> float_to_ratio(f)
(8857097, 10000000)      # mathematically correct

我将注意到,这种分数精度并没有得到优化,通常不需要,但是出于完整性考虑。此函数不会简化分数,但是您可以执行其他处理来减小分数:

>>> n = 0.5
>>> float_to_ratio(n)
(5, 10)
>>> Fraction(*float_to_ratio(n))
Fraction(1, 2)

7

如果您想打印适当的分数,则可以使用以下小方法:

from fractions import Fraction    

def dec_to_proper_frac(dec):
    sign = "-" if dec < 0 else ""
    frac = Fraction(abs(dec))
    return (f"{sign}{frac.numerator // frac.denominator} "
            f"{frac.numerator % frac.denominator}/{frac.denominator}")

打印结果如下:

>>> dec_to_proper_frac(3.75)
>>> "3 3/4"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.