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,181 @@
1
+ """
2
+ Arithmetic operations and functions on complex numbers, represented on
3
+ rectangular form as tuples of real floating-point numbers.
4
+
5
+ This module is quite compact, since most of the dirty work can be
6
+ delegated to functions that work on real numbers.
7
+ """
8
+
9
+ from util import *
10
+ from floatop import *
11
+ from functions import *
12
+ from squareroot import *
13
+
14
+
15
+ # Use fastest rounding mode for intermediate calculations
16
+ RF = ROUND_FLOOR
17
+
18
+
19
+ #----------------------------------------------------------------------
20
+ # Complex parts
21
+ #
22
+
23
+ def fcabs(a, b, prec, rounding):
24
+ """
25
+ Absolute value of a complex number, |a+bi|. Returns a single
26
+ real number.
27
+ """
28
+ return fhypot(a, b, prec, rounding)
29
+
30
+
31
+ #----------------------------------------------------------------------
32
+ # Arithmetic
33
+ #
34
+
35
+ def fcmul(a, b, c, d, prec, rounding):
36
+ """
37
+ Complex multiplication.
38
+
39
+ Returns the real and imaginary part of (a+bi)*(c+di), rounded to
40
+ the specified precision. The rounding mode applies to the real and
41
+ imaginary parts separately.
42
+
43
+ Implemented the straightforward way. TODO: use a more stable
44
+ algorithm to avoid cancellation.
45
+ """
46
+
47
+ # All-real case
48
+ if b == d == fzero:
49
+ return fmul(a, c, prec, rounding), fzero
50
+
51
+ ep = prec + 10
52
+
53
+ re = fsub(fmul(a,c, ep, RF), fmul(b,d, ep, RF), prec, rounding)
54
+ im = fadd(fmul(a,d, ep, RF), fmul(b,c, ep, RF), prec, rounding)
55
+ return re, im
56
+
57
+
58
+ #----------------------------------------------------------------------
59
+ # Square root
60
+ #
61
+
62
+ def fcsqrt(a, b, prec, rounding):
63
+ """
64
+ Complex square root (principal branch).
65
+
66
+ We have sqrt(a+bi) = sqrt((r+a)/2) + b/sqrt(2*(r+a))*i where
67
+ r = abs(a+bi), when a+bi is not a negative real number.
68
+ """
69
+
70
+ if a == b == fzero:
71
+ return (a, b)
72
+
73
+ # When a+bi is a negative real number, we get a real sqrt times i
74
+ if a[0] < 0 and b == fzero:
75
+ im = fsqrt(fneg_exact(a), prec, rounding)
76
+ return (fzero, im)
77
+
78
+ ep = prec+20
79
+
80
+ t = fadd(fcabs(a, b, ep, RF), a, ep, RF) # t = abs(a+bi) + a
81
+ u = fmul(t, fhalf, ep, RF) # u = t / 2
82
+ re = fsqrt(u, prec, rounding) # re = sqrt(u)
83
+ v = fmul(t, ftwo, ep, RF) # v = t * 2
84
+ w = fsqrt(v, ep, RF) # w = sqrt(v)
85
+ im = fdiv(b, w, prec, rounding) # im = b / w
86
+
87
+ return re, im
88
+
89
+
90
+ #----------------------------------------------------------------------
91
+ # Exp and log
92
+ #
93
+
94
+ def fcexp(a, b, prec, rounding):
95
+ """
96
+ Complex exponential function.
97
+
98
+ We use the direct formula exp(a+bi) = exp(a) * (cos(b) + sin(b)*i)
99
+ for the computation. This formula is very nice because it is
100
+ perfectly stable; since we just do real multiplications, the only
101
+ numerical errors that can creep in are single-ulp rounding errors.
102
+
103
+ The formula is efficient since mpmath's real exp is quite fast and
104
+ since we can compute cos and sin simultaneously.
105
+
106
+ It is no problem if a and b are large; if the implementations of
107
+ exp/cos/sin are accurate and efficient for all real numbers, then
108
+ so is this function for all complex numbers.
109
+ """
110
+
111
+ mag = fexp(a, prec+4, rounding)
112
+
113
+ c, s = cos_sin(b, prec+4, rounding)
114
+
115
+ re = fmul(mag, c, prec, rounding)
116
+ im = fmul(mag, s, prec, rounding)
117
+ return re, im
118
+
119
+ # TODO: log
120
+
121
+
122
+ #----------------------------------------------------------------------
123
+ # Trigonometric functions
124
+ #
125
+
126
+ def fccos(a, b, prec, rounding):
127
+ """
128
+ Complex cosine.
129
+
130
+ The formula used is cos(a+bi) = cos(a)*cosh(b) - sin(a)*sinh(b)*i.
131
+
132
+ The same comments apply as for the complex exp: only real
133
+ multiplications are performed, so no cancellation errors are
134
+ possible. The formula is also efficient since we can compute both
135
+ pairs (cos, sin) and (cosh, sinh) in single steps.
136
+ """
137
+ ep = prec + 6
138
+
139
+ c, s = cos_sin(a, ep, RF)
140
+ ch, sh = cosh_sinh(b, ep, RF)
141
+
142
+ re = fmul(c, ch, prec, rounding)
143
+ im = fmul(s, sh, prec, rounding)
144
+
145
+ return re, fneg_exact(im)
146
+
147
+
148
+ def fcsin(a, b, prec, rounding):
149
+ """
150
+ Complex sine.
151
+
152
+ We have sin(a+bi) = sin(a)*cosh(b) + cos(a)*sinh(b)*i.
153
+ See the docstring for fccos for additional comments.
154
+ """
155
+ ep = prec + 6
156
+
157
+ c, s = cos_sin(a, ep, RF)
158
+ ch, sh = cosh_sinh(b, ep, RF)
159
+
160
+ re = fmul(s, ch, prec, rounding)
161
+ im = fmul(c, sh, prec, rounding)
162
+
163
+ return re, im
164
+
165
+
166
+ # TODO: complex tan
167
+
168
+
169
+ #----------------------------------------------------------------------
170
+ # Hyperbolic functions
171
+ #
172
+
173
+ def fccosh(a, b, prec, rounding):
174
+ """Complex hyperbolic cosine. Computed as cosh(z) = cos(z*i)."""
175
+ return fccos(b, fneg_exact(a), prec, rounding)
176
+
177
+
178
+ def fcsinh(a, b, prec, rounding):
179
+ """Complex hyperbolic sine. Computed as sinh(z) = -i*sin(z*i)."""
180
+ b, a = fcsin(b, a, prec, rounding)
181
+ return a, b
@@ -0,0 +1,212 @@
1
+ """
2
+ Mathematical constants
3
+
4
+ """
5
+
6
+ import math
7
+
8
+ from util import *
9
+ from floatop import *
10
+ from squareroot import *
11
+
12
+
13
+ def constant_memo(f):
14
+ """
15
+ Memoization for calculation of constants using fixed-point
16
+ arithmetic. Only store the value computed with highest precision;
17
+ if a lower or equal precision is requested later, the result can
18
+ be generated directly through downshifting the cached value.
19
+ """
20
+ f.memo_prec = -1
21
+ f.memo_val = None
22
+
23
+ def g(prec):
24
+ if prec == f.memo_prec:
25
+ return f.memo_val
26
+ if prec < f.memo_prec:
27
+ return f.memo_val >> (f.memo_prec-prec)
28
+ f.memo_val = f(prec)
29
+ f.memo_prec = prec
30
+ return f.memo_val
31
+
32
+ g.__name__ = f.__name__
33
+ g.__doc__ = f.__doc__
34
+ return g
35
+
36
+ def acot(n, prec, hyperbolic):
37
+ """
38
+ Compute acot of an integer using fixed-point arithmetic. With
39
+ hyperbolic=True, compute acoth. We use the series expansion
40
+
41
+ 1 1 1
42
+ acot(n) = --- - ---- + ---- - ...,
43
+ 3 5
44
+ n 3 n 5 n
45
+
46
+ optimized for integer arguments. In the hyperbolic case, all
47
+ negative terms are changed to positive ones.
48
+ """
49
+ s = t = (1 << prec) // n # 1 / n
50
+ k = 3
51
+ while 1:
52
+ # Repeatedly divide by k * n**2, and add
53
+ t //= (n*n)
54
+ term = t // k
55
+ if not term:
56
+ break
57
+ # Alternate signs
58
+ if hyperbolic or not k & 2:
59
+ s += term
60
+ else:
61
+ s -= term
62
+ k += 2
63
+ return s
64
+
65
+ def machin(coefs, prec, hyperbolic=False):
66
+ """
67
+ Evaluate a Machin-like formula, i.e., a linear combination of
68
+ acot(n) or acoth(n) for specific integer values of n, using fixed-
69
+ point arithmetic.
70
+
71
+ The input should be a list [(c, n), ...], giving c*acot[h](n) + ...
72
+ """
73
+ extraprec = 10
74
+ s = 0
75
+ for a, b in coefs:
76
+ s += a * acot(b, prec+extraprec, hyperbolic)
77
+ return (s >> extraprec)
78
+
79
+ def agm_status(prec, step, adiff, verbose_base):
80
+ logdiff = math.log(max(1, adiff), verbose_base)
81
+ digits = int(prec/math.log(verbose_base,2) - logdiff)
82
+ print " iteration", step, ("(accuracy ~= %i base-%i digits)" % \
83
+ (digits, verbose_base))
84
+
85
+ def pi_agm(prec, verbose=False, verbose_base=10):
86
+ """
87
+ Compute floor(pi * 2**prec) as a big integer using the Brent-
88
+ Salamin algorithm based on the arithmetic-geometric mean.
89
+
90
+ See for example Wikipedia (http://en.wikipedia.org/wiki/Brent-
91
+ Salamin_algorithm) or "Pi and the AGM" by Jonathan and Peter
92
+ Borwein (Wiley, 1987). The algorithm (as stated in the Wikipedia
93
+ article) consists of setting
94
+
95
+ a_0 = 1
96
+ b_0 = 1/sqrt(2)
97
+ t_0 = 1/4
98
+ p_0 = 1
99
+
100
+ and computing
101
+
102
+ a_{n+1} = (a_n + b_n)/2
103
+ b_{n+1} = sqrt(a_n * b_n)
104
+ t_{n+1} = t_n - p_n*(a_n - a_{n+1})**2
105
+ p_{n+1} = 2*p_n
106
+
107
+ for n = 0, 1, 2, 3, ..., after which the approximation is given by
108
+ pi ~= (a_n + b_n)**2 / (4*t_n). Each step roughly doubles the
109
+ number of correct digits.
110
+ """
111
+ extraprec = 50
112
+ prec += extraprec
113
+
114
+ # Initialial values. a, b and t are fixed-point numbers
115
+ a = 1 << prec
116
+ b = sqrt_fixed2(a >> 1, prec)
117
+ t = a >> 2
118
+ p = 1
119
+
120
+ step = 1
121
+ while 1:
122
+ an = (a + b) >> 1
123
+ adiff = a - an
124
+ if verbose:
125
+ agm_status(prec, step, adiff, verbose_base)
126
+ # No change in a
127
+ if p > 16 and abs(adiff) < 1000:
128
+ break
129
+ prod = (a * b) >> prec
130
+ b = sqrt_fixed2(prod, prec)
131
+ t = t - p*((adiff**2) >> prec)
132
+ p = 2*p
133
+ a = an
134
+ step += 1
135
+ if verbose:
136
+ print " final division"
137
+ pi = ((((a+b)**2) >> 2) // t)
138
+ return pi >> extraprec
139
+
140
+ @constant_memo
141
+ def pi_fixed(prec):
142
+ """
143
+ Compute floor(pi * 2**prec) as a big integer.
144
+
145
+ For low precisions, Machin's formula pi = 16*acot(5)-4*acot(239)
146
+ is used. For high precisions, the more efficient arithmetic-
147
+ geometric mean iteration is used.
148
+ """
149
+ if prec < 10000:
150
+ return machin([(16, 5), (-4, 239)], prec)
151
+ else:
152
+ return pi_agm(prec)
153
+
154
+ def fpi(prec, rounding):
155
+ """Compute a floating-point approximation of pi"""
156
+ return normalize(pi_fixed(prec+5), -prec-5, prec, rounding)
157
+
158
+
159
+ # Logarithms of integers can be computed easily using
160
+ # Machin-like formulas
161
+
162
+ @constant_memo
163
+ def log2_fixed(prec):
164
+ return machin([(18, 26), (-2, 4801), (8, 8749)], prec, True)
165
+
166
+ def flog2(prec, rounding):
167
+ return normalize(log2_fixed(prec+5), -prec-5, prec, rounding)
168
+
169
+
170
+ @constant_memo
171
+ def log10_fixed(prec):
172
+ return machin([(46, 31), (34, 49), (20, 161)], prec, True)
173
+
174
+ def flog10(prec, rounding):
175
+ return normalize(log10_fixed(prec+5), -prec-5, prec, rounding)
176
+
177
+
178
+ """
179
+ Euler's constant (gamma) is computed using the Brent-McMillan formula,
180
+ gamma ~= A(n)/B(n) - log(n), where
181
+
182
+ A(n) = sum_{k=0,1,2,...} (n**k / k!)**2 * H(k)
183
+ B(n) = sum_{k=0,1,2,...} (n**k / k!)**2
184
+ H(k) = 1 + 1/2 + 1/3 + ... + 1/k
185
+
186
+ The error is bounded by O(exp(-4n)). Choosing n to be a power
187
+ of two, 2**p, the logarithm becomes particularly easy to calculate.
188
+
189
+ Reference:
190
+ Xavier Gourdon & Pascal Sebah, The Euler constant: gamma
191
+ http://numbers.computation.free.fr/Constants/Gamma/gamma.pdf
192
+ """
193
+
194
+ @constant_memo
195
+ def gamma_fixed(prec):
196
+ prec += 30
197
+ # choose p such that exp(-4*(2**p)) < 2**-n
198
+ p = int(math.log((prec/4) * math.log(2), 2)) + 1
199
+ n = 1<<p
200
+ r = one = 1<<prec
201
+ H, A, B, npow, k, d = 0, 0, 0, 1, 1, 1
202
+ while r:
203
+ A += (r * H) >> prec
204
+ B += r
205
+ r = r * (n*n) // (k*k)
206
+ H += one // k
207
+ k += 1
208
+ S = ((A<<prec) // B) - p*log2_fixed(prec)
209
+ return S >> 30
210
+
211
+ def fgamma(prec, rounding):
212
+ return normalize(gamma_fixed(prec+5), -prec-5, prec, rounding)
@@ -0,0 +1,233 @@
1
+ """
2
+ Functions for converting between raw mpmath floating-point numbers and
3
+ other types and number representations (int, float, str...).
4
+ """
5
+
6
+ from util import *
7
+ from floatop import *
8
+ from constants import flog2, flog10
9
+ import math
10
+
11
+
12
+ #----------------------------------------------------------------------
13
+ # Strings
14
+ #
15
+
16
+ def to_digits_exp(s, dps):
17
+ """
18
+ Helper function for representing the floating-point number s as a
19
+ decimal with dps places. Returns (sign, string, exponent)
20
+ containing '' or '-', the decimal digits as a string, and an
21
+ integer for the decimal exponent.
22
+
23
+ If inexact, the decimal representation is rounded toward zero.
24
+ """
25
+
26
+ # Extract sign so it doesn't mess up the string digit count
27
+ sign = ''
28
+ if s[0] < 0:
29
+ sign = '-'
30
+ s = fabs(s, s[2], ROUND_FLOOR)
31
+ man, exp, bc = s
32
+
33
+ if not man:
34
+ return '', '0', 0
35
+
36
+ bitprec = int(dps * math.log(10,2)) + 10
37
+
38
+ # Cut down to size
39
+ # TODO: account for precision when doing this
40
+ exp_from_1 = exp + bc
41
+ if abs(exp) > 500:
42
+ # Set b = int(exp * log(2)/log(10))
43
+ # If exp is huge, we must use high-precision arithmetic to
44
+ # find the nearest power of ten
45
+ expprec = bitcount(exp) + 5
46
+ RF = ROUND_FLOOR
47
+ tmp = from_int(exp, expprec, RF)
48
+ tmp = fmul(tmp, flog2(expprec, RF), expprec, RF)
49
+ tmp = fdiv(tmp, flog10(expprec, RF), expprec, RF)
50
+ b = to_int(tmp)
51
+ s = fdiv(s, fpow(ften, b, bitprec, RF), bitprec, RF)
52
+ man, exp, bc = s
53
+ exponent = b
54
+ else:
55
+ exponent = 0
56
+
57
+ # First, calculate mantissa digits by converting to a binary
58
+ # fixed-point number and then converting that number to
59
+ # a decimal fixed-point number.
60
+ fixprec = max(bitprec - exp, 0)
61
+ fixdps = int(fixprec / math.log(10,2) + 0.5)
62
+ sf = make_fixed(s, fixprec)
63
+ sd = bin_to_radix(sf, fixprec, 10, fixdps)
64
+ digits = numeral(sd, base=10, size=dps)
65
+
66
+ exponent += len(digits) - fixdps - 1
67
+ return sign, digits, exponent
68
+
69
+
70
+ def to_str(s, dps):
71
+ """Convert a raw mpf to a decimal floating-point literal with at
72
+ most `dps` decimal digits in the mantissa (not counting extra zeros
73
+ that may be inserted for visual purposes).
74
+
75
+ The literal is formatted so that it can be parsed back to a number
76
+ by to_str, float() or Decimal()."""
77
+
78
+ # to_digits_exp rounds to floor.
79
+ # This sometimes kills some instances of "...00001"
80
+ sign, digits, exponent = to_digits_exp(s, dps+3)
81
+
82
+ # Rounding up kills some instances of "...99999"
83
+ if len(digits) > dps and digits[dps] in '56789':
84
+ digits2 = str(int(digits[:dps]) + 1)
85
+ if len(digits2) > dps:
86
+ digits2 = digits2[:dps]
87
+ exponent += 1
88
+ digits = digits2
89
+ else:
90
+ digits = digits[:dps]
91
+
92
+ # Prettify numbers close to unit magnitude
93
+ if -(dps//3) < exponent < dps:
94
+ if exponent < 0:
95
+ digits = ("0"*(-exponent)) + digits
96
+ split = 1
97
+ else:
98
+ split = exponent + 1
99
+ exponent = 0
100
+ else:
101
+ split = 1
102
+
103
+ digits = (digits[:split] + "." + digits[split:])
104
+
105
+ # Clean up trailing zeros
106
+ digits = digits.rstrip('0')
107
+ if digits[-1] == ".":
108
+ digits += "0"
109
+
110
+ if exponent == 0: return sign + digits
111
+ if exponent > 0: return sign + digits + "e+" + str(exponent)
112
+ if exponent < 0: return sign + digits + "e" + str(exponent)
113
+
114
+
115
+ def str_to_man_exp(x, base=10):
116
+ # Verify that the input is a valid float literal
117
+ float(x)
118
+ # Split into mantissa, exponent
119
+ x = x.lower()
120
+ parts = x.split('e')
121
+ if len(parts) == 1:
122
+ exp = 0
123
+ else: # == 2
124
+ x = parts[0]
125
+ exp = int(parts[1])
126
+ # Look for radix point in mantissa
127
+ parts = x.split('.')
128
+ if len(parts) == 2:
129
+ a, b = parts[0], parts[1].rstrip('0')
130
+ exp -= len(b)
131
+ x = a + b
132
+ x = int(x, base)
133
+ return x, exp
134
+
135
+ def from_str(x, prec, rounding):
136
+ """Create a raw mpf from a decimal literal, rounding in the
137
+ specified direction if the input number cannot be represented
138
+ exactly as a binary floating-point number with the given number of
139
+ bits. The literal syntax accepted is the same as for Python
140
+ floats.
141
+
142
+ TODO: the rounding does not work properly for large exponents.
143
+ """
144
+ man, exp = str_to_man_exp(x, base=10)
145
+
146
+ # XXX: appropriate cutoffs & track direction
147
+ # note no factors of 5
148
+ if abs(exp) > 400:
149
+ s = from_int(man, prec+10, ROUND_FLOOR)
150
+ s = fmul(s, fpow(ften, exp, prec+10, ROUND_FLOOR), prec, rounding)
151
+ else:
152
+ if exp >= 0:
153
+ s = from_int(man * 10**exp, prec, rounding)
154
+ else:
155
+ s = from_rational(man, 10**-exp, prec, rounding)
156
+ return s
157
+
158
+ # Binary string conversion. These are currently mainly used for debugging
159
+ # and could use some improvement in the future
160
+
161
+ def from_bstr(x):
162
+ man, exp = str_to_man_exp(x, base=2)
163
+ return normalize(man, exp, bitcount(man), ROUND_FLOOR)
164
+
165
+ def to_bstr(x):
166
+ man, exp, bc = x
167
+ return numeral(man, size=bitcount(man), base=2) + ("e%i" % exp)
168
+
169
+
170
+ #----------------------------------------------------------------------
171
+ # Integers
172
+ #
173
+
174
+ def from_int(n, prec, rounding):
175
+ """Create a raw mpf from an integer, rounding if necessary."""
176
+ return normalize(n, 0, prec, rounding)
177
+
178
+ def from_int_exact(n):
179
+ """Create a raw mpf from an integer, automatically choosing the
180
+ precision high enough to represent the integer exactly."""
181
+ t = trailing_zeros(n)
182
+ n >>= t
183
+ return (n, t, bitcount(n))
184
+
185
+ def to_int(s):
186
+ """Convert a raw mpf to the nearest int, rounding down."""
187
+ man, exp, bc = s
188
+ return rshift(man, -exp, ROUND_DOWN)
189
+
190
+
191
+ #----------------------------------------------------------------------
192
+ # Regular python floats
193
+ #
194
+
195
+ def from_float(x, prec, rounding):
196
+ """Create a raw mpf from a Python float, rounding if necessary.
197
+ If prec >= 53, the result is guaranteed to represent exactly the
198
+ same number as the input."""
199
+ m, e = math.frexp(x)
200
+ return normalize(int(m*(1<<53)), e-53, prec, rounding)
201
+
202
+ def to_float(s):
203
+ """Convert a raw mpf to a Python float. The result is exact if the
204
+ bitcount of s is <= 53 and no underflow/overflow occurs. An
205
+ OverflowError is raised if the number is too large to be
206
+ represented as a regular float."""
207
+ man, exp, bc = s
208
+ try:
209
+ return math.ldexp(man, exp)
210
+ except OverflowError:
211
+ # Try resizing the mantissa. Overflow may still happen here.
212
+ n = bc - 53
213
+ m = man >> n
214
+ return math.ldexp(m, exp + n)
215
+
216
+
217
+ #----------------------------------------------------------------------
218
+ # Rational numbers (for use by other libraries)
219
+ #
220
+
221
+ def from_rational(p, q, prec, rounding):
222
+ """Create a raw mpf from a rational number p/q, rounding if
223
+ necessary."""
224
+ return fdiv(from_int_exact(p), from_int_exact(q), prec, rounding)
225
+
226
+ def to_rational(s):
227
+ """Convert a raw mpf to a rational number. Return integers (p, q)
228
+ such that s = p/q exactly. p and q are not reduced to lowest terms."""
229
+ man, exp, bc = s
230
+ if exp > 0:
231
+ return man * 2**exp, 1
232
+ else:
233
+ return man, 2**-exp