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.
- mpmath-0.4/CHANGES +52 -0
- {mpmath-0.2 → mpmath-0.4}/PKG-INFO +1 -1
- {mpmath-0.2 → mpmath-0.4}/README +58 -8
- {mpmath-0.2 → mpmath-0.4}/demo/pidigits.py +10 -16
- mpmath-0.4/mpmath/__init__.py +3 -0
- mpmath-0.4/mpmath/functions2.py +384 -0
- mpmath-0.4/mpmath/lib/__init__.py +7 -0
- mpmath-0.4/mpmath/lib/complexop.py +181 -0
- mpmath-0.4/mpmath/lib/constants.py +212 -0
- mpmath-0.4/mpmath/lib/convert.py +233 -0
- mpmath-0.4/mpmath/lib/floatop.py +252 -0
- mpmath-0.4/mpmath/lib/functions.py +350 -0
- mpmath-0.4/mpmath/lib/squareroot.py +199 -0
- mpmath-0.4/mpmath/lib/util.py +268 -0
- mpmath-0.4/mpmath/mpmath.py +739 -0
- {mpmath-0.2 → mpmath-0.4}/setup.py +2 -2
- mpmath-0.4/tests/benchmark.py +139 -0
- mpmath-0.4/tests/runtests.py +5 -0
- mpmath-0.4/tests/test_bitwise.py +110 -0
- mpmath-0.4/tests/test_compatibility.py +51 -0
- mpmath-0.4/tests/test_convert.py +62 -0
- mpmath-0.4/tests/test_division.py +126 -0
- mpmath-0.4/tests/test_functions2.py +68 -0
- mpmath-0.4/tests/test_hp.py +199 -0
- {mpmath-0.2 → mpmath-0.4}/tests/test_mpmath.py +137 -166
- mpmath-0.2/CHANGES +0 -23
- mpmath-0.2/mpmath/__init__.py +0 -2
- mpmath-0.2/mpmath/lib.py +0 -1122
- mpmath-0.2/mpmath/mpmath.py +0 -515
- {mpmath-0.2 → mpmath-0.4}/LICENSE +0 -0
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
from lib import *
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class mpnumeric(object):
|
|
6
|
+
"""Base class for mpf and mpc. Calling mpnumeric(x) returns an mpf
|
|
7
|
+
if x can be converted to an mpf (if it is a float, int, mpf, ...),
|
|
8
|
+
and an mpc if x is complex."""
|
|
9
|
+
|
|
10
|
+
def __new__(cls, val):
|
|
11
|
+
# TODO: should maybe normalize here
|
|
12
|
+
if isinstance(val, cls):
|
|
13
|
+
return val
|
|
14
|
+
if isinstance(val, complex):
|
|
15
|
+
return mpc(val)
|
|
16
|
+
return mpf(val)
|
|
17
|
+
|
|
18
|
+
def convert_lossless(x):
|
|
19
|
+
"""Attempt to convert x to an mpf or mpc losslessly. If x is an
|
|
20
|
+
mpf or mpc, return it unchanged. If x is an int, create an mpf with
|
|
21
|
+
sufficient precision to represent it exactly.
|
|
22
|
+
|
|
23
|
+
If x is a decimal or str, just convert it to an mpf with the
|
|
24
|
+
current working precision (perhaps this should be done
|
|
25
|
+
differently...)"""
|
|
26
|
+
if isinstance(x, mpnumeric):
|
|
27
|
+
return x
|
|
28
|
+
if isinstance(x, float):
|
|
29
|
+
return make_mpf(from_float(x, 53, ROUND_FLOOR))
|
|
30
|
+
if isinstance(x, int_types):
|
|
31
|
+
return make_mpf(from_int(x, bitcount(x), ROUND_FLOOR))
|
|
32
|
+
if isinstance(x, complex):
|
|
33
|
+
return mpc(x)
|
|
34
|
+
if isinstance(x, (Decimal, str)):
|
|
35
|
+
if x == 'inf': return inf
|
|
36
|
+
if x == '-inf': return minus_inf
|
|
37
|
+
if x == 'nan': return nan
|
|
38
|
+
return make_mpf(from_str(x, mpf._prec, mpf._rounding))
|
|
39
|
+
raise TypeError("cannot create mpf from " + repr(x))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class context(type):
|
|
43
|
+
"""Metaclass for mpf and mpc. Holds global working precision."""
|
|
44
|
+
|
|
45
|
+
_prec = 53
|
|
46
|
+
_dps = 15
|
|
47
|
+
_rounding = ROUND_HALF_EVEN
|
|
48
|
+
|
|
49
|
+
def _setprec(self, n):
|
|
50
|
+
self._prec = max(1, int(n))
|
|
51
|
+
self._dps = max(1, int(round(int(n)/LOG2_10)-1))
|
|
52
|
+
|
|
53
|
+
prec = property(lambda self: self._prec, _setprec)
|
|
54
|
+
|
|
55
|
+
def _setdps(self, n):
|
|
56
|
+
self._prec = max(1, int(round((int(n)+1)*LOG2_10)))
|
|
57
|
+
self._dps = max(1, int(n))
|
|
58
|
+
|
|
59
|
+
dps = property(lambda self: self._dps, _setdps)
|
|
60
|
+
|
|
61
|
+
def round_up(self): self._rounding = ROUND_UP
|
|
62
|
+
def round_down(self): self._rounding = ROUND_DOWN
|
|
63
|
+
def round_floor(self): self._rounding = ROUND_FLOOR
|
|
64
|
+
def round_ceiling(self): self._rounding = ROUND_CEILING
|
|
65
|
+
def round_half_down(self): self._rounding = ROUND_HALF_DOWN
|
|
66
|
+
def round_half_up(self): self._rounding = ROUND_HALF_UP
|
|
67
|
+
def round_half_even(self): self._rounding = ROUND_HALF_EVEN
|
|
68
|
+
|
|
69
|
+
round_default = round_half_even
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
int_types = (int, long)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _convert(x):
|
|
76
|
+
"""Convet x to mpf data"""
|
|
77
|
+
if isinstance(x, float):
|
|
78
|
+
return from_float(x, mpf._prec, mpf._rounding)
|
|
79
|
+
if isinstance(x, int_types):
|
|
80
|
+
return from_int(x, mpf._prec, mpf._rounding)
|
|
81
|
+
if isinstance(x, (Decimal, str)):
|
|
82
|
+
return from_str(x, mpf._prec, mpf._rounding)
|
|
83
|
+
raise TypeError("cannot create mpf from " + repr(x))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class mpf(mpnumeric):
|
|
87
|
+
"""An mpf instance holds a real-valued floating-point number. mpf:s
|
|
88
|
+
work analogously to Python floats, but support arbitrary-precision
|
|
89
|
+
arithmetic. The mpf class has two properties 'dps' and 'prec' which
|
|
90
|
+
respectively hold the working precision as measured in decimal
|
|
91
|
+
digits and in bits. (The default is 15 digits / 53 bits, the same
|
|
92
|
+
as Python floats.) For example, this increases precision by 10
|
|
93
|
+
bits:
|
|
94
|
+
|
|
95
|
+
mpf.prec += 10
|
|
96
|
+
|
|
97
|
+
The global working precision controls the precision at which all
|
|
98
|
+
arithmetic operations on mpf:s is carried out. Directed rounding is
|
|
99
|
+
also (partially) implemented; all calculations will be rounded up
|
|
100
|
+
after calling
|
|
101
|
+
|
|
102
|
+
mpf.round_up()
|
|
103
|
+
|
|
104
|
+
mpf.round_half_even() is the default rounding.
|
|
105
|
+
|
|
106
|
+
An mpf is represented internally as a tuple of integers (man, exp,
|
|
107
|
+
bc) where man is the mantissa, exp is the exponent and bc is the
|
|
108
|
+
number of bits in the mantissa (bc <= mpf.prec if the number is
|
|
109
|
+
normalized to the current working precision). Mathematically, that
|
|
110
|
+
means the mpf x has the value x = man * 2**exp. The components can
|
|
111
|
+
be accessed using the .val property of an mpf.
|
|
112
|
+
|
|
113
|
+
A useful difference between mpf:s and Python floats is that
|
|
114
|
+
operations on mpf:s that mathematically produce complex numbers
|
|
115
|
+
(like mpf(-1)**0.5) return mpc:s instead of raising exceptions.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
__metaclass__ = context
|
|
119
|
+
|
|
120
|
+
def __new__(cls, val=fzero):
|
|
121
|
+
"""A new mpf can be created from a Python float, an int, a
|
|
122
|
+
Decimal, or a decimal string representing a number in
|
|
123
|
+
floating-point format. Examples:
|
|
124
|
+
|
|
125
|
+
mpf(25)
|
|
126
|
+
mpf(2.5)
|
|
127
|
+
mpf('2.5')
|
|
128
|
+
mpf('1.6e1000')
|
|
129
|
+
|
|
130
|
+
An mpf can also be created from a tuple (man, exp) or
|
|
131
|
+
(man, exp, bc):
|
|
132
|
+
|
|
133
|
+
>>> mpf((3, -1))
|
|
134
|
+
1.5
|
|
135
|
+
"""
|
|
136
|
+
if isinstance(val, mpf):
|
|
137
|
+
return make_mpf(normalize(val.val[0], val.val[1], \
|
|
138
|
+
cls._prec, cls._rounding))
|
|
139
|
+
elif isinstance(val, tuple):
|
|
140
|
+
return make_mpf(normalize(val[0], val[1], cls._prec, \
|
|
141
|
+
cls._rounding))
|
|
142
|
+
else:
|
|
143
|
+
return make_mpf(_convert(val))
|
|
144
|
+
|
|
145
|
+
man = property(lambda self: self.val[0])
|
|
146
|
+
exp = property(lambda self: self.val[1])
|
|
147
|
+
bc = property(lambda self: self.val[2])
|
|
148
|
+
|
|
149
|
+
def __repr__(s):
|
|
150
|
+
st = "mpf('%s')"
|
|
151
|
+
return st % to_str(s.val, mpf._dps+2)
|
|
152
|
+
|
|
153
|
+
def __str__(s):
|
|
154
|
+
return to_str(s.val, mpf._dps)
|
|
155
|
+
|
|
156
|
+
def __hash__(s):
|
|
157
|
+
try:
|
|
158
|
+
# Try to be compatible with hash values for floats and ints
|
|
159
|
+
return hash(float(s))
|
|
160
|
+
except OverflowError:
|
|
161
|
+
# We must unfortunately sacrifice compatibility with ints here. We
|
|
162
|
+
# could do hash(man << exp) when the exponent is positive, but
|
|
163
|
+
# this would cause unreasonable inefficiency for large numbers.
|
|
164
|
+
return hash(self.val)
|
|
165
|
+
|
|
166
|
+
def __int__(s):
|
|
167
|
+
return to_int(s.val)
|
|
168
|
+
|
|
169
|
+
def __float__(s):
|
|
170
|
+
return to_float(s.val)
|
|
171
|
+
|
|
172
|
+
def __complex__(s):
|
|
173
|
+
return float(s) + 0j
|
|
174
|
+
|
|
175
|
+
def __nonzero__(s):
|
|
176
|
+
return bool(s.man)
|
|
177
|
+
|
|
178
|
+
def __eq__(s, t):
|
|
179
|
+
if not isinstance(t, mpf):
|
|
180
|
+
if isinstance(t, complex_types):
|
|
181
|
+
return mpc(s) == t
|
|
182
|
+
if isinstance(t, str):
|
|
183
|
+
return False
|
|
184
|
+
try:
|
|
185
|
+
t = mpf(t)
|
|
186
|
+
except Exception:
|
|
187
|
+
return False
|
|
188
|
+
return s.val == t.val
|
|
189
|
+
|
|
190
|
+
def __ne__(s, t):
|
|
191
|
+
if not isinstance(t, mpf):
|
|
192
|
+
if isinstance(t, complex_types):
|
|
193
|
+
return mpc(s) != t
|
|
194
|
+
if isinstance(t, str):
|
|
195
|
+
return True
|
|
196
|
+
try:
|
|
197
|
+
t = mpf(t)
|
|
198
|
+
except Exception:
|
|
199
|
+
return True
|
|
200
|
+
t = mpf(t)
|
|
201
|
+
return s.val != t.val
|
|
202
|
+
|
|
203
|
+
def __cmp__(s, t):
|
|
204
|
+
if not isinstance(t, mpf):
|
|
205
|
+
t = mpf(t)
|
|
206
|
+
return fcmp(s.val, t.val)
|
|
207
|
+
|
|
208
|
+
def __abs__(s):
|
|
209
|
+
return make_mpf(fabs(s.val, mpf._prec, mpf._rounding))
|
|
210
|
+
|
|
211
|
+
def __pos__(s):
|
|
212
|
+
return mpf(s)
|
|
213
|
+
|
|
214
|
+
def __neg__(s):
|
|
215
|
+
return make_mpf(fneg(s.val, mpf._prec, mpf._rounding))
|
|
216
|
+
|
|
217
|
+
def __add__(s, t):
|
|
218
|
+
if not isinstance(t, mpf):
|
|
219
|
+
if isinstance(t, int_types):
|
|
220
|
+
return make_mpf(fadd(s.val, (t, 0, bitcount(t)), mpf._prec, mpf._rounding))
|
|
221
|
+
if isinstance(t, complex_types):
|
|
222
|
+
return mpc(s) + t
|
|
223
|
+
t = mpf(t)
|
|
224
|
+
return make_mpf(fadd(s.val, t.val, mpf._prec, mpf._rounding))
|
|
225
|
+
|
|
226
|
+
__radd__ = __add__
|
|
227
|
+
|
|
228
|
+
def __sub__(s, t):
|
|
229
|
+
if not isinstance(t, mpf):
|
|
230
|
+
if isinstance(t, int_types):
|
|
231
|
+
return make_mpf(fsub(s.val, (t, 0, bitcount(t)), mpf._prec, mpf._rounding))
|
|
232
|
+
if isinstance(t, complex_types):
|
|
233
|
+
return mpc(s) - t
|
|
234
|
+
t = mpf(t)
|
|
235
|
+
return make_mpf(fsub(s.val, t.val, mpf._prec, mpf._rounding))
|
|
236
|
+
|
|
237
|
+
def __rsub__(s, t):
|
|
238
|
+
if not isinstance(t, mpf):
|
|
239
|
+
if isinstance(t, int_types):
|
|
240
|
+
return make_mpf(fsub((t, 0, bitcount(t)), s.val, mpf._prec, mpf._rounding))
|
|
241
|
+
if isinstance(t, complex_types):
|
|
242
|
+
return t - mpc(s)
|
|
243
|
+
t = mpf(t)
|
|
244
|
+
return make_mpf(fsub(t.val, s.val, mpf._prec, mpf._rounding))
|
|
245
|
+
|
|
246
|
+
def __mul__(s, t):
|
|
247
|
+
if not isinstance(t, mpf):
|
|
248
|
+
if isinstance(t, int_types):
|
|
249
|
+
return make_mpf(normalize(s.val[0]*t, s.val[1], mpf._prec, mpf._rounding))
|
|
250
|
+
if isinstance(t, complex_types):
|
|
251
|
+
return mpc(s) * t
|
|
252
|
+
t = mpf(t)
|
|
253
|
+
return make_mpf(fmul(s.val, t.val, mpf._prec, mpf._rounding))
|
|
254
|
+
|
|
255
|
+
__rmul__ = __mul__
|
|
256
|
+
|
|
257
|
+
def __div__(s, t):
|
|
258
|
+
if not isinstance(t, mpf):
|
|
259
|
+
if isinstance(t, int_types):
|
|
260
|
+
return make_mpf(fdiv(s.val, (t, 0, bitcount(t)), mpf._prec, mpf._rounding))
|
|
261
|
+
if isinstance(t, complex_types):
|
|
262
|
+
return mpc(s) / t
|
|
263
|
+
t = mpf(t)
|
|
264
|
+
return make_mpf(fdiv(s.val, t.val, mpf._prec, mpf._rounding))
|
|
265
|
+
|
|
266
|
+
def __rdiv__(s, t):
|
|
267
|
+
if not isinstance(t, mpf):
|
|
268
|
+
if isinstance(t, int_types):
|
|
269
|
+
return make_mpf(fdiv((t, 0, bitcount(t)), s.val, mpf._prec, mpf._rounding))
|
|
270
|
+
if isinstance(t, complex_types):
|
|
271
|
+
return t / mpc(s)
|
|
272
|
+
t = mpf(t)
|
|
273
|
+
return make_mpf(fdiv(t.val, s.val, mpf._prec, mpf._rounding))
|
|
274
|
+
|
|
275
|
+
def __pow__(s, t):
|
|
276
|
+
if isinstance(t, int_types):
|
|
277
|
+
return make_mpf(fpow(s.val, t, mpf._prec, mpf._rounding))
|
|
278
|
+
if not isinstance(t, mpf):
|
|
279
|
+
if isinstance(t, complex_types):
|
|
280
|
+
return power(s, t)
|
|
281
|
+
t = mpf(t)
|
|
282
|
+
if t.val == fhalf:
|
|
283
|
+
return sqrt(s)
|
|
284
|
+
man, exp, bc = t.val
|
|
285
|
+
if exp >= 0:
|
|
286
|
+
return make_mpf(fpow(s.val, man<<exp, mpf._prec, mpf._rounding))
|
|
287
|
+
return power(s, t)
|
|
288
|
+
|
|
289
|
+
def __rpow__(s, t):
|
|
290
|
+
return convert_lossless(t) ** s
|
|
291
|
+
|
|
292
|
+
def sqrt(s):
|
|
293
|
+
return sqrt(s)
|
|
294
|
+
|
|
295
|
+
def ae(s, t, rel_eps=None, abs_eps=None):
|
|
296
|
+
"""
|
|
297
|
+
Determine whether the difference between s and t is smaller
|
|
298
|
+
than a given epsilon ("ae" is short for "almost equal").
|
|
299
|
+
|
|
300
|
+
Both a maximum relative difference and a maximum difference
|
|
301
|
+
('epsilons') may be specified. The absolute difference is
|
|
302
|
+
defined as |s-t| and the relative difference is defined
|
|
303
|
+
as |s-t|/max(|s|, |t|).
|
|
304
|
+
|
|
305
|
+
If only one epsilon is given, both are set to the same value.
|
|
306
|
+
If none is given, both epsilons are set to 2**(-prec+m) where
|
|
307
|
+
prec is the current working precision and m is a small integer.
|
|
308
|
+
"""
|
|
309
|
+
if not isinstance(t, mpf):
|
|
310
|
+
t = mpf(t)
|
|
311
|
+
if abs_eps is None and rel_eps is None:
|
|
312
|
+
rel_eps = abs_eps = make_mpf((1, -mpf._prec+4, 1))
|
|
313
|
+
if abs_eps is None:
|
|
314
|
+
abs_eps = rel_eps
|
|
315
|
+
elif rel_eps is None:
|
|
316
|
+
rel_eps = abs_eps
|
|
317
|
+
diff = abs(s-t)
|
|
318
|
+
if diff <= abs_eps:
|
|
319
|
+
return True
|
|
320
|
+
abss = abs(s)
|
|
321
|
+
abst = abs(t)
|
|
322
|
+
if abss < abst:
|
|
323
|
+
err = diff/abst
|
|
324
|
+
else:
|
|
325
|
+
err = diff/abss
|
|
326
|
+
return err <= rel_eps
|
|
327
|
+
|
|
328
|
+
def almost_zero(s, prec):
|
|
329
|
+
"""Quick check if |s| < 2**-prec. May return a false negative
|
|
330
|
+
if s is very close to the threshold."""
|
|
331
|
+
return s.bc + s.exp < prec
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def make_mpf(tpl, construct=object.__new__, cls=mpf):
|
|
335
|
+
"""Create mpf verbatim from a given tuple of data."""
|
|
336
|
+
a = construct(cls)
|
|
337
|
+
a.val = tpl
|
|
338
|
+
return a
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class mpc(mpnumeric):
|
|
342
|
+
"""An mpc represents a complex number using a pair of mpf:s (one
|
|
343
|
+
for the real part and another for the imaginary part.) The mpc
|
|
344
|
+
class behaves fairly similarly to Python's complex type."""
|
|
345
|
+
|
|
346
|
+
def __new__(cls, real=0, imag=0):
|
|
347
|
+
s = object.__new__(cls)
|
|
348
|
+
if isinstance(real, complex_types):
|
|
349
|
+
real, imag = real.real, real.imag
|
|
350
|
+
s.real = mpf(real)
|
|
351
|
+
s.imag = mpf(imag)
|
|
352
|
+
return s
|
|
353
|
+
|
|
354
|
+
def __repr__(s):
|
|
355
|
+
r = repr(s.real)[4:-1]
|
|
356
|
+
i = repr(s.imag)[4:-1]
|
|
357
|
+
return "mpc(real=%s, imag=%s)" % (r, i)
|
|
358
|
+
|
|
359
|
+
def __str__(s):
|
|
360
|
+
return "(%s + %sj)" % (s.real, s.imag)
|
|
361
|
+
|
|
362
|
+
def __complex__(s):
|
|
363
|
+
return complex(float(s.real), float(s.imag))
|
|
364
|
+
|
|
365
|
+
def __pos__(s):
|
|
366
|
+
return mpc(s.real, s.imag)
|
|
367
|
+
|
|
368
|
+
def __abs__(s):
|
|
369
|
+
return hypot(s.real, s.imag)
|
|
370
|
+
|
|
371
|
+
def __eq__(s, t):
|
|
372
|
+
if not isinstance(t, mpc):
|
|
373
|
+
if isinstance(t, str):
|
|
374
|
+
return False
|
|
375
|
+
t = mpc(t)
|
|
376
|
+
return s.real == t.real and s.imag == t.imag
|
|
377
|
+
|
|
378
|
+
def _compare(*args):
|
|
379
|
+
raise TypeError("no ordering relation is defined for complex numbers")
|
|
380
|
+
|
|
381
|
+
__gt__ = _compare
|
|
382
|
+
__le__ = _compare
|
|
383
|
+
__gt__ = _compare
|
|
384
|
+
__ge__ = _compare
|
|
385
|
+
|
|
386
|
+
def __nonzero__(s):
|
|
387
|
+
return bool(s.real) or bool(s.imag)
|
|
388
|
+
|
|
389
|
+
def conjugate(s):
|
|
390
|
+
return mpc(s.real, -s.imag)
|
|
391
|
+
|
|
392
|
+
def __add__(s, t):
|
|
393
|
+
if not isinstance(t, mpc):
|
|
394
|
+
t = mpc(t)
|
|
395
|
+
return mpc(s.real+t.real, s.imag+t.imag)
|
|
396
|
+
|
|
397
|
+
__radd__ = __add__
|
|
398
|
+
|
|
399
|
+
def __neg__(s):
|
|
400
|
+
return mpc(-s.real, -s.imag)
|
|
401
|
+
|
|
402
|
+
def __sub__(s, t):
|
|
403
|
+
if not isinstance(t, mpc):
|
|
404
|
+
t = mpc(t)
|
|
405
|
+
return mpc(s.real-t.real, s.imag-t.imag)
|
|
406
|
+
|
|
407
|
+
def __rsub__(s, t):
|
|
408
|
+
return (-s) + t
|
|
409
|
+
|
|
410
|
+
def __mul__(s, t):
|
|
411
|
+
if not isinstance(t, mpc):
|
|
412
|
+
t = mpc(t)
|
|
413
|
+
return mpc(*fcmul(s.real.val, s.imag.val, t.real.val, t.imag.val,
|
|
414
|
+
mpf._prec, mpf._rounding))
|
|
415
|
+
|
|
416
|
+
__rmul__ = __mul__
|
|
417
|
+
|
|
418
|
+
def __div__(s, t):
|
|
419
|
+
if not isinstance(t, mpc):
|
|
420
|
+
t = mpc(t)
|
|
421
|
+
a = s.real; b = s.imag; c = t.real; d = t.imag
|
|
422
|
+
mag = c*c + d*d
|
|
423
|
+
return mpc((a*c+b*d)/mag, (b*c-a*d)/mag)
|
|
424
|
+
|
|
425
|
+
def __rdiv__(s, t):
|
|
426
|
+
return mpc(t) / s
|
|
427
|
+
|
|
428
|
+
def __pow__(s, n):
|
|
429
|
+
if n == 0: return mpc(1)
|
|
430
|
+
if n == 1: return +s
|
|
431
|
+
if n == -1: return 1/s
|
|
432
|
+
if n == 2: return s*s
|
|
433
|
+
if isinstance(n, (int, long)) and n > 0:
|
|
434
|
+
# TODO: should increase working precision here
|
|
435
|
+
w = mpc(1)
|
|
436
|
+
while n:
|
|
437
|
+
if n & 1:
|
|
438
|
+
w = w*s
|
|
439
|
+
n -= 1
|
|
440
|
+
s = s*s
|
|
441
|
+
n //= 2
|
|
442
|
+
return w
|
|
443
|
+
if n == 0.5:
|
|
444
|
+
return sqrt(s)
|
|
445
|
+
return power(s, n)
|
|
446
|
+
|
|
447
|
+
def __rpow__(s, t):
|
|
448
|
+
return convert_lossless(t) ** s
|
|
449
|
+
|
|
450
|
+
# TODO: refactor and merge with mpf.ae
|
|
451
|
+
def ae(s, t, rel_eps=None, abs_eps=None):
|
|
452
|
+
if not isinstance(t, mpc):
|
|
453
|
+
t = mpc(t)
|
|
454
|
+
if abs_eps is None and rel_eps is None:
|
|
455
|
+
abs_eps = rel_eps = make_mpf((1, -mpf._prec+4, 1))
|
|
456
|
+
if abs_eps is None:
|
|
457
|
+
abs_eps = rel_eps
|
|
458
|
+
elif rel_eps is None:
|
|
459
|
+
rel_eps = abs_eps
|
|
460
|
+
diff = abs(s-t)
|
|
461
|
+
if diff <= abs_eps:
|
|
462
|
+
return True
|
|
463
|
+
abss = abs(s)
|
|
464
|
+
abst = abs(t)
|
|
465
|
+
if abss < abst:
|
|
466
|
+
err = diff/abst
|
|
467
|
+
else:
|
|
468
|
+
err = diff/abss
|
|
469
|
+
return err <= rel_eps
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
complex_types = (complex, mpc)
|
|
473
|
+
|
|
474
|
+
def make_mpc(tpl, construct=object.__new__, cls=mpc):
|
|
475
|
+
a = construct(cls)
|
|
476
|
+
a.real, a.imag = map(make_mpf, tpl)
|
|
477
|
+
return a
|
|
478
|
+
|
|
479
|
+
j = mpc(0,1)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
class constant(mpf):
|
|
483
|
+
"""Represents a mathematical constant with dynamic precision.
|
|
484
|
+
When printed or used in an arithmetic operation, a constant
|
|
485
|
+
is converted to a regular mpf at the working precision. A
|
|
486
|
+
regular mpf can also be obtained using the operation +x."""
|
|
487
|
+
|
|
488
|
+
def __new__(cls, func, name):
|
|
489
|
+
a = object.__new__(cls)
|
|
490
|
+
a.name = name
|
|
491
|
+
a.func = func
|
|
492
|
+
return a
|
|
493
|
+
|
|
494
|
+
@property
|
|
495
|
+
def val(self):
|
|
496
|
+
return self.func(mpf._prec, mpf._rounding)
|
|
497
|
+
|
|
498
|
+
#def __repr__(self):
|
|
499
|
+
# return "<%s: %s~>" % (self.name, mpf.__str__(self))
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
_180 = from_int(180, 10, ROUND_FLOOR)
|
|
503
|
+
|
|
504
|
+
pi = constant(fpi, "pi")
|
|
505
|
+
degree = constant(lambda p, r: fdiv(fpi(p+4, ROUND_FLOOR), _180, p, r), "degree")
|
|
506
|
+
e = constant(lambda p, r: fexp(fone, p, r), "e")
|
|
507
|
+
cgamma = constant(fgamma, "Euler's constant gamma")
|
|
508
|
+
clog2 = constant(flog2, "log(2)")
|
|
509
|
+
clog10 = constant(flog10, "log(10)")
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def sqrt(x):
|
|
513
|
+
"""For real x >= 0, returns the square root of x. For negative or
|
|
514
|
+
complex x, returns the principal branch of the complex square root
|
|
515
|
+
of x."""
|
|
516
|
+
x = convert_lossless(x)
|
|
517
|
+
if isinstance(x, mpf) and x.val[0] >= 0:
|
|
518
|
+
return make_mpf(fsqrt(x.val, mpf._prec, mpf._rounding))
|
|
519
|
+
x = mpc(x)
|
|
520
|
+
return make_mpc(fcsqrt(x.real.val, x.imag.val, mpf._prec, mpf._rounding))
|
|
521
|
+
|
|
522
|
+
def hypot(x, y):
|
|
523
|
+
"""Returns the Euclidean distance sqrt(x*x + y*y). Both x and y
|
|
524
|
+
must be real."""
|
|
525
|
+
x = mpf(x)
|
|
526
|
+
y = mpf(y)
|
|
527
|
+
return mpf(fhypot(x.val, y.val, mpf._prec, mpf._rounding))
|
|
528
|
+
|
|
529
|
+
# Since E-functions simply map reals to reals and complexes to complexes, we
|
|
530
|
+
# can construct all of them the same way (unlike log, sqrt, etc)
|
|
531
|
+
def ef(name, real_f, complex_f, doc):
|
|
532
|
+
def f(x):
|
|
533
|
+
x = convert_lossless(x)
|
|
534
|
+
if isinstance(x, mpf):
|
|
535
|
+
return make_mpf(real_f(x.val, mpf._prec, mpf._rounding))
|
|
536
|
+
else:
|
|
537
|
+
return make_mpc(complex_f(x.real.val, x.imag.val, mpf._prec,
|
|
538
|
+
mpf._rounding))
|
|
539
|
+
f.__name__ = name
|
|
540
|
+
f.__doc__ = doc
|
|
541
|
+
return f
|
|
542
|
+
|
|
543
|
+
exp = ef('exp', fexp, fcexp, "Returns the exponential function of x.")
|
|
544
|
+
cos = ef('cos', fcos, fccos, "Returns the cosine of x.")
|
|
545
|
+
sin = ef('sin', fsin, fcsin, "Returns the sine of x.")
|
|
546
|
+
cosh = ef('cosh', fcosh, fccosh, "Returns the hyperbolic cosine of x.")
|
|
547
|
+
sinh = ef('sinh', fsinh, fcsinh, "Returns the hyperbolic sine of x.")
|
|
548
|
+
|
|
549
|
+
# TODO: implement tanh and complex tan in lib instead
|
|
550
|
+
def tan(x):
|
|
551
|
+
"""Returns the tangent of x."""
|
|
552
|
+
x = convert_lossless(x)
|
|
553
|
+
if isinstance(x, mpf):
|
|
554
|
+
return make_mpf(ftan(x.val, mpf._prec, mpf._rounding))
|
|
555
|
+
# the complex division can cause enormous cancellation.
|
|
556
|
+
# TODO: handle more robustly
|
|
557
|
+
mpf._prec += 20
|
|
558
|
+
t = sin(x) / cos(x)
|
|
559
|
+
mpf._prec -= 20
|
|
560
|
+
return +t
|
|
561
|
+
|
|
562
|
+
def tanh(x):
|
|
563
|
+
"""Returns the hyperbolic tangent of x."""
|
|
564
|
+
x = convert_lossless(x)
|
|
565
|
+
oldprec = mpf._prec
|
|
566
|
+
a = abs(x)
|
|
567
|
+
mpf._prec += 10
|
|
568
|
+
high = a.exp + a.bc
|
|
569
|
+
if high < -10:
|
|
570
|
+
if high < (-(mpf._prec-10) * 0.3):
|
|
571
|
+
return x - (x**3)/3 + 2*(x**5)/15
|
|
572
|
+
mpf._prec += (-high)
|
|
573
|
+
a = exp(2*x)
|
|
574
|
+
t = (a-1)/(a+1)
|
|
575
|
+
mpf._prec = oldprec
|
|
576
|
+
return +t
|
|
577
|
+
|
|
578
|
+
def arg(x):
|
|
579
|
+
"""Returns the complex argument (phase) of x. The returned value is
|
|
580
|
+
an mpf instance. The argument is here defined to satisfy
|
|
581
|
+
-pi < arg(x) <= pi. On the negative real half-axis, it is taken to
|
|
582
|
+
be +pi."""
|
|
583
|
+
x = mpc(x)
|
|
584
|
+
mpf._prec += 5
|
|
585
|
+
t = atan2(x.imag, x.real)
|
|
586
|
+
mpf._prec -= 5
|
|
587
|
+
return +t
|
|
588
|
+
|
|
589
|
+
def log(x, b=None):
|
|
590
|
+
"""Returns the base-b logarithm of x. If b is unspecified, return
|
|
591
|
+
the natural (base-e) logarithm. log(x, b) is defined as
|
|
592
|
+
log(x)/log(b). log(0) raises ValueError.
|
|
593
|
+
|
|
594
|
+
The natural logarithm is real if x > 0 and complex if x < 0 or if x
|
|
595
|
+
is complex. The principal branch of the complex logarithm is chosen,
|
|
596
|
+
for which Im(log(x)) = -pi < arg(x) <= pi. """
|
|
597
|
+
if b is not None:
|
|
598
|
+
mpf.prec += 3
|
|
599
|
+
a = log(x) / log(b)
|
|
600
|
+
mpf.prec -= 3
|
|
601
|
+
return +a
|
|
602
|
+
x = convert_lossless(x)
|
|
603
|
+
if not x:
|
|
604
|
+
raise ValueError, "logarithm of 0"
|
|
605
|
+
if isinstance(x, mpf) and x.val[0] > 0:
|
|
606
|
+
return make_mpf(flog(x.val, mpf._prec, mpf._rounding))
|
|
607
|
+
else:
|
|
608
|
+
return mpc(log(abs(x)), arg(x))
|
|
609
|
+
|
|
610
|
+
def power(x, y):
|
|
611
|
+
"""Returns x**y = exp(y*log(x)) for real or complex x and y."""
|
|
612
|
+
# TODO: better estimate for extra precision needed
|
|
613
|
+
mpf._prec += 10
|
|
614
|
+
t = exp(y * log(x))
|
|
615
|
+
mpf._prec -= 10
|
|
616
|
+
return +t
|
|
617
|
+
|
|
618
|
+
def atan(x):
|
|
619
|
+
"""Returns the inverse tangent of x."""
|
|
620
|
+
x = convert_lossless(x)
|
|
621
|
+
if isinstance(x, mpf):
|
|
622
|
+
return make_mpf(fatan(x.val, mpf._prec, mpf._rounding))
|
|
623
|
+
# TODO: maybe get this to agree with Python's cmath atan about the
|
|
624
|
+
# branch to choose on the imaginary axis
|
|
625
|
+
# TODO: handle cancellation robustly
|
|
626
|
+
mpf._prec += 10
|
|
627
|
+
t = (0.5j)*(log(1-1j*x) - log(1+1j*x))
|
|
628
|
+
mpf._prec -= 10
|
|
629
|
+
return +t
|
|
630
|
+
|
|
631
|
+
def atan2(y,x):
|
|
632
|
+
"""atan2(y, x) has the same magnitude as atan(y/x) but accounts for
|
|
633
|
+
the signs of y and x. (Defined for real x and y only.)"""
|
|
634
|
+
x = mpf(x)
|
|
635
|
+
y = mpf(y)
|
|
636
|
+
if y < 0:
|
|
637
|
+
return -atan2(-y, x)
|
|
638
|
+
if not x and not y:
|
|
639
|
+
return mpf(0)
|
|
640
|
+
if y > 0 and x == 0:
|
|
641
|
+
mpf._prec += 2
|
|
642
|
+
t = pi/2
|
|
643
|
+
mpf._prec -= 2
|
|
644
|
+
return t
|
|
645
|
+
mpf._prec += 2
|
|
646
|
+
if x > 0:
|
|
647
|
+
a = atan(y/x)
|
|
648
|
+
else:
|
|
649
|
+
a = pi - atan(-y/x)
|
|
650
|
+
mpf._prec -= 2
|
|
651
|
+
return +a
|
|
652
|
+
|
|
653
|
+
# TODO: robustly deal with cancellation in all of the following functions
|
|
654
|
+
|
|
655
|
+
def _asin_complex(z):
|
|
656
|
+
mpf._prec += 10
|
|
657
|
+
t = -1j * log(1j * z + sqrt(1 - z*z))
|
|
658
|
+
mpf._prec -= 10
|
|
659
|
+
return +t
|
|
660
|
+
|
|
661
|
+
def asin(x):
|
|
662
|
+
"""Returns the inverse sine of x. Outside the range [-1, 1], the
|
|
663
|
+
result is complex and defined as the principal branch value of
|
|
664
|
+
-i * log(i * x + sqrt(1 - x**2))."""
|
|
665
|
+
x = convert_lossless(x)
|
|
666
|
+
if isinstance(x, mpf) and abs(x) <= 1:
|
|
667
|
+
return _asin_complex(x).real
|
|
668
|
+
return _asin_complex(x)
|
|
669
|
+
|
|
670
|
+
def _acos_complex(z):
|
|
671
|
+
mpf._prec += 10
|
|
672
|
+
t = pi/2 + 1j * log(1j * z + sqrt(1 - z*z))
|
|
673
|
+
mpf._prec -= 10
|
|
674
|
+
return +t
|
|
675
|
+
|
|
676
|
+
def acos(x):
|
|
677
|
+
"""Returns the inverse cosine of x. Outside the range [-1, 1], the
|
|
678
|
+
result is complex and defined as the principal branch value of
|
|
679
|
+
pi/2 + i * log(i * x + sqrt(1 - x**2))."""
|
|
680
|
+
x = convert_lossless(x)
|
|
681
|
+
if isinstance(x, mpf) and abs(x) <= 1:
|
|
682
|
+
return _acos_complex(x).real
|
|
683
|
+
return _acos_complex(x)
|
|
684
|
+
|
|
685
|
+
def asinh(x):
|
|
686
|
+
"""Returns the inverse hyperbolic sine of x. For complex x, the
|
|
687
|
+
result is the principal branch value of log(x + sqrt(1 + x**2))."""
|
|
688
|
+
x = convert_lossless(x)
|
|
689
|
+
oldprec = mpf._prec
|
|
690
|
+
a = abs(x)
|
|
691
|
+
mpf._prec += 10
|
|
692
|
+
high = a.exp + a.bc
|
|
693
|
+
if high < -10:
|
|
694
|
+
if high < (-(mpf._prec-10) * 0.3):
|
|
695
|
+
return x - (x**3)/6 + 3*(x**5)/40
|
|
696
|
+
mpf._prec += (-high)
|
|
697
|
+
t = log(x + sqrt(x**2 + 1))
|
|
698
|
+
mpf._prec = oldprec
|
|
699
|
+
return +t
|
|
700
|
+
|
|
701
|
+
def acosh(x):
|
|
702
|
+
"""Returns the inverse hyperbolic cosine of x. The value is
|
|
703
|
+
given by log(x + sqrt(1 + x**2)), where the principal branch is
|
|
704
|
+
used when the result is complex."""
|
|
705
|
+
x = convert_lossless(x)
|
|
706
|
+
mpf._prec += 10
|
|
707
|
+
t = log(x + sqrt(x-1)*sqrt(x+1))
|
|
708
|
+
mpf._prec -= 10
|
|
709
|
+
return +t
|
|
710
|
+
|
|
711
|
+
def atanh(x):
|
|
712
|
+
"""Returns the inverse hyperbolic tangent of x. Outside the range
|
|
713
|
+
[-1, 1], the result is complex and defined as the principal branch
|
|
714
|
+
value of (log(1+x) - log(1-x))/2."""
|
|
715
|
+
x = convert_lossless(x)
|
|
716
|
+
oldprec = mpf._prec
|
|
717
|
+
a = abs(x)
|
|
718
|
+
mpf._prec += 10
|
|
719
|
+
high = a.exp + a.bc
|
|
720
|
+
if high < -10:
|
|
721
|
+
#print mpf._prec, x, x-(x**3)/3+(x**5)/5
|
|
722
|
+
if high < (-(mpf._prec-10) * 0.3):
|
|
723
|
+
return x - (x**3)/3 + (x**5)/5
|
|
724
|
+
mpf._prec += (-high)
|
|
725
|
+
t = 0.5*(log(1+x)-log(1-x))
|
|
726
|
+
mpf._prec = oldprec
|
|
727
|
+
return +t
|
|
728
|
+
|
|
729
|
+
def rand():
|
|
730
|
+
"""Return an mpf chosen randomly from [0, 1)."""
|
|
731
|
+
return make_mpf(frand(mpf._prec))
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
__all__ = ["mpnumeric", "mpf", "mpc", "pi", "e", "cgamma", "clog2", "clog10",
|
|
735
|
+
"j", "sqrt", "hypot", "exp", "log", "cos", "sin", "tan", "atan", "atan2",
|
|
736
|
+
"power", "asin", "acos", "sinh", "cosh", "tanh", "asinh", "acosh", "atanh",
|
|
737
|
+
"arg", "degree", "rand"]
|
|
738
|
+
|
|
739
|
+
|