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

119

我在思考如何在Python中将一个十进制数转换为最简分数。

例如:

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

将0.25转换为25/100,然后找出最大公因数是多少? - Lev Levitsky
6个回答

204

你有两个选择:

  1. 使用 float.as_integer_ratio() 方法:

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

    自Python 3.6起,您可以使用decimal.Decimal()对象执行相同的操作。

  2. 使用fractions.Fraction()类型

  3. >>> 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() 类方法:

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' object cannot be interpreted as an index”。你能告诉我为什么吗? - user2370460
1
@user2370460:你使用的是哪个版本的Python? - Martijn Pieters
5
是的,只有2.7及以上版本支持传递浮点或十进制类型;在这种情况下,请改用Fraction(*(0.25).as_integer_ratio()) - Martijn Pieters
1
请注意,fractions模块和float.as_integer_ratio是在Python 2.6中添加的。如果您正在运行旧版本的Python,则这些功能将不可用。 - IceArdor
3
我错过了可用的Fraction.from_float()类方法,这个方法更加清晰。Fraction.from_float(0.25)可以将0.25转换为分数。 - Martijn Pieters
显示剩余4条评论

15
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' object cannot be interpreted as an index"。你能告诉我为什么吗? - user2370460
2
好的建议,但我想补充一点:单参数构造函数对于某些数字效果很好,但对于其他数字则不然。例如,Fraction(.2) 变成了 Fraction(3602879701896397, 18014398509481984)。最好使用双参数构造函数,例如 Fraction(2,10) - Kevin
3
@Kevin: 这是因为浮点数无法准确表示0.2。请参考我的答案,有一个解决方法:限制分母,就可以轻松将其还原为2/10。 - Martijn Pieters

12

在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实例。
>>> 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"

1

这是如何简单而正确地完成它。

通过使用分数:

from fractions import Fraction
decimals = [0.25, 0.5, 1.25, 3, 0.6, 0.84]

for d in decimals:
    print(Fraction(str(d))) #Cast as string for proper fraction

通过使用 Decimal:

from  decimal import Decimal
decimals = [0.25, 0.5, 1.25, 3, 0.6, 0.84]

for d in decimals:
    d = Decimal(str(d)) #Cast as string for proper fraction
    nominator,denominator = d.as_integer_ratio()
    if denominator==1:
        print(a)
    else:
        print(nominator,denominator, sep="/")

输出:

1/4
1/2
5/4
3
3/5
21/25

0

其中最简单的方法是使用as_integer_ratio(),像这样。

b = 0.125

b.as_integer_ratio()

# Output as Tuple(1, 8).Numerator as 1 & Denominator as 8


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接