# GNU Solfege - ear training for GNOME
# Copyright (C) 2000, 2001, 2002, 2003, 2004  Tom Cato Amundsen
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

def gcd(a, b):
    while b:
        a, b = b, a % b
    return a

class Rat(object):
    __slots__ = ('m_num', 'm_den')
    """
    This is NOT a generic rational number class, it includes
    only the features needed for the the soundcard and mpd
    module included in Solfege.
    """
    def __init__(self, num, den=1):
        assert isinstance(num, int)
        assert isinstance(den, int)
        self.m_num = num
        self.m_den = den
    def __repr__(self):
        return "(Rat %i/%i)" % (self.m_num, self.m_den)
    def __str__(self):
        return "(Rat %i/%i)" % (self.m_num, self.m_den)
    def __add__(self, B):
        assert isinstance(self, Rat)
        assert isinstance(B, Rat)
        a = self.m_num * B.m_den + B.m_num * self.m_den
        b = self.m_den * B.m_den
        g = gcd(a, b)
        return Rat(a/g, b/g)
    def __sub__(self, B):
        assert isinstance(self, Rat)
        assert isinstance(B, Rat)
        a = (self.m_num * B.m_den - B.m_num * self.m_den)
        b = self.m_den * B.m_den
        g = gcd(a, b)
        return Rat(a/g, b/g)
    def __mul__(self, B):
        assert isinstance(self, Rat)
        if type(B) == type(0):
            g = gcd(self.m_num*B, self.m_den)
            return Rat(self.m_num*B/g, self.m_den/g)
        assert isinstance(B, Rat)
        g = gcd(self.m_num*B.m_num, self.m_den*B.m_den)
        return Rat(self.m_num*B.m_num/g, self.m_den*B.m_den/g)
    def __rdiv__(self, B):
        """ called when integer / Rat
        """
        assert isinstance(B, int)
        assert isinstance(self, Rat)
        a = B * self.m_den
        b = self.m_num
        g = gcd(a, b)
        return Rat(a/g, b/g)
    def __rmul__(self, B):
        """ called when integer * Rat
        """
        assert isinstance(self, Rat)
        assert isinstance(B, int)
        a = self.m_num * B
        g = gcd(a, self.m_den)
        return Rat(a/g, self.m_den/g)
    def __int__(self):
        return self.m_num / self.m_den
    def __hash__(self):
        return hash((self.m_num, self.m_den))
    def __cmp__(self, B):
        return cmp(1.0*self.m_num/self.m_den, 1.0*B.m_num/B.m_den)

if __name__ == "__main__":
    A = Rat(3, 4)
    B = Rat(1, 4)
    print "%s+%s=%s" % (A, B, A+B)
    print "A-B", A-B
    print "A, B", A, B
    print "A*B", A*B
    print "1/A", 1/A
    print "2*A", 2*A
