[Python-Dev] Re: PEP239 (Rational Numbers) Reference Implementation and new issues
Tim Peters
tim@zope.com
Fri, 4 Oct 2002 12:33:01 -0400
[Fran=E7ois Pinard]
> ...
> Interesting, I'll save it. I use continued fraction expansion to get
> the "best" rational fitting a float within a tolerance, and wonder how
> Farey will be similar/different. Tim will surely tell us, out of his
> head! :-)
Your wish is granted <wink>: Moshe Zadka's prototype implementation of
rationals is still sitting in Python CVS nondist/sandox/rational/. Its
_trim function is one I worked on with him, and uses c.f. expansion to fi=
nd
"the best" rational approximating a given rational, among all rationals w=
ith
denominator no larger than argument max_d. The Farey method is almost
identical, except potentially much slower. It's almost what "the usual"
continued fraction algorithm would do if you couldn't use integer divisio=
n
to do a whole bunch of steps in one gulp; e.g., whenever the c.f. expansi=
on
gets a partial quotient of N, the Farey method does N distinct steps. Ab=
out
"almost identical": c.f. expansion produces a sequence of rationals
alternately smaller and larger than the target, each one (much) closer th=
an
the last. The Farey method also looks at rationals "between" those; _tri=
m
does too, but only at the endpoint, when max_d is between the denominator=
s
of two successive c.f. convergents.
Moshe's package also has an _approximate function, to find "the smallest"
rational within a given absolute distance of an input rational; that's
probably closest to what you're doing now. _trim answers questions like
"what's the best approximation to pi with denominator no greater than 6?".
Neither of the adjacent convergents 3/1 and 22/7 is the correct answer to
that; 19/6 is correct. Note that the c.f. expansion gets 22/7 because th=
e
previous two convergents were 1/0 and 3/1, the next partial quotient is 7=
,
and then the next convergent is
1 + 3*7 22
------- =3D --
0 + 1*7 7
If the partial quotient *had* been 6, it would have given 19/6 instead.
That's what the tail end of _trim deduces.
The Farey method does this one step at a time, going from (and skipping t=
o
then end of process)
1/0 3/1
as bounds to
3/1 4/1
and then
3/1 7/2
and then
3/1 10/3
and then
3/1 13/4
and then
3/1 16/5
and then, finally
3/1 19/6
Especially when coded in Python, it's much more efficient to deduce this =
in
one gulp (via exploiting division).