How about adding rational fraction to Python?
Lie
Lie.1296 at gmail.com
Sun Feb 24 14:09:32 EST 2008
On Feb 25, 1:21 am, Mark Dickinson <dicki... at gmail.com> wrote:
> On Feb 24, 1:09 pm, Lie <Lie.1... at gmail.com> wrote:
>
> > And this limit is much lower than n!. I think it's sum(primes(n)), but
> > I've got no proof for this one yet.
>
> It's the least common multiple of the integers 1 through n, or
> equivalently the product over all primes p <= n of the highest power
> of p not exceeding n. So for n = 100, it's:
>
> 64 * 81 * 25 * 49 * 11 * 13 * 17 * ... rest of primes up to 100.
>
> For general n, this number is of roughly the same order of magnitude
> as e**n.
Ah, yes, I meant product(primes(n)), please forgive my honest mistake
which is partially caused by me not supposed to still be awake at this
time of the day. And thanks for Mark for noticing the mistake, and
here is the code I used:
import fraction
import random
frac = fraction.frac
ops = (frac.__add__, frac.__sub__)
a = frac(random.randrange(1, 10), random.randrange(1, 10))
b = frac(random.randrange(1, 10), random.randrange(1, 10))
while True:
o = ops[random.randrange(0, 2)]
a = o(a, b)
b = frac(random.randrange(1, 10), random.randrange(1, 10))
print a
I decided to keep the num/den limit low (10) because higher values
might obscure the fact that it do have limits. And through further
observations, I think it is sufficient if the limit is imposed in the
denominator only (numerator can have any values it wanted to,
denominator growth is determined only by the limit of denominator
growth).
I think I'll also post the code for the fraction class I used, if you
have other fraction class that can automatically simplify, you could
use that instead as this class suffers from a naive GCD
implementation:
==== fraction.py ====
from __future__ import division
def GCD(a, b):
if b == 0: return a
return GCD(b, a % b)
class frac:
''' Fraction Class
A fraction class.
Attributes:
num -> the numerator of a fraction
den -> the denominator of a fraction
Methods:
add(a, b) -> add fraction a to fraction b and return a
new fraction
sub(a, b) -> subtract fraction b from fraction a and
return a new fraction
mul(a, b) -> multiply fraction a with fraction b and
return a new fraction
div(a, b) -> divides fraction b from fraction a and
return a new fraction
invert(a) -> invert the fraction (switch the numerator
and denominator)
neg(a) -> negates the fraction (negates numerator)
powr(a, b) -> raise fraction a to the power of b
simplify(a, b) -> simplify fraction to its canonical
representation
__init__(a, b) -> creates a new fraction
__str__(a, b) -> returns a string representation. Mixed
fraction if possible
__repr__(a, b) -> returns a string representation. Always
return vulgar fraction
Operators:
Conversion to fractions will be done automatically whenever
possible, in-place
operation is fully supported. Both regular and reflected
operation is supported.
a + b -> Calls frac.add(a, b)
a - b -> Calls frac.sub(a, b)
a * b -> Calls frac.mul(a, b)
a / b -> Calls frac.div(a, b)
a // b -> Floors the resulting fraction from frac.div(a, b)
-a -> Negates a fraction
+a -> Returns a copy of the fraction
~a -> Return the reciprocal of a
Comparisons:
Implemented through __cmp__(a, b), no rich comparison.
a == b -> a equals b
a != b -> a not equal b
a > b -> a greater than b
a < b -> a less than b
a >= b -> a greater than or equal to b
a <= b -> a less than or equal to b
Casting:
__complex__ -> Converts the fraction to floats and return the
result as complex number
__int__ -> Returns the whole part of the fraction in
Integer
__long__ -> Returns the whole part of the fraction in Long
__float__ -> Returns the value of the fractino in Float
Exceptions:
ZeroDenominatorError
-> A fraction cannot have zero as its denominator
Bugs:
- At the meantime, the fraction class doesn't mix well if used
together with floating type numbers. Inline operators and
initializers implicitly assumed that numbers are either
integers or
fraction. So if there are operations involving floating
point or
you initialized a fraction with a floating point number, the
result
would be something like a "floating point fraction".
'''
def __init__(self, a = 0, b = 1):
dev = GCD(a, b)
if b > 0:
self.num = a // dev
elif b < 0:
self.num = -a // dev
else:
raise frac.ZeroDenominatorError
self.den = abs(b) // dev
def simplify(self):
dev = GCD(self.num, self.den)
self.num //= dev
self.den //= dev
return self
def add(a, b):
return frac(a.num * b.den + b.num * a.den, a.den * b.den)
def sub(a, b):
return frac(a.num * b.den - b.num * a.den, a.den * b.den)
def mul(a, b):
return frac(a.num * b.num, a.den * b.den)
def div(a, b):
return frac(a.num * b.den, a.den * b.num)
def invert(a):
return frac(a.den, a.num)
def neg(a):
return frac(-a.num, a.den)
def powr(x, y):
return frac(x.num ** y, x.den ** y)
def __add__(self, other):
return self.add(other)
def __radd__(self, other):
return other.add(self)
def __sub__(self, other):
return self.sub(other)
def __rsub__(self, other):
return other.sub(self)
def __mul__(self, other):
return self.mul(other)
def __rmul__(self, other):
return other.mul(self)
def __div__(self, other):
return self.div(other)
def __rdiv__(self, other):
return other.div(self)
def __truediv__(self, other):
return self.div(other)
def __rtruediv__(self, other):
return other.div(self)
def __floordiv__(self, other):
ret = self.div(other)
return ret.num // ret.den
def __rfloordiv__(self, other):
ret = other.div(self)
return ret.num // ret.den
def __iadd__(a, b):
a.num, a.den = a.num * b.den + b.num * a.den, a.den * b.den
return a.simplify()
def __isub__(a, b):
a.num, a.den = a.num * b.den - b.num * a.den, a.den * b.den
return a.simplify()
def __imul__(a, b):
a.num, a.den = a.num * b.num, a.den * b.den
return a.simplify()
def __idiv__(a, b):
a.num, a.den = a.num * b.den, a.den * b.num
return a.simplify()
def __itruediv__(a, b):
a.num, a.den = a.num * b.den, a.den * b.num
return a.simplify()
def __ifloordiv__(self, other):
self /= other
return self.num // self.den
def __str__(self):
''' String Function
Convert the function to its human-friendly representation.
Tries
to convert smartly.
'''
ret = ''
if self.num < 0: ret = '-'
w, n, d = abs(self.num // self.den), abs(self.num) % self.den,
self.den
if w != 0:
if n != 0 and d != 1:
ret += '%s %s/%s' % (w, n, d)
else:
ret += str(w)
else:
if n != 0 and d != 1:
ret += '%s/%s' % (n, d)
else:
ret = '0'
return ret
def __repr__(self):
return str(self.num) + '/' + str(self.den)
def __complex__(self):
return complex(float(self))
def __int__(self):
return int(self.num / self.den)
def __long__(self):
return long(self.num / self.den)
def __float__(self):
return self.num / self.den
def __neg__(self):
return frac.neg(self)
def __pos__(self):
return frac(self.num, self.den)
def __abs__(self):
return frac(abs(self.num), self.den)
def __invert__(self):
return frac.invert(self)
def __pow__(x, y):
return powr(x, y)
def __coerce__(self, other):
try:
self.num, self.den
except AttributeError:
self = frac(self)
try:
other.num, other.den
except AttributeError:
other = frac(other)
return self, other
def __cmp__(self, other):
a = self.num * other.den
b = other.num * self.den
return cmp(a, b)
class ZeroDenominatorError(Exception):
''' Exception for having a zero as the denominator in a
Fraction Class
'''
def __init__(self):
pass
def __str__(self):
return "A fraction cannot have zero as denominator
(frac.den != 0)"
More information about the Python-list
mailing list