]> git.donarmstrong.com Git - lilypond.git/blobdiff - python/rational.py
lilypond-manuals.css: edit color scheme and some spacing
[lilypond.git] / python / rational.py
index fc6fd169b5084390d1cdf7b9abc43dff0a0f36f6..f2d8360fb8004e4eb1b67ba8bec768dad08e2cd8 100644 (file)
@@ -2,7 +2,6 @@
 
 from __future__ import division
 
-import decimal as _decimal
 import math as _math
 
 def _gcf(a, b):
@@ -39,18 +38,23 @@ class Rational(object):
            raise TypeError('denominator must have integer type')
        if not denominator:
            raise ZeroDivisionError('rational construction')
-       # Store the fraction in reduced form as _n/_d
-       factor = _gcf(numerator, denominator)
-       self._n = numerator // factor
-       self._d = denominator // factor
+       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
+        return self._n
 
     def denominator(self):
-       return self._d
+        return self._d
 
     def __repr__(self):
         if self._d == 1:
@@ -95,8 +99,6 @@ class Rational(object):
             return Rational(self._n + self._d * other, self._d)
         elif isinstance(other, (float, complex)):
             return float(self) + other
-        elif isinstance(other, _decimal.Decimal):
-            return self.decimal() + other
         else:
             return NotImplemented
     __radd__ = __add__
@@ -108,8 +110,6 @@ class Rational(object):
             return Rational(self._n - self._d * other, self._d)
         elif isinstance(other, (float, complex)):
             return float(self) - other
-        elif isinstance(other, _decimal.Decimal):
-            return self.decimal() - other
         else:
             return NotImplemented
     def __rsub__(self, other):
@@ -117,8 +117,6 @@ class Rational(object):
             return Rational(other * self._d - self._n, self._d)
         elif isinstance(other, (float, complex)):
             return other - float(self)
-        elif isinstance(other, _decimal.Decimal):
-            return other - self.decimal()
         else:
             return NotImplemented
     def __mul__(self, other):
@@ -128,8 +126,6 @@ class Rational(object):
             return Rational(self._n * other, self._d)
         elif isinstance(other, (float, complex)):
             return float(self) * other
-        elif isinstance(other, _decimal.Decimal):
-            return self.decimal() * other
         else:
             return NotImplemented
     __rmul__ = __mul__
@@ -140,8 +136,6 @@ class Rational(object):
             return Rational(self._n, self._d * other)
         elif isinstance(other, (float, complex)):
             return float(self) / other
-        elif isinstance(other, _decimal.Decimal):
-            return self.decimal() / other
         else:
             return NotImplemented
     __div__ = __truediv__
@@ -150,8 +144,6 @@ class Rational(object):
             return Rational(other * self._d, self._n)
         elif isinstance(other, (float, complex)):
             return other / float(self)
-        elif isinstance(other, _decimal.Decimal):
-            return other / self.decimal()
         else:
             return NotImplemented
     __rdiv__ = __rtruediv__
@@ -184,9 +176,6 @@ class Rational(object):
                 return float(self) ** other
     def __rpow__(self, other):
         return other ** float(self)
-    def decimal(self):
-        """Return a Decimal approximation of self in the current context."""
-        return _decimal.Decimal(self._n) / _decimal.Decimal(self._d)
     def round(self, denominator):
         """Return self rounded to nearest multiple of 1/denominator."""
         int_part, frac_part = divmod(self * denominator, 1)
@@ -198,65 +187,60 @@ class Rational(object):
         else:
            numerator = int_part + 1
         return Rational(numerator, denominator)
-    @staticmethod
-    def 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)
-    @staticmethod
-    def from_exact_decimal(x):
-        """Returns the exact Rational equivalent of x."""
-        sign, mantissa, exponent = x.as_tuple()
-        sign = (1, -1)[sign]
-        mantissa = sign * reduce(lambda a, b: 10 * a + b, mantissa)
-        if exponent < 0:
-            return Rational(mantissa, 10 ** (-exponent))
-        else:
-            return Rational(mantissa * 10 ** exponent)
-    @staticmethod
-    def approx_smallest_denominator(x, tolerance):
-        """
-        Returns a Rational approximation of x.
-        Minimizes the denominator given a constraint on the error.
-        
-        x = the float or Decimal value to convert
-        tolerance = maximum absolute error allowed,
-                    must be of the same type as x
-        """
-        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
-    @staticmethod
-    def approx_smallest_error(x, maxDenominator):
-        """
-        Returns a Rational approximation of x.
-        Minimizes the error given a constraint on the denominator.
-        
-        x = the float or Decimal value to convert
-        maxDenominator = maximum denominator allowed
-        """
-        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 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):
+    """
+    Returns a Rational approximation of x.
+    Minimizes the denominator given a constraint on the error.
+
+    x = the float or Decimal value to convert
+    tolerance = maximum absolute error allowed,
+                must be of the same type as x
+    """
+    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):
+    """
+    Returns a Rational approximation of x.
+    Minimizes the error given a constraint on the denominator.
+
+    x = the float or Decimal value to convert
+    maxDenominator = maximum denominator allowed
+    """
+    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."""