- File:
-
- 1 edited
-
sage/rings/real_mpfr.pyx (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
sage/rings/real_mpfr.pyx
r4122 r4120 1578 1578 return intv.simplest_rational(low_open = True) 1579 1579 1580 def nearby_rational(self, max_error=None, max_denominator=None):1581 """1582 Find a rational near to self. Exactly one of max_error1583 or max_denominator must be specified. If max_error is specified,1584 then this returns the simplest rational in the range1585 [self-max_error .. self+max_error]. If max_denominator is1586 specified, then this returns the rational closest to self with1587 denominator at most max_denominator. (In case of ties, we1588 pick the simpler rational.)1589 1590 EXAMPLES:1591 sage: (0.333).nearby_rational(max_error=0.001)1592 1/31593 sage: (0.333).nearby_rational(max_error=1)1594 01595 sage: (-0.333).nearby_rational(max_error=0.0001)1596 -257/7721597 1598 sage: (0.333).nearby_rational(max_denominator=100)1599 1/31600 sage: RR(1/3 + 1/1000000).nearby_rational(max_denominator=2999999)1601 777780/23333331602 sage: RR(1/3 + 1/1000000).nearby_rational(max_denominator=3000000)1603 1000003/30000001604 sage: (-0.333).nearby_rational(max_denominator=1000)1605 -333/10001606 sage: RR(3/4).nearby_rational(max_denominator=2)1607 11608 sage: RR(pi).nearby_rational(max_denominator=120)1609 355/1131610 sage: RR(pi).nearby_rational(max_denominator=10000)1611 355/1131612 sage: RR(pi).nearby_rational(max_denominator=100000)1613 312689/995321614 sage: RR(pi).nearby_rational(max_denominator=1)1615 31616 sage: RR(-3.5).nearby_rational(max_denominator=1)1617 -31618 """1619 if ((max_error is None and max_denominator is None) or1620 (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 RealIntervalField1625 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_r1642 1643 if sgn < 0:1644 self_r = -self_r1645 1646 cdef Integer fl = self_r.floor()1647 cdef Rational target = self_r - fl1648 1649 cdef int low_done = 01650 cdef int high_done = 01651 1652 # We use the Stern-Brocot tree to find the nearest neighbors of1653 # self with denominator at most max_denominator. However,1654 # navigating the Stern-Brocot tree in the straightforward way1655 # can be very slow; for instance, to get to 1/1000000 takes a1656 # million steps. Instead, we perform many steps at once;1657 # this probably slows down the average case, but it drastically1658 # speeds up the worst case.1659 1660 # Suppose we have a/b < c/d < e/f, where a/b and e/f are1661 # neighbors in the Stern-Brocot tree and c/d is the target.1662 # We alternate between moving the low and the high end toward1663 # the target as much as possible. Suppose that there are1664 # k consecutive rightward moves in the Stern-Brocot tree1665 # traversal; then we end up with (a+k*e)/(b+k*f). We have1666 # 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/d1669 # d*a + k*(d*e) <= c*b + k*(c*f)1670 # k*(d*e) - k*(c*f) <= c*b - d*a1671 # k <= (c*b - d*a)/(d*e - c*f)1672 # when moving the high side, we get1673 # (k*a+e)/(k*b+f) >= c/d1674 # k*(d*a) + d*e >= k*(c*b) + c*f1675 # 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; this1679 # gives (b+k*f) <= max_denominator or1680 # k <= (max_denominator - b)/f1681 # or1682 # k <= (max_denominator - f)/b1683 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 k1694 1695 while (not low_done) or (not high_done):1696 # Move the low side1697 k = (c*b - d*a) // (d*e - c*f)1698 1699 if b+k*f > max_denominator:1700 k = (max_denominator - b) // f1701 low_done = True1702 1703 if k == 0:1704 low_done = True1705 1706 a = a + k*e1707 b = b + k*f1708 1709 # Move the high side1710 k = (d*e - c*f) // (c*b - d*a)1711 1712 if k*b + f >= max_denominator:1713 k = (max_denominator - f) // b1714 high_done = True1715 1716 if k == 0:1717 high_done = True1718 1719 e = k*a + e1720 f = k*b + f1721 1722 # Now a/b and e/f are rationals surrounding c/d. We know that1723 # neither is equal to c/d, since d > max_denominator and1724 # b and f are both <= max_denominator. (We know that1725 # d > max_denominator because we return early (before we1726 # get here) if d <= max_denominator.)1727 1728 low = a/b1729 high = e/f1730 1731 cdef int compare = cmp(target - low, high - target)1732 1733 if compare > 0:1734 result = high1735 elif compare < 0:1736 result = low1737 else:1738 compare = cmp(b, f)1739 if compare > 0:1740 result = high1741 elif compare < 0:1742 result = low1743 else:1744 compare = cmp(a, e)1745 if compare > 0:1746 result = high1747 else:1748 result = low1749 1750 result = fl + result1751 1752 if sgn < 0:1753 return -result1754 return result1755 1756 1580 1757 1581 ###########################################
Note: See TracChangeset
for help on using the changeset viewer.
