| I don't think it's that good. At the very least I implemented it and got different answers for the test case of 0.263157894737 = 5/19 depending on the choice of numerical representation. float64 ended up at 87714233939/333314088968 while decimal and fraction ended up at 87719298244/333333333327. Here is the code. import argparse
parser = argparse.ArgumentParser()
parser.add_argument("Q", nargs="?", default="0.263157894737")
parser.add_argument("--method", choices = ("float", "decimal", "fraction"), default="float")
args = parser.parse_args()
if args.method == "float":
print(f"Using float64 for {args.Q!r}")
one = 1.0
Q = float(args.Q)
int2float = float
elif args.method == "decimal":
print(f"Using decimal for {args.Q!r}")
import decimal
one = decimal.Decimal(1)
Q = decimal.Decimal(args.Q)
int2float = decimal.Decimal
elif args.method == "fraction":
print(f"Using fractions for {args.Q!r}")
import fractions
one = fractions.Fraction(1)
Q = fractions.Fraction(args.Q)
int2float = fractions.Fraction
def to_frac(X):
Da = 0
Db = 1
Za = X
while 1:
Zb = one / (Za - int(Za))
Dc = Db * int(Zb) + Da
N = round(X * Dc)
frac = N / int2float(Dc)
print(f" {N}/{Dc} = {frac} (diff: {X-frac})")
if float(N) / float(Dc) == float(X):
return (N, Dc)
Da, Db = Db, Dc
Za = Zb
print("solution:", to_frac(Q))
Here's the output for 0.263157894737 % python frac.py 0.263157894737 --method float
Using float64 for '0.263157894737'
1/3 = 0.3333333333333333 (diff: -0.0701754385963333)
1/4 = 0.25 (diff: 0.01315789473700002)
4/15 = 0.26666666666666666 (diff: -0.003508771929666643)
5/19 = 0.2631578947368421 (diff: 1.5792922525292852e-13)
87714233939/333314088968 = 0.263157894737 (diff: 0.0)
solution: (87714233939, 333314088968)
% python frac.py 0.263157894737 --method decimal
Using decimal for '0.263157894737'
1/3 = 0.3333333333333333333333333333 (diff: -0.0701754385963333333333333333)
1/4 = 0.25 (diff: 0.013157894737)
4/15 = 0.2666666666666666666666666667 (diff: -0.0035087719296666666666666667)
5/19 = 0.2631578947368421052631578947 (diff: 1.578947368421053E-13)
87719298244/333333333327 = 0.2631578947370000000000030000 (diff: -3.0000E-24)
solution: (87719298244, 333333333327)
% python frac.py 0.263157894737 --method fraction
Using fractions for '0.263157894737'
1/3 = 1/3 (diff: -210526315789/3000000000000)
1/4 = 1/4 (diff: 13157894737/1000000000000)
4/15 = 4/15 (diff: -10526315789/3000000000000)
5/19 = 5/19 (diff: 3/19000000000000)
87719298244/333333333327 = 87719298244/333333333327 (diff: -1/333333333327000000000000)
solution: (87719298244, 333333333327)
For the pi = 3.14159265359 test case the solutions are all 226883371/72219220 . The sequence diverges at the point marked with "<---- here". Using float64
22/7 = 3.142857142857143 (diff: -0.0012644892671427321)
333/106 = 3.141509433962264 (diff: 8.321962773605307e-05)
355/113 = 3.1415929203539825 (diff: -2.667639824593948e-07)
103993/33102 = 3.1415926530119025 (diff: 5.780975698144175e-10)
104348/33215 = 3.141592653921421 (diff: -3.3142111277584263e-10)
208341/66317 = 3.1415926534674368 (diff: 1.2256329284809908e-10)
312689/99532 = 3.1415926536189365 (diff: -2.893640882462023e-11)
833719/265381 = 3.141592653581078 (diff: 8.922196315097608e-12)
1146408/364913 = 3.141592653591404 (diff: -1.403765992336048e-12)
5419351/1725033 = 3.1415926535898153 (diff: 1.8474111129762605e-13) <---- here
6565759/2089946 = 3.141592653590093 (diff: -9.281464485866309e-14)
11985110/3814979 = 3.141592653589967 (diff: 3.2862601528904634e-14)
18550869/5904925 = 3.1415926535900116 (diff: -1.1546319456101628e-14)
30535979/9719904 = 3.1415926535899943 (diff: 5.773159728050814e-15)
49086848/15624829 = 3.141592653590001 (diff: -8.881784197001252e-16)
226883371/72219220 = 3.14159265359 (diff: 0.0)
solution: (226883371, 72219220)
For 0.10000000000000002 it gives 562949953421313/5629499534213129 (for float64) or 500000000000000/4999999999999999 (using fractions): Using float64 for '0.10000000000000002'
1/9 = 0.1111111111111111 (diff: -0.011111111111111086)
1/10 = 0.1 (diff: 1.3877787807814457e-17)
562949953421313/5629499534213129 = 0.10000000000000002 (diff: 0.0)
solution: (562949953421313, 5629499534213129)
Using fractions for '0.10000000000000002'
1/9 = 1/9 (diff: -4999999999999991/450000000000000000)
1/10 = 1/10 (diff: 1/50000000000000000)
500000000000000/4999999999999999 = 500000000000000/4999999999999999 (diff: -1/249999999999999950000000000000000)
solution: (500000000000000, 4999999999999999)
FWIW, the exact solution is: >>> import fractions
>>> fractions.Fraction("0.10000000000000002")
Fraction(5000000000000001, 50000000000000000)
|