root / trunk / sandbox / jhb / fraction.py

Revision 184, 4.1 kB (checked in by ocjhb, 4 years ago)

now comparing to floats

Line 
1"""The fraction class. It converts ints and strings to fractions."""
2
3# helper functions
4def gcd(a, b):
5    if b == 0:
6        return a
7
8    return gcd(b, a % b)
9
10def lcm(a, b):
11    return a * b / gcd(a, b)
12
13class Fraction:
14    def __init__(self, val,denominator=None):
15        import types
16
17        if isinstance(val, self.__class__):
18            self.num = val.num
19            self.den = val.den
20
21            #self.reduce()
22
23
24        elif denominator:
25            self.num = int(val)
26            self.den = int(denominator)
27
28        elif isinstance(val, types.StringType):
29            if val.count('/') == 1:
30                num, den = val.split('/')
31                self.num, self.den = int(num), int(den)
32
33                if self.den == 0:
34                    raise ZeroDenominatorError()
35
36                if self.den < 0: # Move negative denominator to the numerator
37                    self.num, self.den = -self.num, -self.den
38
39            else:
40                self.num = int(val)
41                self.den = 1
42
43        elif isinstance(val, types.IntType) or isinstance(val, types.LongType):
44            self.num = val
45            self.den = 1
46
47        elif isinstance(val, types.TupleType):
48            self.num, self.den = val
49
50            if not isinstance(self.num, types.IntType) or isinstance(self.num, types.LongType):
51                raise Exception()
52
53            if not isinstance(self.den, types.IntType) or isinstance(self.den, types.LongType):
54                raise Exception()
55
56            if self.den < 0: # Move negative denominator to the numberator
57                self.num, self.den = -self.num, -self.den
58
59        # TODO: optionally, float conversion?
60
61        else:
62            raise Exception('%s' % val)
63            raise NotImplementedError()
64
65        #self.reduce()
66
67    def __add__(self, other):
68        if not isinstance(other, Fraction):
69            other = Fraction(other)
70
71        new = Fraction((((self.num * other.den) + (other.num * self.den)), (self.den * other.den)))
72       
73        return new.reduce()
74
75
76    def __sub__(self, other):
77        copy = Fraction(other)
78        copy.num = -copy.num
79
80        return self + copy
81
82    def __mul__(self, other):
83        if not isinstance(other, Fraction):
84            other = Fraction(other)
85
86        new = Fraction(( (self.num * other.num), (self.den * other.den) ))
87
88        return new.reduce()
89
90
91    def __div__(self, other):
92        if not isinstance(other, Fraction):
93            other = Fraction(other)
94
95        new = Fraction(( other.den, other.num )) # Inverse of other
96           
97        return self * new
98
99    def reduce(self):
100        """Reduce reduces a fraction to it's smallest numerator and denominator."""
101
102        if self.den == 0:
103            raise ZeroDenominatorError()
104
105        divisor = gcd(self.num, self.den)
106
107        num = self.num / divisor
108        den = self.den / divisor
109
110        return Fraction(num,den)
111
112    def __str__(self):
113        if self.den != 1:
114            return "%s/%s" % (self.num, self.den)
115        else:
116            return "%s" % (self.num)
117
118    def __repr__(self):
119        return "<Fraction: %s>" % str(self)
120
121    def __eq__(self, other):
122        if not isinstance(other, Fraction):
123            other = Fraction(other)
124
125        return self.num == other.num and self.den == other.den
126
127    def __cmp__(self, other):
128        import types
129        if type(other) == types.FloatType:
130            return cmp(self.float(),other)
131
132        elif not isinstance(other, Fraction):
133            other = Fraction(other)
134
135        common = lcm(self.den, other.den)
136
137        self_num = self.num * common / self.den
138        other_num = other.num * common / other.den
139
140        return self_num.__cmp__(other_num)
141
142    def __gt__(self, other):
143        return self.__cmp__(other) == 1
144
145    def __lt__(self, other):
146        return self.__cmp__(other) == -1
147
148    def __ne__(self, other):
149        return not self == other
150
151    def __hash__(self):
152        return str(self).__hash__()
153   
154    def float(self):
155        return float(self.num)/float(self.den)
156
157class ZeroDenominatorError(Exception):
158    """A fraction with a zero denominator cannot be computed."""
Note: See TracBrowser for help on using the browser.