How about adding rational fraction to Python?

NickC ncoghlan at gmail.com
Tue Mar 4 08:46:48 EST 2008


On Mar 4, 7:11 am, Lie <Lie.1... at gmail.com> wrote:
> On Mar 2, 11:36 pm, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> > > > Try with a=7, b=25
>
> > > They should still compare true, but they don't. The reason why they
> > > don't is because of float's finite precision, which is not exactly
> > > what we're talking here since it doesn't change the fact that
> > > multiplication and division are inverse of each other.
>
> > What?  Obviously they are not exact inverses for floats, as that test
> > shows.  They would be inverses for mathematical reals or rationals,
> > but Python does not have those.
>
> When I said multiplication and division are inverse, I was pointing
> out the fact that even though float's inexactness make them imperfect
> inverse, mult & div are still inverse of each other. In-practice, the
> inversing behavior is impossible unless we have a way to represent
> real number (which we don't), and the *workaround* to make them work
> is to do epsilon comparison.

A mildly interesting Py3k experiment:

Python 3.0a3+ (py3k:61229, Mar  4 2008, 21:38:15)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from fractions import Fraction
>>> from decimal import Decimal
>>> def check_accuracy(num_type, max_val=1000):
...     wrong = 0
...     for x in range(1, max_val):
...         for y in range(1, max_val):
...             wrong += (x / num_type(y)) * y != x
...     return wrong
...
>>> check_accuracy(float)
101502
>>> check_accuracy(Decimal)
310013
>>> check_accuracy(Fraction)
0


The conclusions I came to based on running that experiment are:
- Decimal actually appears to suffer more rounding problems than float
for rational arithmetic
- Decimal appears to be significantly slower than Fraction for small
denominator rational arithmetic
- both Decimal and Fraction are significantly slower than builtin
floats

The increased number of inaccurate answers with Decimal (31% vs 10%)
is probably due to the fact that it is actually more precise than
float - for the builtin floats, the rounding error in the division
step may be cancelled out by a further rounding error in the
multiplication step (this can be seen happening in the case of ((1 /
3.0) * 3) == 1.0, where the result of the multiplication ends up being
1.0 despite the rounding error on division, due to the next smallest
floating value being 0.99999999999999989).

The speed difference between Decimal and Fraction is likely due to the
fact that Fraction can avoid actually doing any division most of the
time - it does addition and multiplication instead. The main reason
behind the overall speed advantage of builtin floats should hopefully
be obvious ;)

Regardless, the result of integer division is going to be a binary
floating point value in Py3k. For cases where that isn't adequate or
acceptable, the application should really be tightly controlling its
numeric types anyway and probably using a high performance math
library like numpy or gmpy instead of the standard numeric types (as
others have already noted in this thread).





More information about the Python-list mailing list