Decimals -> Fraction strings, my solution
François Pinard
pinard at iro.umontreal.ca
Wed May 17 15:23:47 EDT 2000
"Tim Peters" <tim_one at email.msn.com> écrit:
> > ...
> > residual = 1.0 / residual
> Note that this step can introduce a small error on each iteration, due
> to the vagaries of floating-point arithmetic. To do this with complete
> accuracy requires sticking to rational arithmetic throughout.
I understand, Tim. I revised my suggested solution according to this
remark, to get what follows. A bit sadly, the code gets much longer,
and more intricate. I'm not fully satisfied, yet it seems to work!
>>> Fraction(math.pi, tolerance=1e-5)
355:113
At least, doing this, I learned many useful things about Python. :-)
def Fraction(num, den=1, tolerance=0):
if type(0.) in (type(num), type(den)):
num, den = num/den, 1L
while long(num) != num:
num, den = 2.*num, 2L*den
num = long(num)
elif den < 0:
num = -num
den = -den
d = gcd(abs(num), den)
value = SimplifiedFraction(num/d, den/d)
if tolerance > 0:
value = ContinuedFraction(value, tolerance).simplify()
return value
class SimplifiedFraction:
triples = 0 # set to 1 for a:b:c printing
def __init__(self, num, den):
self.num = num
self.den = den
def __repr__(self):
num = self.num
den = self.den
if den == 1:
return '%.f' % num
if self.triples:
if num > 0 and num > den:
return '%.f:%.f:%.f' % (num / den, num % den, den)
if num < 0 and -num > den:
return '-%.f:%.f:%.f' % (-num / den, -num % den, den)
return '%.f:%.f' % (num, den)
def __coerce__(self, other):
if isinstance(other, SimplifiedFraction):
return self, other
if type(other) in (type(0), type(0L)):
return self, SimplifiedFraction(other, 1)
if type(other) is type(0.):
return float(self), other
def __int__(self):
if self.num < 0:
return -(-self.num / self.den)
return self.num / self.den
def __float__(self):
return float(self.num) / float(self.den)
def __neg__(self): return SimplifiedFraction(-self.num, self.den)
def __pos__(self): return self
def __abs__(self): return SimplifiedFraction(abs(self.num), self.den)
def __cmp__(self, other):
d = gcd(self.den, other.den)
if d == 1:
return cmp(self.num*other.den, other.num*self.den)
return cmp(self.num*(other.den/d), other.num*(self.den/d))
def __add__(self, other):
d1 = gcd(self.den, other.den)
if d1 == 1:
return SimplifiedFraction(self.num*other.den + other.num*self.den,
self.den*other.den)
t = self.num*(other.den/d1) + other.num*(self.den/d1)
d2 = gcd(t, d1)
return SimplifiedFraction(t/d2, (self.den/d1) * (other.den/d2))
def __sub__(self, other):
d1 = gcd(self.den, other.den)
if d1 == 1:
return SimplifiedFraction(self.num*other.den - other.num*self.den,
self.den*other.den)
t = self.num*(other.den/d1) - other.num*(self.den/d1)
d2 = gcd(t, d1)
return SimplifiedFraction(t/d2, (self.den/d1) * (other.den/d2))
def __mul__(self, other):
d1 = gcd(self.num, other.den)
d2 = gcd(self.den, other.num)
return SimplifiedFraction((self.num/d1) * (other.num/d2),
(self.den/d2) * (other.den/d1))
def __div__(self, other):
d1 = gcd(self.num, other.num)
d2 = gcd(self.den, other.den)
return SimplifiedFraction((self.num/d1) * (other.den/d2),
(self.den/d2) * (other.num/d1))
def __radd__(self, other): return other.__add__(self)
def __rsub__(self, other): return other.__sub__(self)
def __rmul__(self, other): return other.__mul__(self)
def __rdiv__(self, other): return other.__div__(self)
def gcd(a, b):
while b:
a, b = b, a % b
return a
class ContinuedFraction:
def __init__(self, value, tolerance):
integer = int(value)
residual = value - integer
self.integers = [integer]
while residual != 0 and abs(value - self.simplify()) > tolerance:
residual = 1 / residual
integer = int(residual)
residual = residual - integer
self.integers.insert(0, integer)
def __repr__(self):
import string
text = map(str, self.integers)
text.reverse()
return string.join(text, '+1/(') + ')' * (len(self.integers) - 1)
def simplify(self):
num, den = 1, 0
for integer in self.integers:
num, den = integer * num + den, num
return SimplifiedFraction(num, den)
--
François Pinard http://www.iro.umontreal.ca/~pinard
More information about the Python-list
mailing list