How about adding rational fraction to Python?

Mark Dickinson dickinsm at gmail.com
Tue Mar 4 14:04:23 EST 2008


On Mar 4, 9:39 am, Mark Dickinson <dicki... at gmail.com> wrote:
> On Mar 4, 8:46 am, NickC <ncogh... at gmail.com> wrote:
>
> > 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
>
> I suspect it has more to do with the fact that 10 is bigger than 2,
> though I'm not sure I could precisely articulate the reasons why
> this matters.

Indeed, a quick lunchtime back-of-the-envelope calculation suggests
that precision is largely irrelevant:  it's the base that matters.
For randomly chosen(*) base B floats x and y, the probability that
(x/y)*y == x is approximately given by

1/2 + 1/log(B) - 1/log(B)**2 + 1/B/log(B)**2

For Decimal, this gives a probability of:

>>> 0.5 + 1/log(10) - 1/log(10)**2 + 1/10/log(10)**2
0.76454395459279922

while for randomly chosen floats it's the same thing with all 10s
replaced by 2s:

>>> 0.5 + 1/log(2) - 1/log(2)**2 + 1/2/log(2)**2
0.90201055038615952

(*) Here, randomly chosen means I'm assuming that log(x) and log(y)
are independent and uniformly distributed over some largish
interval.  Maybe not the most obvious definition of random, but
not unreasonable. (And it makes the analysis easier!)

A quick check, for floats:

#####
from __future__ import division
from random import random
from math import exp

def random_float():
    return exp(random()*400.-200.)

def test():
    x = random_float()
    y = random_float()
    return (x/y)*y == x

print sum(test() for i in xrange(10**8))/10**8
#####

produces (eventually):

0.90199129

Mark



More information about the Python-list mailing list