If this goes in, I have some recommendations:
* Follow the decimal module's lead in assiduously avoiding
float->rational conversions. Something like Rat.from_float(1.1) is
likely to produce unexpected results (like locking in an inexact input
and having an unexpectedly large denominator).
* Likewise, follow decimal's lead in avoiding all automatic coercisions
from floats: Rational(3,10) + 0.3 for example. The two don't mix.
* Consider following decimal's lead on having a context that can limit
the maximum size of a denominator. There are various strategies for
handling a limit overflow including raising an exception or finding the
nearest rational upto the max denominator (there are some excellent
though complex published algorithms for this) or rounding the nearest
fixed-base (very easy). I'll dig out my HP calculator manuals at some
point -- they had worked-out a number of challenges with fractional
arithmetic (including their own version of an Inexact tag).
* Consider adding Decimal.from_rational and Rational.from_decimal. I
believe these are both easy and can be done losslessly.
* Automatic coercions to/from Decimal need to respect the active decimal
context. For example the result of Rational(3,11) +
Decimal('3.1415926') is context dependent and may not be commutative.
* When in doubt, keep the API minimal so we don't lock-in design mistakes.
* Test the API by taking a few numerical algorithms and seeing how well
they work with rational inputs (for starters, try
http://docs.python.org/lib/decimal-recipes.html ).
* If you do put in a method that accepts floats, make sure that it can
accept arguments to control the rational approximation. Ideally, you
would get something something like this Rational.approximate(math.pi, 6)
--> 355/113 that could produce the smallest rationalal approximation to
a given level of accuracy. |