Given integers x and M, M > 0, such that x/M is small in absolute value, compute an integer approximation to M*exp(x/M). For 0 <= x/M <= 2.4, the absolute error in the result is bounded by 60 (and is usually much smaller).
(x, M, L=8)
| 5866 | _log10_digits = _Log10Memoize().getdigits |
| 5867 | |
| 5868 | def _iexp(x, M, L=8): |
| 5869 | """Given integers x and M, M > 0, such that x/M is small in absolute |
| 5870 | value, compute an integer approximation to M*exp(x/M). For 0 <= |
| 5871 | x/M <= 2.4, the absolute error in the result is bounded by 60 (and |
| 5872 | is usually much smaller).""" |
| 5873 | |
| 5874 | # Algorithm: to compute exp(z) for a real number z, first divide z |
| 5875 | # by a suitable power R of 2 so that |z/2**R| < 2**-L. Then |
| 5876 | # compute expm1(z/2**R) = exp(z/2**R) - 1 using the usual Taylor |
| 5877 | # series |
| 5878 | # |
| 5879 | # expm1(x) = x + x**2/2! + x**3/3! + ... |
| 5880 | # |
| 5881 | # Now use the identity |
| 5882 | # |
| 5883 | # expm1(2x) = expm1(x)*(expm1(x)+2) |
| 5884 | # |
| 5885 | # R times to compute the sequence expm1(z/2**R), |
| 5886 | # expm1(z/2**(R-1)), ... , exp(z/2), exp(z). |
| 5887 | |
| 5888 | # Find R such that x/2**R/M <= 2**-L |
| 5889 | R = _nbits((x<<L)//M) |
| 5890 | |
| 5891 | # Taylor series. (2**L)**T > M |
| 5892 | T = -int(-10*len(str(M))//(3*L)) |
| 5893 | y = _div_nearest(x, T) |
| 5894 | Mshift = M<<R |
| 5895 | for i in range(T-1, 0, -1): |
| 5896 | y = _div_nearest(x*(Mshift + y), Mshift * i) |
| 5897 | |
| 5898 | # Expansion |
| 5899 | for k in range(R-1, -1, -1): |
| 5900 | Mshift = M<<(k+2) |
| 5901 | y = _div_nearest(y*(y+Mshift), Mshift) |
| 5902 | |
| 5903 | return M+y |
| 5904 | |
| 5905 | def _dexp(c, e, p): |
| 5906 | """Compute an approximation to exp(c*10**e), with p decimal places of |
no test coverage detected
searching dependent graphs…