Gosper arithmetic in Python

Subscriber123 subscriber123 at gmail.com
Mon Feb 12 20:36:56 EST 2007


Speaking of useful home-made modules, I wrote this primitive module which
does limited math with fractions. Anyone is welcome to expand on it or use
it for any purpose. If anyone would like to submit it as a PEP to be added
to the Python library of reference, that would be great. If anyone wishes to
do that, I ask that you at least add me as a coauthor.

Collin Stocks

On 2/12/07, Marcin Ciura <marcin.ciura at poczta.nospamonet.pl> wrote:
>
> Hello,
>
> I hacked together a module implementing exact real
> arithmetic via lazily evaluated continued fractions.
> You can download it from
> http://www-zo.iinf.polsl.gliwice.pl/~mciura/software/cf.py
> an use as an almost drop-in replacement for the math module
> if you don't care too much about performance.
> I'd be happy to hear any feedback and suggestions.
>
> Cheers,
>    Marcin
> --
> http://mail.python.org/mailman/listinfo/python-list
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20070212/2de641f6/attachment.html>
-------------- next part --------------
from math import sqrt

class Fract(object):
    def __init__(self,*args):
        if len(args)==2:
            self.num,self.den=map(int,args)
        if len(args)==1:
            try:self.num,self.den=args[0].num,args[0].den
            except:self.num,self.den=int(args[0]),int(1)

    def __abs__(self):
        return Fract(abs(self.num),abs(self.den))

    def __add__(self,other):
        other=Fract(other)
        x=self.change_den(self,other.den)
        y=self.change_den(other,self.den)
        return Fract(x.num+y.num,x.den)

    def __sub__(self,other):
        other=Fract(other)
        x=self.change_den(self,other.den)
        y=self.change_den(other,self.den)
        return Fract(x.num-y.num,x.den)

    def __div__(self,other):
        other=Fract(other)
        return Fract(self*self.invert(other))

    def __mul__(self,other):
        other=Fract(other)
        return Fract(self.num*other.num,self.den*other.den)

    def __gt__(self,other):
        return float(self)>float(other)

    def __lt__(self,other):
        return float(self)<float(other)

    def __ge__(self,other):
        return float(self)>=float(other)

    def __le__(self,other):
        return float(self)<=float(other)

    def __eq__(self,other):
        return float(self)==float(other)

    def __pow__(self,exp):
        x=self
        for i in range(1,exp):
            x=x*self
        return x

    def __float__(self):
        return float(self.num)/float(self.den)

    def __int__(self):
        return self.num/self.den

    def __str__(self):
        #print>>s,"string:",self.num,self.den
        self.simplify()
        return "%s/%s"%(self.num,self.den)

    def __repr__(self):
        #print>>s,"string:",self.num,self.den
        self.simplify()
        return "Fract(%s,%s)"%(self.num,self.den)

    def simplify(self):
        self.num,self.den=reduce(self.num,self.den)
        """
        debug=[]
        debug.append((self.num,self.den))
        for i in [self.num,self.den,2,3,5,7]:
            while self.num%i==0 and self.den%i==0 and self.num!=1 and self.den!=1:
                self.num/=i
                self.den/=i
        for i in xrange(11,int(sqrt(self.den))+3,2):
            while self.num%i==0 and self.den%i==0:
                self.num/=i
                self.den/=i
        if self.num==self.den!=1:
            print debug
            raise "the end"
        """

    def invert(self,fraction):
        fraction=Fract(fraction)
        return Fract(fraction.den,fraction.num)

    def change_den(self,fraction,mult):
        return Fract(fraction.num*mult,fraction.den*mult)

    def scale(*args):
        mul=float(args[0])
        args=list(args)
        length=len(args)
        dens=[]
        for arg in args:
            dens.append(arg.den)
        #print>>s,args
        for i in range(length):
            for j in range(length):
                if not i==j:
                    args[i].num*=dens[j]
                    args[i].den*=dens[j]
        nums=[]
        for arg in args:nums.append(arg.num)
        args=map(Fract,reduce(*nums))
        #print>>s,args
        mul=float(args[0])/mul
        args.append(mul)
        #print>>s,args[0].den==args[1].den==args[2].den
        return args
        """
        for j in range(len(args)):
            args2=list(args)
            for i in range(len(args)):
                #print>>s,i,j
                #print>>s,args,args2
                args[i]*=args2[j].den
                dens=[]
                for arg in args:dens.append(arg.den)
                dens=reduce(*dens)
                for i in range(len(dens)):args[i].den=dens[i]
                #print>>s,args,args2
                ##args[i].simplify()
        return args
        """

def reduce(*args):
    args=list(args)
    for i in [min(args),2,3,5,7]:
        divisible=True
        for j in range(len(args)):divisible=(divisible and (args[j]%i==0))
        #print>>s,divisible,args,i
        if args[0]!=int(args[0]):
            raise Warning
        while divisible and min(args)!=1:
            for loc in range(len(args)):args[loc]/=i
            for j in range(len(args)):divisible=(divisible and (args[j]%i==0))
    for i in xrange(11,int(sqrt(min(args)))+3,2):
        divisible=True
        for j in range(len(args)):divisible=(divisible and (args[j]%i==0))
        while divisible and min(args)!=1:
            for loc in range(len(args)):args[loc]/=i
            for j in range(len(args)):divisible=(divisible and (args[j]%i==0))
    return args

import sys
s=sys.__stdout__


More information about the Python-list mailing list