2010-01-10 19 views
6

Gibt es eine reine Python-Implementierung von fractions.Fraction, die long s als Zähler und Nenner unterstützt? Leider scheint die Potenzierung so codiert zu sein, dass ein float (ack !!!) zurückgegeben wird, der zumindest decimal.Decimal unterstützen sollte.Brüche mit dezimaler Genauigkeit

Wenn nicht, nehme ich an, ich kann wahrscheinlich eine Kopie der Bibliothek erstellen und versuchen, Vorkommen von float() mit etwas passendem von Decimal zu ersetzen, aber ich würde lieber etwas, das zuvor von anderen getestet wurde.

Hier ist ein Codebeispiel:

base = Fraction.from_decimal(Decimal(1).exp()) 
a = Fraction(69885L, 53L) 
x = Fraction(9L, 10L) 

print base**(-a*x), type(base**(-a*x)) 

Ergebnisse in 0.0 <type 'float'> wo die Antwort ein wirklich kleines dezimal sein sollte.

Update: Ich habe die folgende Umgehung für jetzt (vorausgesetzt, für a ** b, dass beide Brüche sind; natürlich brauche ich eine andere Funktion, wenn exp_ ein float ist oder selbst ist ein Dezimal):

def fracpow(base, exp_): 
    base = Decimal(base.numerator)/Decimal(base.denominator) 
    exp_ = Decimal(exp_.numerator)/Decimal(exp_.denominator) 

    return base**exp_ 

, die die Antwort 4.08569925773896097019795484811E-516 gibt.

Ich wäre immer noch interessiert, wenn es eine bessere Möglichkeit gibt, dies ohne die zusätzlichen Funktionen zu tun (ich denke, wenn ich mit der Fraction Klasse genug arbeite, werde ich andere Schwimmer finden, die ihren Weg in meine Ergebnisse arbeiten).

+0

Wenn ich Fraktionen mache.Fraktion (11,17) ** 2 bekomme ich Brüche.Fraktion (121, 289). Was bekommst du? –

+0

Versuchstyp (Brüche. Fraktion (11,17) ** 2.1) – Noah

+0

IMO, das Verhalten, das Sie sehen, ist richtig, obwohl nicht was Sie wollen.Da der Exponent ein float ist, ist es sinnvoll, dass Dinge in float umgewandelt werden. Nun, wenn der Exponent Fraction (21,10) wäre, wäre das interessanter ... –

Antwort

6

„Raise auf eine Leistung“ ist kein geschlossene Betrieb über das rationals (anders als die üblichen vier arithmetischen Operationen): Es gibt keine rationale Zahl r so dass r == 2 ** 0.5. Die Legende besagt, dass Pythagoras (von dessen Satz diese Tatsache so einfach folgt) seinen Schüler Hippasus für das schreckliche Verbrechen getötet hat, dieses zu beweisen; Sieht so aus, als würdest du mit Pythagoras 'angeblicher Reaktion sympathisieren ;-), angesichts deiner seltsamen Verwendung von "sollte".

Pythons Brüche sollen genau sein, so dass es unvermeidlich Fälle gibt, in denen die Erhöhung eines Bruchteils auf die Leistung einer anderen Fraktion absolut unfähig ist, einen Bruch als Ergebnis zurückgeben; und "sollte" kann vernünftigerweise nicht auf eine mathematische Unmöglichkeit angewandt werden.

Also das Beste, was Sie tun können, ist ungefähres Ihr gewünschtes Ergebnis, z.B. indem man ein Ergebnis erhält, das kein exakter Bruch ist (Floats werden im Allgemeinen für den Zweck als ausreichend angesehen), und dann wird es weiter mit einem Bruchteil angenähert. Die meisten existierenden pure-Python-Implementierungen (es gibt vielerationals.py Dateien rund um das Netz ;-) lieber keinen ** Operator überhaupt implementieren, aber natürlich gibt es nichts, was Sie daran hindert, eine andere Designentscheidung in Ihrer eigenen Implementierung zu treffen! -)

+0

Dies ist natürlich mathematisch korrekt, aber der Grund, warum ich die Fraction-Klasse verwende, ist, weil ich hohe numerische Genauigkeit will, und ich versuche Code zu aktualisieren jemand anderes schrieb mit der clnum-Bibliothek. Da Fraction glücklich ist, einen Zähler oder Nenner zu nehmen, scheint es nur gerecht, dass es in der Lage sein sollte, ein Dezimum nach der Potenzierung zurückzugeben. Nun, wenn ich nur herausfinden könnte, ob Fracpow (0,0) als 1 definiert werden sollte oder ob das ein Fehler im Code war! – Noah

+1

@Noah, kann dir hier mit reinem Python-Code nicht wirklich helfen, da ich für solche Aufgaben immer 'gmpy' benutze, natürlich; aber gmpy.mpq erlaubt auch keine unexact-roots mit gebrochenen Exponenten (_my_ Design-Entscheidung in diesem Fall), also würde ich in meinem Fall hochpräzise Floats (gmpy.mpf) durchlaufen, genau wie du es mit Decimal machst (Das sind auch Floats, nur dezimale anstelle von binären, mit SW statt HW-Implementierungen, und mit der Genauigkeit so hoch wie gewünscht einstellbar - gmpy.mpf sind ähnlich, aber binär statt dezimal. –

+0

Der Fehler aus Ihrer numerischen Approximation von exp ist normalerweise größer als der Fehler bei der Approximation des Approximationsergebnisses mit einem Float. –

0

Sie können Ihre eigene "pow" -Funktion für Brüche schreiben, die keine Fließkomma-Exponentiation verwenden. Ist es das, was du versuchst?

Dadurch wird ein Bruch zu einer ganzzahligen Potenz mit Zurückfallen in float erhöht.

def pow(fract, exp): 
    if exp == 0: 
     return fract 
    elif exp % 2 == 0: 
     t = pow(fract, exp//2) 
     return t*t 
    else: 
     return fract*pos(fract, exp-1) 
+0

Hmmm, besser _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ –

Verwandte Themen