[Python-Dev] Adding a Rational Type to Python

Guido van Rossum guido@digicool.com
Sun, 11 Mar 2001 18:55:03 -0500


Here's the third installment -- my response to Moshe's rational
numbers PEP.

I believe that a fourth PEP should be written as well: decimal
floating point.  Maybe Tim can draft this?

> PEP: XXX
> Title: Adding a Rational Type to Python
> Version: $Revision$
> Author: pep@zadka.site.co.il (Moshe Zadka)
> Status: Draft
> Python-Version: 2.2
> Type: Standards Track
> Created: 11-Mar-2001
> Post-History:
> 
> 
> Abstract
> 
>     Python has no number type whose semantics are that of a
>     unboundedly precise rational number.

But one could easily be added to the standard library, and several
implementations exist, including one in the standard distribution:
Demo/classes/Rat.py.

>     This proposal explains the
>     semantics of such a type, and suggests builtin functions and
>     literals to support such a type. In addition, if division of
>     integers would return a non-integer, it could also return a
>     rational type.

It's kind of sneaky not to mention in the abstract that this should be
the default representation for numbers containing a decimal point,
replacing most use of floats!

> Rationale
> 
>     While sometimes slower and more memory intensive (in general,
>     unboundedly so) rational arithmetic captures more closely the
>     mathematical ideal of numbers, and tends to have behaviour which
>     is less surprising to newbies,

This PEP definitely needs a section of arguments Pro and Con.  For
Con, mention at least that rational arithmetic is much slower than
floating point, and can become *very* much slower when algorithms
aren't coded carefully.  Now, naively coded algorithms often don't
work well with floats either, but there is a lot of cultural knowledge
about defensive programming with floats, which is easily accessible to
newbies -- similar information about coding with rationals is much
less easily accessible, because no mainstream languages have used
rationals before.  (I suppose Common Lisp has rationals, since it has
everything, but I doubt that it uses them by default for numbers with
a decimal point.)

> RationalType
> 
>     This will be a numeric type. The unary operators will do the
>     obvious thing.  Binary operators will coerce integers and long
>     integers to rationals, and rationals to floats and complexes.
>
>     The following attributes will be supported: .numerator,
>     .denominator.  The language definition will not define other
>     then that
> 
>            r.denominator * r == r.numerator
> 
>     In particular, no guarantees are made regarding the GCD or the
>     sign of the denominator, even though in the proposed
>     implementation, the GCD is always 1 and the denominator is
>     always positive.
>
>     The method r.trim(max_denominator) will return the closest
>     rational s to r such that abs(s.denominator) <= max_denominator.
> 
> The rational() Builtin
> 
>     This function will have the signature rational(n, d=1). n and d
>     must both be integers, long integers or rationals. A guarantee
>     is made that
> 
>             rational(n, d) * d == n
> 
> Literals
> 
>     Literals conforming to the RE '\d*.\d*' will be rational numbers.
> 
> Backwards Compatability
> 
>     The only backwards compatible issue is the type of literals
>     mentioned above. The following migration is suggested:
> 
>     1. from __future__ import rational_literals will cause all such
>        literals to be treated as rational numbers.
>     2. Python 2.2 will have a warning, turned off by default, about
>        such literals in the absence of such an __future__. The
>        warning message will contain information about the __future__
>        statement, and that to get floating point literals, they
>        should be suffixed with "e0".
>     3. Python 2.3 will have the warning turned on by default. This
>        warning will stay in place for 24 months, at which time the
>        literals will be rationals and the warning will be removed.

There are also backwards compatibility issues at the C level.

Question: the time module's time() function currently returns a
float.  Should it return a rational instead?  This is a trick question.

> Copyright
> 
>     This document has been placed in the public domain.
> 
> 
> 
> Local Variables:
> mode: indented-text
> indent-tabs-mode: nil
> End:

--Guido van Rossum (home page: http://www.python.org/~guido/)