mpmath 0.2__zip → 0.4__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,199 @@
1
+ """
2
+ This module provides functions for computing approximate square roots
3
+ (in fixed-point or floating-point form) of positive real numbers.
4
+ """
5
+
6
+ from util import *
7
+ from floatop import *
8
+
9
+
10
+ def sqrt_initial(y, prec):
11
+ """Given y = floor(x * 2**prec), compute floor(sqrt(x) * 2**50),
12
+ i.e. calculate a 50-bit approximation of the square root. This is
13
+ done quickly using regular floating-point arithmetic. It is
14
+ assumed that x ~= 1."""
15
+
16
+ # Two cases; the second avoids overflow
17
+ if prec < 200: return int(y**0.5 * 2.0**(50 - prec*0.5))
18
+ else: return int((y >> (prec-100))**0.5)
19
+
20
+
21
+ # XXX: doesn't work
22
+ def invsqrt_initial(y, prec):
23
+ """Like sqrt_initial, but computes 1/sqrt(y) instead of sqrt(y)."""
24
+ if prec < 200: return int(y**-0.5 * 2.0**(50 + prec*0.5))
25
+ else: return int((y >> (prec-100)) ** -0.5)
26
+
27
+
28
+ def sqrt_fixed(y, prec):
29
+ """
30
+ Square root of a fixed-point number.
31
+
32
+ Given the big integer y = floor(x * 2**prec), this function returns
33
+ floor(r * 2**prec) where r = sqrt(x).
34
+
35
+ We start from a 50-bit estimate for r generated with ordinary
36
+ floating-point arithmetic, and then refines the value to full
37
+ accuracy using the iteration
38
+
39
+ 1 / y \
40
+ r = --- | r + --- |
41
+ n+1 2 \ n r_n /
42
+
43
+ which is simply Newton's method applied to the equation r**2 = y.
44
+
45
+ Newton's method doubles the accuracy with each step. We make use of
46
+ this fact by only using a precision corresponding to the current
47
+ accuracy during intermediate iterations. For example, with a 50-bit
48
+ accurate r_1, r_2 can be computed using 100-bit precision, r_3
49
+ using 200-bit precision, and so on. (In practice, the precision
50
+ levels must be chosen slightly more conservatively to account for
51
+ rounding errors in the last one or two bits.)
52
+
53
+ It is assumed that x ~= 1 (the main fsqrt() function fiddles with
54
+ the exponent of the input to reduce it to unit magnitude before
55
+ passing it here.)
56
+
57
+ TODO: it would be possible to specify separate precision levels
58
+ for the input and output, which could be useful when calculating
59
+ pure-integer square roots.
60
+ """
61
+
62
+ r = sqrt_initial(y, prec)
63
+ extra = 10
64
+ prevp = 50
65
+
66
+ for p in giant_steps(50, prec+extra):
67
+
68
+ # Explanation: in the first term, we shift by the appropriate number
69
+ # of bits to convert r from the previous precision to the current one.
70
+ # The "-1" divides by two in the same step.
71
+
72
+ # In the second term, we do a fixed-point division using the usual
73
+ # formula (y<<precision)//r. The precision term is a bit messy and
74
+ # takes into account the fact that y, r_n and r_{n+1} all have
75
+ # different precision levels. As before, the "-1" divides by two.
76
+ r = lshift_quick(r, p-prevp-1) + (lshift_quick(y, p+prevp-prec-1)//r)
77
+
78
+ prevp = p
79
+
80
+ return r >> extra
81
+
82
+
83
+ def sqrt_fixed2(y, prec):
84
+ """
85
+ This function is essentially equivalent to sqrt_fixed (see its
86
+ documentation), but uses an asymptotically faster algorithm.
87
+
88
+ Instead of using Newton's method to calculate sqrt(y) directly,
89
+ we calculate 1/sqrt(y) with Newton's method and multiply by y to
90
+ obtain sqrt(y). The Newton iteration for 1/sqrt(y) is
91
+
92
+ r
93
+ n / 2 \
94
+ r = ---- * | 3 - y * r |.
95
+ n+1 2 \ n /
96
+
97
+ This is slightly slower at low precision levels since it requires
98
+ three multiplications in each step, as opposed to the single
99
+ division in the Newton iteration for sqrt(y).
100
+
101
+ However, since Python uses Karatsuba algorithm for multiplication,
102
+ three multiplications can be performed much more quickly than a
103
+ single division at high precision levels. In practice, the cutoff
104
+ where sqrt_fixed2 becomes faster than sqrt_fixed seems to be around
105
+ 60,000 bits.
106
+ """
107
+
108
+ # XXX
109
+ from mpmath.lib import to_float, normalize, ROUND_FLOOR
110
+ r = to_float(normalize(y, -prec, 64, ROUND_FLOOR)) ** -0.5
111
+ r = int(r * 2**50)
112
+
113
+ # r = invsqrt_initial(y, prec)
114
+
115
+ extra = 10
116
+ prevp = 50
117
+
118
+ for p in giant_steps(50, prec+extra):
119
+
120
+ # This is even messier than in sqrt_fixed. As many shifts as possible
121
+ # have been combined together for optimal speed, at a slight expense
122
+ # of legibility.
123
+
124
+ # Compute r**2 at precision p.
125
+ r2 = rshift_quick(r*r, 2*prevp - p)
126
+
127
+ # A = r, converted from precision prevp to p
128
+ A = lshift_quick(r, p-prevp)
129
+
130
+ # S = y * r2, computed at precision p. We shift y by '-prec' to
131
+ # account for its initial precision, and by 'p' for the fixed-point
132
+ # multiplication
133
+ S = (lshift_quick(y, p-prec) * r2) >> p
134
+
135
+ # B = (3-S) and finally the outer product, both done at precision p
136
+ B = (3<<p) - S
137
+ r = (A*B) >> (p+1)
138
+
139
+ prevp = p
140
+
141
+ # Finally, sqrt(y) = y * (1/sqrt(y))
142
+ r = (r * y) >> prec
143
+
144
+ return r >> extra
145
+
146
+
147
+
148
+
149
+ def fsqrt(s, prec, rounding):
150
+ """
151
+ Floating-point square root.
152
+
153
+ Returns a tuple representing the square root of s, rounded to the
154
+ nearest floating-point number in the specified rounding direction.
155
+ The input must be a tuple representing a nonnegative floating-point
156
+ number.
157
+ """
158
+ if s == fone:
159
+ return fone
160
+
161
+ man, exp, bc = s
162
+
163
+ if not man:
164
+ return fzero
165
+
166
+ # Convert to a fixed-point number with prec2 bits. Adjust
167
+ # exponents to be even so that they can be divided in half
168
+ prec2 = prec + 10 + (prec & 1)
169
+
170
+ if exp & 1:
171
+ exp -= 1
172
+ man <<= 1
173
+ bc += 1
174
+
175
+ # Mantissa may have more bits than we need. Trim it down.
176
+ shift = bc - prec2
177
+ shift -= shift & 1
178
+ man = rshift_quick(man, shift)
179
+
180
+ if prec < 65000:
181
+ man = sqrt_fixed(man, prec2)
182
+ else:
183
+ man = sqrt_fixed2(man, prec2)
184
+
185
+ return normalize(man, (exp+shift-prec2)>>1, prec, rounding)
186
+
187
+
188
+
189
+ def fhypot(x, y, prec, rounding):
190
+ if y == fzero:
191
+ return fabs(x, prec, rounding)
192
+ if x == fzero:
193
+ return fabs(y, prec, rounding)
194
+
195
+ RF = ROUND_FLOOR
196
+ hypot2 = fadd(fmul(x,x,prec+4,RF), fmul(y,y,prec+4,RF), prec+4, RF)
197
+
198
+ return fsqrt(hypot2, prec, rounding)
199
+
@@ -0,0 +1,268 @@
1
+ """
2
+ Contents of this module:
3
+
4
+ * Integer and bit-level operations
5
+ * Miscellaneous utilities
6
+
7
+ """
8
+
9
+ import math
10
+ import decimal
11
+
12
+ # Same as standard Python float
13
+ STANDARD_PREC = 53
14
+
15
+ LOG2_10 = math.log(10,2) # 3.3219...
16
+
17
+
18
+ # All supported rounding modes. We define them as integer constants for easy
19
+ # management, but change __repr__ to give more information on inspection
20
+
21
+ class Rounding(int):
22
+
23
+ def __new__(cls, level, name):
24
+ a = int.__new__(cls, level)
25
+ a.name = name
26
+ return a
27
+
28
+ def __repr__(self):
29
+ return self.name
30
+
31
+ __str__ = __repr__
32
+
33
+ ROUND_DOWN = Rounding(1, 'ROUND_DOWN')
34
+ ROUND_UP = Rounding(2, 'ROUND_UP')
35
+ ROUND_FLOOR = Rounding(3, 'ROUND_FLOOR')
36
+ ROUND_CEILING = Rounding(4, 'ROUND_CEILING')
37
+ ROUND_HALF_UP = Rounding(5, 'ROUND_HALF_UP')
38
+ ROUND_HALF_DOWN = Rounding(6, 'ROUND_HALF_DOWN')
39
+ ROUND_HALF_EVEN = Rounding(7, 'ROUND_HALF_EVEN')
40
+
41
+
42
+ def giant_steps(start, target):
43
+ """Generate a list of precisions ranging from 'start' to 'target'
44
+ that doubles with each step. This is used by quadratically
45
+ convergent iterations (that is, Newton iterations), where we want
46
+ to keep the precision at the same level as the accuracy in each
47
+ step to minimize work.
48
+
49
+ For example, to find a sequence of precisions to reach 1000 bits
50
+ starting from a 53-bit estimate, giant_steps(53, 1000) gives
51
+
52
+ [64, 126, 251, 501, 1000]
53
+
54
+ So, if we start Newton's method with a 53-bit accurate initial
55
+ guess, the first iteration should be carried out at 64-bit
56
+ precision, the second at 126-bit precision, and so on.
57
+
58
+ Note the conservative rounding (1000 to 501, etc); this is used
59
+ guard against unit errors in the last place."""
60
+ L = [target]
61
+ while L[-1] > start*2:
62
+ L = L + [L[-1]//2 + 1]
63
+ return L[::-1]
64
+
65
+
66
+ def rshift_quick(x, n):
67
+ """For an integer x, calculate x >> n with the fastest (floor)
68
+ rounding. Unlike the plain Python expression (x >> n), n is
69
+ allowed to be negative, in which case a left shift is performed."""
70
+ if n >= 0: return x >> n
71
+ else: return x << (-n)
72
+
73
+
74
+ def lshift_quick(x, n):
75
+ """For an integer x, calculate x << n. Unlike the plain Python
76
+ expression (x << n), n is allowed to be negative, in which case a
77
+ right shift with default (floor) rounding is performed."""
78
+ if n >= 0: return x << n
79
+ else: return x >> (-n)
80
+
81
+
82
+ def make_fixed(s, prec):
83
+ """Convert a floating-point number to a fixed-point big integer"""
84
+ man, exp, bc = s
85
+ offset = exp + prec
86
+ if offset >= 0:
87
+ return man << offset
88
+ else:
89
+ return man >> (-offset)
90
+
91
+
92
+ def bitcount(n, log=math.log, table=(0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4)):
93
+ """Give size of n in bits; i.e. the position of the highest set bit
94
+ in n. If n is negative, the absolute value is used. The bitcount of
95
+ zero is taken to be 0."""
96
+
97
+ if not n: return 0
98
+ if n < 0: n = -n
99
+
100
+ # math.log gives a good estimate, and never overflows, but
101
+ # is not always exact. Subtract 2 to underestimate, then
102
+ # count remaining bits by table lookup
103
+ bc = int(log(n, 2)) - 2
104
+ if bc < 0:
105
+ bc = 0
106
+ return bc + table[n >> bc]
107
+
108
+
109
+ # from decimal.py -- faster for small precs
110
+ def bitcount2(n, correction = {
111
+ '0': 4, '1': 3, '2': 2, '3': 2,
112
+ '4': 1, '5': 1, '6': 1, '7': 1,
113
+ '8': 0, '9': 0, 'a': 0, 'b': 0,
114
+ 'c': 0, 'd': 0, 'e': 0, 'f': 0}):
115
+ if n < 0:
116
+ n = -n
117
+ hex_n = "%x" % n
118
+ return 4*len(hex_n) - correction[hex_n[0]]
119
+
120
+
121
+ def trailing_zeros(n):
122
+ """Count trailing zero bits in an integer. If n is negative, it is
123
+ replaced by its absolute value."""
124
+ if n & 1: return 0
125
+ if not n: return 0
126
+ if n < 0: n = -n
127
+ t = 0
128
+ while not n & 0xffffffffffffffff: n >>= 64; t += 64
129
+ while not n & 0xff: n >>= 8; t += 8
130
+ while not n & 1: n >>= 1; t += 1
131
+ return t
132
+
133
+ #----------------------------------------------------------------------------
134
+ # Integer shifting with directed rounding
135
+ #
136
+
137
+ def round_floor(x, n):
138
+ if not n or not x: return x
139
+ if n < 0: return x << -n
140
+ return x >> n
141
+
142
+ def round_ceiling(x, n):
143
+ if not n or not x: return x
144
+ if n < 0: return x << -n
145
+ return -((-x) >> n)
146
+
147
+ def round_down(x, n):
148
+ if not n or not x: return x
149
+ if n < 0: return x << -n
150
+ if x > 0:
151
+ return x >> n
152
+ else:
153
+ return -((-x) >> n)
154
+
155
+ def round_up(x, n):
156
+ if not n or not x: return x
157
+ if n < 0: return x << -n
158
+ if x > 0:
159
+ return -((-x) >> n)
160
+ else:
161
+ return x >> n
162
+
163
+ def round_half_up(x, n):
164
+ if not n or not x: return x
165
+ if n < 0: return x << -n
166
+ positive = x > 0
167
+ if positive: t = x >> (n-1)
168
+ else: t = (-x) >> (n-1)
169
+ if t & 1:
170
+ if positive: return (t>>1)+1
171
+ else: return -((t>>1)+1)
172
+ if positive: return t>>1
173
+ else: return -(t>>1)
174
+
175
+ def round_half_down(x, n):
176
+ if not n or not x: return x
177
+ if n < 0: return x << -n
178
+ positive = x > 0
179
+ if positive: t = x >> (n-1)
180
+ else: t = (-x) >> (n-1)
181
+ if t & 1 and x & ((1<<(n-1))-1):
182
+ if positive: return (t>>1)+1
183
+ else: return -((t>>1)+1)
184
+ if positive: return t>>1
185
+ else: return -(t>>1)
186
+
187
+ def round_half_even(x, n):
188
+ if not n or not x: return x
189
+ if n < 0: return x << -n
190
+ positive = x > 0
191
+ if positive: t = x >> (n-1)
192
+ else: t = (-x) >> (n-1)
193
+ if t & 1 and (t&2 or x & ((1<<(n-1))-1)):
194
+ if positive: return (t>>1)+1
195
+ else: return -((t>>1)+1)
196
+ if positive: return t>>1
197
+ else: return -(t>>1)
198
+
199
+
200
+ rounding_functions = {
201
+ ROUND_FLOOR : round_floor,
202
+ ROUND_CEILING : round_ceiling,
203
+ ROUND_DOWN : round_down,
204
+ ROUND_UP : round_up,
205
+ ROUND_HALF_UP : round_half_up,
206
+ ROUND_HALF_DOWN : round_half_down,
207
+ ROUND_HALF_EVEN : round_half_even
208
+ }
209
+
210
+
211
+ def rshift(x, n, rounding):
212
+ """Shift x (a plain Python integer) n bits to the right (i.e.,
213
+ calculate x/(2**n)), and round to the nearest integer in accordance
214
+ with the specified rounding mode. The exponent n may be negative,
215
+ in which case x is shifted to the left (and no rounding is
216
+ necessary)."""
217
+ return rounding_functions[rounding](x, n)
218
+
219
+
220
+
221
+ # TODO: speed up for bases 2, 4, 8, 16, ...
222
+
223
+ def bin_to_radix(x, xbits, base, bdigits):
224
+ """
225
+ Radix conversion for fixed-point numbers. That is, convert
226
+ x * 2**xbits to floor(x * 10**bdigits).
227
+ """
228
+ return x * (base**bdigits) >> xbits
229
+
230
+ stddigits = '0123456789abcdefghijklmnopqrstuvwxyz'
231
+
232
+ def small_numeral(n, base=10, digits=stddigits):
233
+ """
234
+ Return the string numeral of a positive integer in an arbitrary
235
+ base. Most efficient for small input.
236
+ """
237
+ if base == 10:
238
+ return str(n)
239
+ digs = []
240
+ while n:
241
+ n, digit = divmod(n, base)
242
+ digs.append(digits[digit])
243
+ return "".join(digs[::-1])
244
+
245
+ def numeral(n, base=10, size=0, digits=stddigits):
246
+ """
247
+ Represent the integer n as a string of digits in the given base.
248
+ Recursive division is used to make this function about 3x faster
249
+ than Python's str() for converting integers to decimal strings.
250
+
251
+ The 'size' parameters specifies the number of digits in n; this
252
+ number is only used to determine splitting points and need not
253
+ be exact.
254
+ """
255
+
256
+ if n < 0:
257
+ return "-" + numeral(-n, base, size, digits)
258
+
259
+ # Fast enough to do directly
260
+ if size < 250:
261
+ return small_numeral(n, base, digits)
262
+
263
+ # Divide in half
264
+ half = (size // 2) + (size & 1)
265
+ A, B = divmod(n, base**half)
266
+ ad = numeral(A, base, half, digits)
267
+ bd = numeral(B, base, half, digits).rjust(half, "0")
268
+ return ad + bd