Seite 4 von 4
Re: Dezimalzahlen in Bruch umwandeln
Verfasst: 10.11.2020 03:02
von Nino
Hi Stargåte,
interessanter Code, danke!
Die Prüfung
Code: Alles auswählen
If IsInfinity(Double) Or IsNAN(Double) Or Double > 1e16 Or Double < 1e-16
ProcedureReturn ""
EndIf
sollte weiter zu Beginn der Prozedur durchgeführt werden, teste mal
Und warum all dies in einen Topf werfen? Ich würde es eher so machen:
Code: Alles auswählen
If IsInfinity(Double)
ProcedureReturn StrD(Infinity())
ElseIf IsNAN(Double)
ProcedureReturn StrD(NaN())
EndIf
Die Prüfung auf Infinity sollte dann VOR
stehen, damit zwischen +Infinity und -Infinity unterschieden werden kann.
Mich irritiert ein bisschen die Bezeichnung "MaxRelativeError". Relativ wozu? Sind 1e-6 usw. nicht
absolute Fehler?
Re: Dezimalzahlen in Bruch umwandeln
Verfasst: 10.11.2020 11:15
von STARGÅTE
Nino hat geschrieben:Mich irritiert ein bisschen die Bezeichnung "MaxRelativeError". Relativ wozu? Sind 1e-6 usw. nicht absolute Fehler?
Der Fehler ist relativ zur Zahl selbst. Also eine Art Präzision der Zahl.
1e-6 heißt, dass etwa 6 Ziffern (vor + nach dem Komma) richtig sein sollten.
Somit geben ToFraction(0.3333333) und ToFraction(33333.33) beide etwas mit drittel zurück.
Um die Prüfung werde ich mich noch mal kümmern.
Re: Dezimalzahlen in Bruch umwandeln
Verfasst: 11.11.2020 17:47
von Nino
Ich habe den Code für meine Bedürfnisse entspr. meiner obigen Bemerkungen angepasst. Die eigentliche Berechnung habe ich nicht geändert. Vielen Dank nochmal für den schönen Code!
Anm.: Die in PB eingebaute Funktion Assert() ist leider erst verfügbar, nachdem man die Datei "PureUnit.res" in den Unterordner "Residents\" verschoben hat.
Code: Alles auswählen
Procedure.s ToFraction (Double.d, MaxRelativeError.d=1e-6)
Protected.q LowNumerator, LowDenominator
Protected.q HighNumerator, HighDenominator
Protected.q Numerator, Denominator
Protected.d Fraction, OldFraction
Protected.i Factor, Iteration
Protected sign$
If IsNAN(Double) Or IsInfinity(Double)
ProcedureReturn StrD(double) ; NaN, +Infinity or -Infinity
EndIf
If Double < 0
Double = Abs(Double)
sign$ = "-"
EndIf
If Double > 1e16
ProcedureReturn "Overflow"
ElseIf Double < 1e-16
ProcedureReturn "Underflow"
EndIf
LowNumerator = 0
LowDenominator = 1
HighNumerator = 1
HighDenominator = Round(1/Double, #PB_Round_Down) - 1
Numerator = LowNumerator + HighNumerator
Denominator = HighNumerator + HighDenominator
Fraction = Infinity()
Repeat
Iteration + 1
OldFraction = Fraction
Fraction = 1 - Double * Denominator / Numerator
; Debug "Iteration "+RSet(Str(Iteration),3)+": " + Str(Numerator) + " / " + Str(Denominator) + " ( δ = "+Fraction+" )"
Factor = Abs(Fraction) / (Abs(OldFraction) - Abs(Fraction))
If Factor < 1 Or Fraction > 0 Or OldFraction > 0
Factor = 1
EndIf
If Fraction < -MaxRelativeError ; zu klein
LowNumerator = Numerator
LowDenominator = Denominator
Numerator + Factor*HighNumerator
Denominator + Factor*HighDenominator
ElseIf Fraction > MaxRelativeError ; zu groß
HighNumerator = Numerator
HighDenominator = Denominator
Numerator + Factor*LowNumerator
Denominator + Factor*LowDenominator
Else
ProcedureReturn sign$ + Str(Numerator) + "/" + Str(Denominator)
EndIf
ForEver
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
; -- Ein paar Brüche:
Assert(ToFraction(0.375) = "3/8")
Assert(ToFraction(0.3333333) = "1/3")
Assert(ToFraction(0.0625) = "1/16")
Assert(ToFraction(-1.15) = "-23/20")
Assert(ToFraction(13.4) = "67/5")
Assert(ToFraction(127/307) = "127/307")
Assert(ToFraction(1018/717.0) = "1018/717")
Assert(ToFraction(-73/105.0) = "-73/105")
Assert(ToFraction(1.0/1000.0) = "1/1000")
Assert(ToFraction(7.0/10000.0) = "7/10000")
Assert(ToFraction(999.0/1000.0) = "999/1000")
Assert(ToFraction(9999.0/10000.0, 1e-8) = "9999/10000")
Assert(ToFraction(499999.0/999999.0, 1e-12) = "499999/999999")
; -- Näherungsbrüche für Pi: ; https://de.wikipedia.org/wiki/Kreiszahl#Näherungsbrüche_der_Kreiszahl
Assert(ToFraction(#PI, 1e-3) = "22/7")
Assert(ToFraction(#PI, 1e-5) = "355/113")
; -- Spezielle Argumente:
Assert(ToFraction(NaN()) = "NaN")
Assert(ToFraction( Infinity()) = "+Infinity")
Assert(ToFraction(-Infinity()) = "-Infinity")
Assert(ToFraction( 1e17) = "Overflow")
Assert(ToFraction(-1e17) = "Overflow")
Assert(ToFraction( 1e-17) = "Underflow")
Assert(ToFraction(-1e-17) = "Underflow")
CompilerEndIf