Thanks, I was looking for this and it is very useful. But.. I found a tiny error in it... Brackets... Here is my version.
Code: Select all
; https://www.purebasic.fr/english/viewtopic.php?t=42091&start=15
; ** find rational approximation To given real number
; ** David Eppstein / UC Irvine / 8 Aug 1993
; ** With corrections from Arno Formella, May 2008
; ** PureBasic portage by DrGolf, Mai 2010
; ** Al_the_dutch July 2024
EnableExplicit
Procedure.s Fraction(Start.d, MaxDen.q=10000)
Protected x.d
Protected.q x_int, t, NomAlt= 0, Nom = 1, DeNom = 0, DeNomAlt = 1
x = Start
x_int = Int(x)
;While DeNom * x_int + DeNomAlt <= MaxDen; OK!!
While DeNom * (x_int + DeNomAlt) <= MaxDen; Originally While (q0 * (Int(x) + q1) <= maxden); not correct
; = = Remove brackets
t = Nom * x_int + NomAlt
NomAlt = Nom
Nom = t
t = DeNom * x_int + DeNomAlt
DeNomAlt = DeNom
DeNom = t
If x - x_int = 0
Debug "Zero Exit..."
Break ; // AF: division by zero
EndIf
x = 1/(x - x_int)
If (x>$7FFFFFFF)
Debug "Exit..."
Break; // AF: representation failure
EndIf
x_int = Int(x)
Wend
; Solution 2...
x_int = (MaxDen - DeNomAlt) / DeNom
NomAlt = Nom * x_int + NomAlt
DeNomAlt = DeNom * x_int + DeNomAlt
If Abs(Start - (Nom / DeNom)) > Abs(Start - (NomAlt / DeNomAlt))
;Debug "Solution 2 prefered..."
Nom = NomAlt
DeNom = DeNomAlt
EndIf
;Debug Str(Nom)+"/"+Str(DeNom)+" error : "+StrD(Start - (Nom / DeNom))
ProcedureReturn Str(Nom)+" / "+Str(DeNom) + " " + StrD(Start - Nom/DeNom, 15)
EndProcedure
Procedure.s Iif(Test.b, ok$, nok$)
If Test
ProcedureReturn ok$
EndIf
ProcedureReturn nok$
EndProcedure
Define q.d = #PI; https://math.stackexchange.com/questions/3506435/best-possible-rational-approximation-of-pi
; https://mathworld.wolfram.com/PiApproximations.html
; Convergents of the pi continued fractions are the simplest approximants To pi.
; The first few are given by 3, 22/7, 333/106, 355/113, 103993/33102, 104348/33215, ... (OEIS A002485 And A002486),
; which are good To 0, 2, 4, 6, 9, 9, 9, 10, 11, 11, 12, 13, ... (OEIS A114526) decimal digits, respectively.
Define k.a, l.a, MaxDen.q, Diff0.d = 1.0, Diff1.d, Fract$
;Testing - You only expect Smaller or Equal.
For k = 1 To 6
For l = 1 To 9
MaxDen = l* Pow(10, k)
Fract$ = Fraction(q, MaxDen)
Diff1 = ValD(Right(Fract$, 18))
Debug "MaxDen : " + MaxDen + " Frac: "+ Fract$ + Iif(Bool(Abs(Diff1) <= Abs(Diff0)), " Smaller Or Equal", " NO GOOD!")
Diff0 = Diff1
Next l
Next k