Integer approximation to M*log(x/M), with absolute error boundable in terms only of x/M. Given positive integers x and M, return an integer approximation to M * log(x/M). For L = 8 and 0.1 <= x/M <= 10 the difference between the approximation and the exact result is at most 22
(x, M, L = 8)
| 5736 | return q + (2*r + (q&1) > b) |
| 5737 | |
| 5738 | def _ilog(x, M, L = 8): |
| 5739 | """Integer approximation to M*log(x/M), with absolute error boundable |
| 5740 | in terms only of x/M. |
| 5741 | |
| 5742 | Given positive integers x and M, return an integer approximation to |
| 5743 | M * log(x/M). For L = 8 and 0.1 <= x/M <= 10 the difference |
| 5744 | between the approximation and the exact result is at most 22. For |
| 5745 | L = 8 and 1.0 <= x/M <= 10.0 the difference is at most 15. In |
| 5746 | both cases these are upper bounds on the error; it will usually be |
| 5747 | much smaller.""" |
| 5748 | |
| 5749 | # The basic algorithm is the following: let log1p be the function |
| 5750 | # log1p(x) = log(1+x). Then log(x/M) = log1p((x-M)/M). We use |
| 5751 | # the reduction |
| 5752 | # |
| 5753 | # log1p(y) = 2*log1p(y/(1+sqrt(1+y))) |
| 5754 | # |
| 5755 | # repeatedly until the argument to log1p is small (< 2**-L in |
| 5756 | # absolute value). For small y we can use the Taylor series |
| 5757 | # expansion |
| 5758 | # |
| 5759 | # log1p(y) ~ y - y**2/2 + y**3/3 - ... - (-y)**T/T |
| 5760 | # |
| 5761 | # truncating at T such that y**T is small enough. The whole |
| 5762 | # computation is carried out in a form of fixed-point arithmetic, |
| 5763 | # with a real number z being represented by an integer |
| 5764 | # approximation to z*M. To avoid loss of precision, the y below |
| 5765 | # is actually an integer approximation to 2**R*y*M, where R is the |
| 5766 | # number of reductions performed so far. |
| 5767 | |
| 5768 | y = x-M |
| 5769 | # argument reduction; R = number of reductions performed |
| 5770 | R = 0 |
| 5771 | while (R <= L and abs(y) << L-R >= M or |
| 5772 | R > L and abs(y) >> R-L >= M): |
| 5773 | y = _div_nearest((M*y) << 1, |
| 5774 | M + _sqrt_nearest(M*(M+_rshift_nearest(y, R)), M)) |
| 5775 | R += 1 |
| 5776 | |
| 5777 | # Taylor series with T terms |
| 5778 | T = -int(-10*len(str(M))//(3*L)) |
| 5779 | yshift = _rshift_nearest(y, R) |
| 5780 | w = _div_nearest(M, T) |
| 5781 | for k in range(T-1, 0, -1): |
| 5782 | w = _div_nearest(M, k) - _div_nearest(yshift*w, M) |
| 5783 | |
| 5784 | return _div_nearest(w*y, M) |
| 5785 | |
| 5786 | def _dlog10(c, e, p): |
| 5787 | """Given integers c, e and p with c > 0, p >= 0, compute an integer |
no test coverage detected