Мне было интересно, как преобразовать десятичную дробь в дробную часть в ее младшей форме в Python.
Например:
0.25 -> 1/4
0.5 -> 1/2
1.25 -> 5/4
3 -> 3/1
Мне было интересно, как преобразовать десятичную дробь в дробную часть в ее младшей форме в Python.
Например:
0.25 -> 1/4
0.5 -> 1/2
1.25 -> 5/4
3 -> 3/1
У вас есть два варианта:
Используйте float.as_integer_ratio()
:
>>> (0.25).as_integer_ratio()
(1, 4)
(с Python 3.6 вы можете сделать то же самое с объектом decimal.Decimal()
.)
Используйте fractions.Fraction()
type:
>>> 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.
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
Чтобы расширить 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
, который может быть достигнут путем литья в строку и последующего манипулирования им.
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)