Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • sage/rings/real_mpfr.pyx

    r4122 r4120  
    15781578            return intv.simplest_rational(low_open = True) 
    15791579         
    1580     def nearby_rational(self, max_error=None, max_denominator=None): 
    1581         """ 
    1582         Find a rational near to self.  Exactly one of max_error 
    1583         or max_denominator must be specified.  If max_error is specified, 
    1584         then this returns the simplest rational in the range 
    1585         [self-max_error .. self+max_error].  If max_denominator is 
    1586         specified, then this returns the rational closest to self with 
    1587         denominator at most max_denominator.  (In case of ties, we 
    1588         pick the simpler rational.) 
    1589  
    1590         EXAMPLES: 
    1591             sage: (0.333).nearby_rational(max_error=0.001) 
    1592             1/3 
    1593             sage: (0.333).nearby_rational(max_error=1) 
    1594             0 
    1595             sage: (-0.333).nearby_rational(max_error=0.0001) 
    1596             -257/772 
    1597  
    1598             sage: (0.333).nearby_rational(max_denominator=100) 
    1599             1/3 
    1600             sage: RR(1/3 + 1/1000000).nearby_rational(max_denominator=2999999) 
    1601             777780/2333333 
    1602             sage: RR(1/3 + 1/1000000).nearby_rational(max_denominator=3000000) 
    1603             1000003/3000000 
    1604             sage: (-0.333).nearby_rational(max_denominator=1000) 
    1605             -333/1000 
    1606             sage: RR(3/4).nearby_rational(max_denominator=2) 
    1607             1 
    1608             sage: RR(pi).nearby_rational(max_denominator=120) 
    1609             355/113 
    1610             sage: RR(pi).nearby_rational(max_denominator=10000) 
    1611             355/113 
    1612             sage: RR(pi).nearby_rational(max_denominator=100000) 
    1613             312689/99532 
    1614             sage: RR(pi).nearby_rational(max_denominator=1) 
    1615             3 
    1616             sage: RR(-3.5).nearby_rational(max_denominator=1) 
    1617             -3 
    1618         """ 
    1619         if ((max_error is None and max_denominator is None) or 
    1620             (max_error is not None and max_denominator is not None)): 
    1621             raise ValueError, 'Must specify exactly one of max_error or max_denominator in nearby_rational()' 
    1622  
    1623         if max_error is not None: 
    1624             from real_mpfi import RealIntervalField 
    1625  
    1626             intv_field = RealIntervalField(self.prec()) 
    1627             intv = intv_field(self - max_error, self + max_error) 
    1628  
    1629             return intv.simplest_rational() 
    1630  
    1631         cdef int sgn = mpfr_sgn(self.value) 
    1632  
    1633         if sgn == 0: 
    1634             return Rational(0) 
    1635  
    1636         cdef Rational self_r = self.exact_rational() 
    1637  
    1638         cdef Integer self_d = self_r.denominator() 
    1639  
    1640         if self_d <= max_denominator: 
    1641             return self_r 
    1642  
    1643         if sgn < 0: 
    1644             self_r = -self_r 
    1645  
    1646         cdef Integer fl = self_r.floor() 
    1647         cdef Rational target = self_r - fl 
    1648  
    1649         cdef int low_done = 0 
    1650         cdef int high_done = 0 
    1651  
    1652         # We use the Stern-Brocot tree to find the nearest neighbors of 
    1653         # self with denominator at most max_denominator.  However, 
    1654         # navigating the Stern-Brocot tree in the straightforward way 
    1655         # can be very slow; for instance, to get to 1/1000000 takes a 
    1656         # million steps.  Instead, we perform many steps at once; 
    1657         # this probably slows down the average case, but it drastically 
    1658         # speeds up the worst case. 
    1659  
    1660         # Suppose we have a/b < c/d < e/f, where a/b and e/f are 
    1661         # neighbors in the Stern-Brocot tree and c/d is the target. 
    1662         # We alternate between moving the low and the high end toward 
    1663         # the target as much as possible.  Suppose that there are 
    1664         # k consecutive rightward moves in the Stern-Brocot tree 
    1665         # traversal; then we end up with (a+k*e)/(b+k*f).  We have 
    1666         # two constraints on k.  First, the result must be <= c/d; 
    1667         # this gives us the following: 
    1668         # (a+k*e)/(b+k*f) <= c/d 
    1669         # d*a + k*(d*e) <= c*b + k*(c*f) 
    1670         # k*(d*e) - k*(c*f) <= c*b - d*a 
    1671         # k <= (c*b - d*a)/(d*e - c*f) 
    1672         # when moving the high side, we get 
    1673         # (k*a+e)/(k*b+f) >= c/d 
    1674         # k*(d*a) + d*e >= k*(c*b) + c*f 
    1675         # d*e - c*f >= k*(c*b - d*a) 
    1676         # k <= (d*e - c*f)/(c*b - d*a) 
    1677  
    1678         # We also need the denominator to be <= max_denominator; this 
    1679         # gives (b+k*f) <= max_denominator or 
    1680         # k <= (max_denominator - b)/f 
    1681         # or 
    1682         # k <= (max_denominator - f)/b 
    1683  
    1684         # We use variables with the same names as in the math above. 
    1685  
    1686         cdef Integer a = Integer(0) 
    1687         cdef Integer b = Integer(1) 
    1688         cdef Integer c = target.numerator() 
    1689         cdef Integer d = target.denominator() 
    1690         cdef Integer e = Integer(1) 
    1691         cdef Integer f = Integer(1) 
    1692  
    1693         cdef Integer k 
    1694  
    1695         while (not low_done) or (not high_done): 
    1696             # Move the low side 
    1697             k = (c*b - d*a) // (d*e - c*f) 
    1698  
    1699             if b+k*f > max_denominator: 
    1700                 k = (max_denominator - b) // f 
    1701                 low_done = True 
    1702  
    1703             if k == 0: 
    1704                 low_done = True 
    1705  
    1706             a = a + k*e 
    1707             b = b + k*f 
    1708  
    1709             # Move the high side 
    1710             k = (d*e - c*f) // (c*b - d*a) 
    1711  
    1712             if k*b + f >= max_denominator: 
    1713                 k = (max_denominator - f) // b 
    1714                 high_done = True 
    1715  
    1716             if k == 0: 
    1717                 high_done = True 
    1718  
    1719             e = k*a + e 
    1720             f = k*b + f 
    1721  
    1722         # Now a/b and e/f are rationals surrounding c/d.  We know that 
    1723         # neither is equal to c/d, since d > max_denominator and 
    1724         # b and f are both <= max_denominator.  (We know that 
    1725         # d > max_denominator because we return early (before we 
    1726         # get here) if d <= max_denominator.) 
    1727  
    1728         low = a/b 
    1729         high = e/f 
    1730  
    1731         cdef int compare = cmp(target - low, high - target) 
    1732  
    1733         if compare > 0: 
    1734             result = high 
    1735         elif compare < 0: 
    1736             result = low 
    1737         else: 
    1738             compare = cmp(b, f) 
    1739             if compare > 0: 
    1740                 result = high 
    1741             elif compare < 0: 
    1742                 result = low 
    1743             else: 
    1744                 compare = cmp(a, e) 
    1745                 if compare > 0: 
    1746                     result = high 
    1747                 else: 
    1748                     result = low 
    1749  
    1750         result = fl + result 
    1751  
    1752         if sgn < 0: 
    1753             return -result 
    1754         return result         
    1755  
    17561580 
    17571581    ########################################### 
Note: See TracChangeset for help on using the changeset viewer.