Comment convertir un nombre décimal en fraction?
Je me demandais comment convertir une décimale en une fraction dans sa forme la plus basse en Python.
Par exemple:
0.25 -> 1/4
0.5 -> 1/2
1.25 -> 5/4
3 -> 3/1
4 réponses
, Vous avez deux options:
-
Utiliser
float.as_integer_ratio()
:>>> (0.25).as_integer_ratio() (1, 4)
(depuis Python 3.6, vous pouvez faire de même avec un objet
decimal.Decimal()
.) -
Utiliser le
fractions.Fraction()
type:>>> from fractions import Fraction >>> Fraction(0.25) Fraction(1, 4)
Ce dernier a une conversion str()
très utile:
>>> str(Fraction(0.25))
'1/4'
>>> print Fraction(0.25)
1/4
Parce que les valeurs à virgule flottante peuvent être imprécises, vous pouvez vous retrouver avec des fractions "étranges"; limitez le dénominateur pour "simplifier" quelque peu la fraction, avec Fraction.limit_denominator()
:
>>> Fraction(0.185)
Fraction(3332663724254167, 18014398509481984)
>>> Fraction(0.185).limit_denominator()
Fraction(37, 200)
Si vous utilisez toujours python 2.6, alors Fraction()
ne prend pas encore en charge le passage direct d'un float
, mais vous pouvez combiner les deux techniques ci-dessus en:
Fraction(*0.25.as_integer_ratio())
, Ou vous pouvez simplement utiliser l'Fraction.from_float()
méthode de la classe:
Fraction.from_float(0.25)
Qui fait essentiellement la même chose, par exemple prendre le tuple de rapport entier et le passer en tant que deux arguments distincts.
Et une petite démo avec vos valeurs d'échantillon:
>>> 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
Les deux Le module fractions
et la méthode float.as_integer_ratio()
sont nouveaux dans 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
Si vous souhaitez imprimer une fraction appropriée , Cette petite recette devrait faire:
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}")
Cela affichera comme suit:
>>> dec_to_proper_frac(3.75)
>>> "3 3/4"
Pour développer Martijn Pieters excellente réponse avec une option supplémentaire en raison de l'imprécision inhérente aux flotteurs plus complexes. Par exemple:
>>> 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
Le résultat mathématique souhaité était {[6] } qui peut être obtenu en lançant une chaîne et en la manipulant ensuite.
Réponse Modifiée
J'ai trouvé un moyen beaucoup plus simple de résoudre le problème de précision.
>>> Fraction(str(f))
Fraction(8857097, 10000000)
Le Casting d'une chaîne permet également une décimale précise les instances
>>> Decimal(f).as_integer_ratio()
(1994440937439217, 2251799813685248)
>>> Decimal(str(f)).as_integer_ratio()
(8857097, 10000000)
Réponse Originale
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
Maintenant, nous allons le tester:
>>> float_to_ratio(f)
(8857097, 10000000) # mathematically correct
Je noterai que ce type de précision de fraction n'est pas optimisé et ne sera généralement pas nécessaire, mais pour être complet, c'est ici. Cette fonction ne simplifie pas la fraction, mais vous pouvez faire un traitement supplémentaire pour la réduire:
>>> n = 0.5
>>> float_to_ratio(n)
(5, 10)
>>> Fraction(*float_to_ratio(n))
Fraction(1, 2)