Da Gleitkommawerte ungenau sein können, kann es zu "seltsamen" Brüchen kommen. Begrenzen Sie den Nenner, um den Bruch etwas zu vereinfachen, mit Fraction.limit_denominator():
Wenn Sie Python 2.6 noch verwenden, wird Fraction()die floatdirekte Übergabe von a noch nicht unterstützt. Sie können jedoch die beiden oben genannten Techniken kombinieren, um:
Vielen Dank! Option 1 funktioniert, aber Option 2 (Bruch (0,25)) gibt mir den Fehler: "TypeError: 'float'-Objekt kann nicht als Index interpretiert werden". Kannst du mir sagen warum?
user2370460
1
@ user2370460: Welche Python-Version verwenden Sie?
Martijn Pieters
5
@ user2370460: Ah, ja, nur Version 2.7 und höher unterstützen die Übergabe eines Gleitkomma- oder Dezimaltyps. Verwenden Sie Fraction(*(0.25).as_integer_ratio())stattdessen in diesem Fall.
Martijn Pieters
1
Beachten Sie, dass sowohl das fractionsModul float.as_integer_ratioals auch in Python 2.6 hinzugefügt wurden. Wenn Sie eine ältere Version von Python ausführen, sind diese nicht verfügbar.
IceArdor
3
@ user2370460: Ich habe es total geschafft, die verfügbare Fraction.from_float()Klassenmethode zu verpassen , viel klarer. 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
Danke, aber das gibt mir: "TypeError: 'float' Objekt kann nicht als Index interpretiert werden". Kannst du mir sagen warum?
user2370460
1
Guter Vorschlag, aber ich möchte hinzufügen: Der Konstruktor mit einem Argument funktioniert gut für einige Zahlen, aber nicht für andere. Zum Beispiel Fraction(.2)wird Fraction(3602879701896397, 18014398509481984). Es könnte besser sein, den Konstruktor mit zwei Argumenten zu verwenden, z. Fraction(2,10)
Kevin
3
@ Kevin: Das liegt daran, dass .2 nicht genau durch einen Float dargestellt werden kann. Siehe meine Antwort für eine Problemumgehung; Begrenzen Sie den Nenner und Sie können ihn im Handumdrehen auf 2/10 zurückbringen.
Martijn Pieters
9
Martijn Pieters ausgezeichnete Antwort mit einer zusätzlichen Option aufgrund der Ungenauigkeit, die komplexeren Schwimmern innewohnt, zu erweitern. Zum Beispiel:
>>> 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
Das gewünschte mathematische Ergebnis war 8857097/10000000 das, das erreicht werden kann, indem eine Saite gegossen und dann manipuliert wird.
Bearbeitete Antwort
Ich habe einen viel einfacheren Weg gefunden, um das Genauigkeitsproblem zu lösen.
>>> Fraction(str(f))
Fraction(8857097, 10000000)
Das Umwandeln einer Zeichenfolge ermöglicht auch genaue Dezimalinstanzen
Ich werde bemerken, dass diese Art der Bruchgenauigkeit nicht optimiert ist und normalerweise nicht benötigt wird, aber der Vollständigkeit halber ist sie hier. Diese Funktion vereinfacht den Bruch nicht, aber Sie können zusätzliche Verarbeitung durchführen, um ihn zu reduzieren:
Antworten:
Sie haben zwei Möglichkeiten:
Verwendung
float.as_integer_ratio()
:>>> (0.25).as_integer_ratio() (1, 4)
(Ab Python 3.6 können Sie dasselbe mit einem
decimal.Decimal()
Objekt tun .)Verwenden Sie den
fractions.Fraction()
Typ :>>> from fractions import Fraction >>> Fraction(0.25) Fraction(1, 4)
Letzteres hat eine sehr hilfreiche
str()
Konvertierung:>>> str(Fraction(0.25)) '1/4' >>> print Fraction(0.25) 1/4
Da Gleitkommawerte ungenau sein können, kann es zu "seltsamen" Brüchen kommen. Begrenzen Sie den Nenner, um den Bruch etwas zu vereinfachen, mit
Fraction.limit_denominator()
:>>> Fraction(0.185) Fraction(3332663724254167, 18014398509481984) >>> Fraction(0.185).limit_denominator() Fraction(37, 200)
Wenn Sie Python 2.6 noch verwenden, wird
Fraction()
diefloat
direkte Übergabe von a noch nicht unterstützt. Sie können jedoch die beiden oben genannten Techniken kombinieren, um:Fraction(*0.25.as_integer_ratio())
Oder Sie können einfach die
Fraction.from_float()
Klassenmethode verwenden :Fraction.from_float(0.25)
Dies macht im Wesentlichen dasselbe, z. B. nehmen Sie das Ganzzahlverhältnis-Tupel und übergeben Sie es als zwei separate Argumente.
Und eine kleine Demo mit Ihren Beispielwerten:
>>> 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
Sowohl das
fractions
Modul als auch diefloat.as_integer_ratio()
Methode sind neu in Python 2.6.quelle
Fraction(*(0.25).as_integer_ratio())
stattdessen in diesem Fall.fractions
Modulfloat.as_integer_ratio
als auch in Python 2.6 hinzugefügt wurden. Wenn Sie eine ältere Version von Python ausführen, sind diese nicht verfügbar.Fraction.from_float()
Klassenmethode zu verpassen , viel klarer.Fraction.from_float(0.25)
.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
quelle
Fraction(.2)
wirdFraction(3602879701896397, 18014398509481984)
. Es könnte besser sein, den Konstruktor mit zwei Argumenten zu verwenden, z.Fraction(2,10)
Martijn Pieters ausgezeichnete Antwort mit einer zusätzlichen Option aufgrund der Ungenauigkeit, die komplexeren Schwimmern innewohnt, zu erweitern. Zum Beispiel:
>>> 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
Das gewünschte mathematische Ergebnis war
8857097/10000000
das, das erreicht werden kann, indem eine Saite gegossen und dann manipuliert wird.Bearbeitete Antwort
Ich habe einen viel einfacheren Weg gefunden, um das Genauigkeitsproblem zu lösen.
>>> Fraction(str(f)) Fraction(8857097, 10000000)
Das Umwandeln einer Zeichenfolge ermöglicht auch genaue Dezimalinstanzen
>>> Decimal(f).as_integer_ratio() (1994440937439217, 2251799813685248) >>> Decimal(str(f)).as_integer_ratio() (8857097, 10000000)
Ursprüngliche Antwort
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
Jetzt testen wir es:
>>> float_to_ratio(f) (8857097, 10000000) # mathematically correct
Ich werde bemerken, dass diese Art der Bruchgenauigkeit nicht optimiert ist und normalerweise nicht benötigt wird, aber der Vollständigkeit halber ist sie hier. Diese Funktion vereinfacht den Bruch nicht, aber Sie können zusätzliche Verarbeitung durchführen, um ihn zu reduzieren:
>>> n = 0.5 >>> float_to_ratio(n) (5, 10) >>> Fraction(*float_to_ratio(n)) Fraction(1, 2)
quelle
Wenn Sie einen richtigen Bruch drucken möchten , sollte dieses kleine Rezept Folgendes tun:
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}")
Dies wird wie folgt gedruckt:
>>> dec_to_proper_frac(3.75) >>> "3 3/4"
quelle