My Rational class code:

from __future__ import division

import math as _math

def _gcf(a, b):
    # Returns the greatest common factor of a and b.
    a = abs(a)
    b = abs(b)
    while b:
        a, b = b, a % b
    return a

class Rational(object):

    def __init__(self, numerator=0, denominator=1):
       # Contructs the Rational object for numerator/denominator.
       if not isinstance(numerator, (int)):
           raise TypeError("Numerator must have integer type.")
       if not isinstance(denominator, (int)):
           raise TypeError("Denominator must have integer type.")
       if not denominator:
           raise ZeroDivisionError('rational construction')
       self._d = denominator
       self._n = numerator
       self.normalize_self()
    # Cancel the fraction to reduced form
    def normalize_self(self):
       factor = _gcf(self._n, self._d)
       self._n = self._n // factor
       self._d = self._d // factor
       if self._d < 0:
           self._n = -self._n
           self._d = -self._d

    def numerator(self):
        return self._n

    def denominator(self):
        return self._d

    def __repr__(self):
        if self._d == 1:
            return "Rational(%d)" % self._n
        else:
            return "Rational(%d, %d)" % (self._n, self._d)
    def __str__(self):
        if self._d == 1:
            return str(self._n)
        else:
            return "%d/%d" % (self._n, self._d)
    def __lt__(self, other):
        selfNum = self._n * other._d
        otherNum = other._n * self._d
    def __hash__(self):
        try:
            return hash(float(self))
        except OverflowError:
            return hash(self)
    def __float__(self):
        return self._n / self._d
    def __int__(self):
        if self._n < 0:
            return -int(-self._n // self._d)
        else:
            return int(self._n // self._d)
    def __long__(self):
        return int(self)
    def __nonzero__(self):
        return bool(self._n)
    def __pos__(self):
        return self
    def __neg__(self):
        return Rational(-self._n, self._d)
    def __abs__(self):
        if self._n < 0:
            return -self
        else:
            return self
    def __add__(self, other):
        if isinstance(other, Rational):
            return Rational(self._n * other._d + self._d * other._n,
                            self._d * other._d)
        elif isinstance(other, (int)):
            return Rational(self._n + self._d * other, self._d)
        elif isinstance(other, (float, complex)):
            return float(self) + other
        else:
            return NotImplemented
    __radd__ = __add__
    def __sub__(self, other):
        if isinstance(other, Rational):
            return Rational(self._n * other._d - self._d * other._n,
                            self._d * other._d)
        elif isinstance(other, (int)):
            return Rational(self._n - self._d * other, self._d)
        elif isinstance(other, (float, complex)):
            return float(self) - other
        else:
            return NotImplemented
    def __rsub__(self, other):
        if isinstance(other, (int)):
            return Rational(other * self._d - self._n, self._d)
        elif isinstance(other, (float, complex)):
            return other - float(self)
        else:
            return NotImplemented
    def __mul__(self, other):
        if isinstance(other, Rational):
            return Rational(self._n * other._n, self._d * other._d)
        elif isinstance(other, (int)):
            return Rational(self._n * other, self._d)
        elif isinstance(other, (float, complex)):
            return float(self) * other
        else:
            return NotImplemented
    __rmul__ = __mul__
    def __truediv__(self, other):
        if isinstance(other, Rational):
            return Rational(self._n * other._d, self._d * other._n)
        elif isinstance(other, (int)):
            return Rational(self._n, self._d * other)
        elif isinstance(other, (float, complex)):
            return float(self) / other
        else:
            return NotImplemented
    __div__ = __truediv__
    def __rtruediv__(self, other):
        if isinstance(other, (int)):
            return Rational(other * self._d, self._n)
        elif isinstance(other, (float, complex)):
            return other / float(self)
        else:
            return NotImplemented
    __rdiv__ = __rtruediv__
    def __floordiv__(self, other):
        truediv = self / other
        if isinstance(truediv, Rational):
            return truediv._n // truediv._d
        else:
            return truediv // 1
    def __rfloordiv__(self, other):
        return (other / self) // 1
    def __mod__(self, other):
        return self - self // other * other
    def __rmod__(self, other):
        return other - other // self * self
    def __divmod__(self, other):
        return self // other, self % other
    def __cmp__(self, other):
        if other == 0:
            return cmp(self._n, 0)
        else:
            return cmp(self - other, 0)
    def __pow__(self, other):
        if isinstance(other, (int)):
            if other < 0:
                return Rational(self._d ** -other, self._n ** -other)
            else:
                return Rational(self._n ** other, self._d ** other)
        else:
                return float(self) ** other
    def __rpow__(self, other):
        return other ** float(self)
    def round(self, denominator):
        # Return self rounded to nearest multiple of 1/denominator.
        int_part, frac_part = divmod(self * denominator, 1)
        round_direction = cmp(frac_part * 2, 1)
        if round_direction == 0:
           numerator = int_part + (int_part & 1) # round to even
        elif round_direction < 0:
           numerator = int_part
        else:
           numerator = int_part + 1
        return Rational(numerator, denominator)



def rational_from_exact_float(x):
    # Returns the exact Rational equivalent of x.
    mantissa, exponent = _math.frexp(x)
    mantissa = int(mantissa * 2 ** 53)
    exponent -= 53
    if exponent < 0:
        return Rational(mantissa, 2 ** (-exponent))
    else:
        return Rational(mantissa * 2 ** exponent)



def rational_approx_smallest_denominator(x, tolerance):
    tolerance = abs(tolerance)
    n = 1
    while True:
        m = int(round(x * n))
        result = Rational(m, n)
        if abs(result - x) < tolerance:
            return result
        n += 1


def rational_approx_smallest_error(x, maxDenominator):
    result = None
    minError = x
    for n in xrange(1, maxDenominator + 1):
        m = int(round(x * n))
        r = Rational(m, n)
        error = abs(r - x)
        if error == 0:
            return r
        elif error < minError:
            result = r
            minError = error
    return result

def divide(x, y):
    # Same as x/y, but returns a Rational if both are ints.
    if isinstance(x, (int)) and isinstance(y, (int)):
        return Rational(x, y)
    else:
        return x / y

I have this:

third = Rational(25, 10)
    print ("third: {0}/{1}".format(third.numerator, third.denominator))

and it returns as an error of a sort: third: <bound method Rational.numerator of Rational(5, 2)>/<bound method Rational.denominator of Rational(5, 2)>

Not sure why that is?

And also, if the Rational number ends up being a whole number, how do I still make it a fraction? (If it equals 4, how to get it to say 4/1)

Recommended Answers

All 8 Replies

Here you have the opposite problem from what you had before: because these are methods rather that properties, you need the parenthese after them in order to call the methods.

Without the parentheses, it becomes a reference to the method itself, not a method call.

Gotcha, makes sense, thank you.

As for making a whole number a fraction, how would I go about doing that?

Oh, you simply make the number the numerator and set the denominator to 1.

def __init__(self, numerator=0, denominator=1):

I do have it equal to 1, unless that's not the spot?

Yes, that's the right spot; that sets the default value for the denominator to one. If you pass just the numerator value, you should get the right result.

whole_number_rat = Rational(3)

Should result in whole_number_rat referring to the object Rational(3, 1).

second = Rational(4)
print ("second: ", second)

When I run this, it just gives me 4, not 4/1.

Which is exactly what you wrote in the str() method:

    def __str__(self):
        if self._d == 1:
            return str(self._n)
        else:
            return "%d/%d" % (self._n, self._d)
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.