shomez commited on
Commit
4de5125
·
verified ·
1 Parent(s): 07e974c

Upload ctx_mp_python.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. ctx_mp_python.py +1149 -0
ctx_mp_python.py ADDED
@@ -0,0 +1,1149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #from ctx_base import StandardBaseContext
2
+
3
+ from .libmp.backend import basestring, exec_
4
+
5
+ from .libmp import (MPZ, MPZ_ZERO, MPZ_ONE, int_types, repr_dps,
6
+ round_floor, round_ceiling, dps_to_prec, round_nearest, prec_to_dps,
7
+ ComplexResult, to_pickable, from_pickable, normalize,
8
+ from_int, from_float, from_npfloat, from_Decimal, from_str, to_int, to_float, to_str,
9
+ from_rational, from_man_exp,
10
+ fone, fzero, finf, fninf, fnan,
11
+ mpf_abs, mpf_pos, mpf_neg, mpf_add, mpf_sub, mpf_mul, mpf_mul_int,
12
+ mpf_div, mpf_rdiv_int, mpf_pow_int, mpf_mod,
13
+ mpf_eq, mpf_cmp, mpf_lt, mpf_gt, mpf_le, mpf_ge,
14
+ mpf_hash, mpf_rand,
15
+ mpf_sum,
16
+ bitcount, to_fixed,
17
+ mpc_to_str,
18
+ mpc_to_complex, mpc_hash, mpc_pos, mpc_is_nonzero, mpc_neg, mpc_conjugate,
19
+ mpc_abs, mpc_add, mpc_add_mpf, mpc_sub, mpc_sub_mpf, mpc_mul, mpc_mul_mpf,
20
+ mpc_mul_int, mpc_div, mpc_div_mpf, mpc_pow, mpc_pow_mpf, mpc_pow_int,
21
+ mpc_mpf_div,
22
+ mpf_pow,
23
+ mpf_pi, mpf_degree, mpf_e, mpf_phi, mpf_ln2, mpf_ln10,
24
+ mpf_euler, mpf_catalan, mpf_apery, mpf_khinchin,
25
+ mpf_glaisher, mpf_twinprime, mpf_mertens,
26
+ int_types)
27
+
28
+ from . import rational
29
+ from . import function_docs
30
+
31
+ new = object.__new__
32
+
33
+ class mpnumeric(object):
34
+ """Base class for mpf and mpc."""
35
+ __slots__ = []
36
+ def __new__(cls, val):
37
+ raise NotImplementedError
38
+
39
+ class _mpf(mpnumeric):
40
+ """
41
+ An mpf instance holds a real-valued floating-point number. mpf:s
42
+ work analogously to Python floats, but support arbitrary-precision
43
+ arithmetic.
44
+ """
45
+ __slots__ = ['_mpf_']
46
+
47
+ def __new__(cls, val=fzero, **kwargs):
48
+ """A new mpf can be created from a Python float, an int, a
49
+ or a decimal string representing a number in floating-point
50
+ format."""
51
+ prec, rounding = cls.context._prec_rounding
52
+ if kwargs:
53
+ prec = kwargs.get('prec', prec)
54
+ if 'dps' in kwargs:
55
+ prec = dps_to_prec(kwargs['dps'])
56
+ rounding = kwargs.get('rounding', rounding)
57
+ if type(val) is cls:
58
+ sign, man, exp, bc = val._mpf_
59
+ if (not man) and exp:
60
+ return val
61
+ v = new(cls)
62
+ v._mpf_ = normalize(sign, man, exp, bc, prec, rounding)
63
+ return v
64
+ elif type(val) is tuple:
65
+ if len(val) == 2:
66
+ v = new(cls)
67
+ v._mpf_ = from_man_exp(val[0], val[1], prec, rounding)
68
+ return v
69
+ if len(val) == 4:
70
+ if val not in (finf, fninf, fnan):
71
+ sign, man, exp, bc = val
72
+ val = normalize(sign, MPZ(man), exp, bc, prec, rounding)
73
+ v = new(cls)
74
+ v._mpf_ = val
75
+ return v
76
+ raise ValueError
77
+ else:
78
+ v = new(cls)
79
+ v._mpf_ = mpf_pos(cls.mpf_convert_arg(val, prec, rounding), prec, rounding)
80
+ return v
81
+
82
+ @classmethod
83
+ def mpf_convert_arg(cls, x, prec, rounding):
84
+ if isinstance(x, int_types): return from_int(x)
85
+ if isinstance(x, float): return from_float(x)
86
+ if isinstance(x, basestring): return from_str(x, prec, rounding)
87
+ if isinstance(x, cls.context.constant): return x.func(prec, rounding)
88
+ if hasattr(x, '_mpf_'): return x._mpf_
89
+ if hasattr(x, '_mpmath_'):
90
+ t = cls.context.convert(x._mpmath_(prec, rounding))
91
+ if hasattr(t, '_mpf_'):
92
+ return t._mpf_
93
+ if hasattr(x, '_mpi_'):
94
+ a, b = x._mpi_
95
+ if a == b:
96
+ return a
97
+ raise ValueError("can only create mpf from zero-width interval")
98
+ raise TypeError("cannot create mpf from " + repr(x))
99
+
100
+ @classmethod
101
+ def mpf_convert_rhs(cls, x):
102
+ if isinstance(x, int_types): return from_int(x)
103
+ if isinstance(x, float): return from_float(x)
104
+ if isinstance(x, complex_types): return cls.context.mpc(x)
105
+ if isinstance(x, rational.mpq):
106
+ p, q = x._mpq_
107
+ return from_rational(p, q, cls.context.prec)
108
+ if hasattr(x, '_mpf_'): return x._mpf_
109
+ if hasattr(x, '_mpmath_'):
110
+ t = cls.context.convert(x._mpmath_(*cls.context._prec_rounding))
111
+ if hasattr(t, '_mpf_'):
112
+ return t._mpf_
113
+ return t
114
+ return NotImplemented
115
+
116
+ @classmethod
117
+ def mpf_convert_lhs(cls, x):
118
+ x = cls.mpf_convert_rhs(x)
119
+ if type(x) is tuple:
120
+ return cls.context.make_mpf(x)
121
+ return x
122
+
123
+ man_exp = property(lambda self: self._mpf_[1:3])
124
+ man = property(lambda self: self._mpf_[1])
125
+ exp = property(lambda self: self._mpf_[2])
126
+ bc = property(lambda self: self._mpf_[3])
127
+
128
+ real = property(lambda self: self)
129
+ imag = property(lambda self: self.context.zero)
130
+
131
+ conjugate = lambda self: self
132
+
133
+ def __getstate__(self): return to_pickable(self._mpf_)
134
+ def __setstate__(self, val): self._mpf_ = from_pickable(val)
135
+
136
+ def __repr__(s):
137
+ if s.context.pretty:
138
+ return str(s)
139
+ return "mpf('%s')" % to_str(s._mpf_, s.context._repr_digits)
140
+
141
+ def __str__(s): return to_str(s._mpf_, s.context._str_digits)
142
+ def __hash__(s): return mpf_hash(s._mpf_)
143
+ def __int__(s): return int(to_int(s._mpf_))
144
+ def __long__(s): return long(to_int(s._mpf_))
145
+ def __float__(s): return to_float(s._mpf_, rnd=s.context._prec_rounding[1])
146
+ def __complex__(s): return complex(float(s))
147
+ def __nonzero__(s): return s._mpf_ != fzero
148
+
149
+ __bool__ = __nonzero__
150
+
151
+ def __abs__(s):
152
+ cls, new, (prec, rounding) = s._ctxdata
153
+ v = new(cls)
154
+ v._mpf_ = mpf_abs(s._mpf_, prec, rounding)
155
+ return v
156
+
157
+ def __pos__(s):
158
+ cls, new, (prec, rounding) = s._ctxdata
159
+ v = new(cls)
160
+ v._mpf_ = mpf_pos(s._mpf_, prec, rounding)
161
+ return v
162
+
163
+ def __neg__(s):
164
+ cls, new, (prec, rounding) = s._ctxdata
165
+ v = new(cls)
166
+ v._mpf_ = mpf_neg(s._mpf_, prec, rounding)
167
+ return v
168
+
169
+ def _cmp(s, t, func):
170
+ if hasattr(t, '_mpf_'):
171
+ t = t._mpf_
172
+ else:
173
+ t = s.mpf_convert_rhs(t)
174
+ if t is NotImplemented:
175
+ return t
176
+ return func(s._mpf_, t)
177
+
178
+ def __cmp__(s, t): return s._cmp(t, mpf_cmp)
179
+ def __lt__(s, t): return s._cmp(t, mpf_lt)
180
+ def __gt__(s, t): return s._cmp(t, mpf_gt)
181
+ def __le__(s, t): return s._cmp(t, mpf_le)
182
+ def __ge__(s, t): return s._cmp(t, mpf_ge)
183
+
184
+ def __ne__(s, t):
185
+ v = s.__eq__(t)
186
+ if v is NotImplemented:
187
+ return v
188
+ return not v
189
+
190
+ def __rsub__(s, t):
191
+ cls, new, (prec, rounding) = s._ctxdata
192
+ if type(t) in int_types:
193
+ v = new(cls)
194
+ v._mpf_ = mpf_sub(from_int(t), s._mpf_, prec, rounding)
195
+ return v
196
+ t = s.mpf_convert_lhs(t)
197
+ if t is NotImplemented:
198
+ return t
199
+ return t - s
200
+
201
+ def __rdiv__(s, t):
202
+ cls, new, (prec, rounding) = s._ctxdata
203
+ if isinstance(t, int_types):
204
+ v = new(cls)
205
+ v._mpf_ = mpf_rdiv_int(t, s._mpf_, prec, rounding)
206
+ return v
207
+ t = s.mpf_convert_lhs(t)
208
+ if t is NotImplemented:
209
+ return t
210
+ return t / s
211
+
212
+ def __rpow__(s, t):
213
+ t = s.mpf_convert_lhs(t)
214
+ if t is NotImplemented:
215
+ return t
216
+ return t ** s
217
+
218
+ def __rmod__(s, t):
219
+ t = s.mpf_convert_lhs(t)
220
+ if t is NotImplemented:
221
+ return t
222
+ return t % s
223
+
224
+ def sqrt(s):
225
+ return s.context.sqrt(s)
226
+
227
+ def ae(s, t, rel_eps=None, abs_eps=None):
228
+ return s.context.almosteq(s, t, rel_eps, abs_eps)
229
+
230
+ def to_fixed(self, prec):
231
+ return to_fixed(self._mpf_, prec)
232
+
233
+ def __round__(self, *args):
234
+ return round(float(self), *args)
235
+
236
+ mpf_binary_op = """
237
+ def %NAME%(self, other):
238
+ mpf, new, (prec, rounding) = self._ctxdata
239
+ sval = self._mpf_
240
+ if hasattr(other, '_mpf_'):
241
+ tval = other._mpf_
242
+ %WITH_MPF%
243
+ ttype = type(other)
244
+ if ttype in int_types:
245
+ %WITH_INT%
246
+ elif ttype is float:
247
+ tval = from_float(other)
248
+ %WITH_MPF%
249
+ elif hasattr(other, '_mpc_'):
250
+ tval = other._mpc_
251
+ mpc = type(other)
252
+ %WITH_MPC%
253
+ elif ttype is complex:
254
+ tval = from_float(other.real), from_float(other.imag)
255
+ mpc = self.context.mpc
256
+ %WITH_MPC%
257
+ if isinstance(other, mpnumeric):
258
+ return NotImplemented
259
+ try:
260
+ other = mpf.context.convert(other, strings=False)
261
+ except TypeError:
262
+ return NotImplemented
263
+ return self.%NAME%(other)
264
+ """
265
+
266
+ return_mpf = "; obj = new(mpf); obj._mpf_ = val; return obj"
267
+ return_mpc = "; obj = new(mpc); obj._mpc_ = val; return obj"
268
+
269
+ mpf_pow_same = """
270
+ try:
271
+ val = mpf_pow(sval, tval, prec, rounding) %s
272
+ except ComplexResult:
273
+ if mpf.context.trap_complex:
274
+ raise
275
+ mpc = mpf.context.mpc
276
+ val = mpc_pow((sval, fzero), (tval, fzero), prec, rounding) %s
277
+ """ % (return_mpf, return_mpc)
278
+
279
+ def binary_op(name, with_mpf='', with_int='', with_mpc=''):
280
+ code = mpf_binary_op
281
+ code = code.replace("%WITH_INT%", with_int)
282
+ code = code.replace("%WITH_MPC%", with_mpc)
283
+ code = code.replace("%WITH_MPF%", with_mpf)
284
+ code = code.replace("%NAME%", name)
285
+ np = {}
286
+ exec_(code, globals(), np)
287
+ return np[name]
288
+
289
+ _mpf.__eq__ = binary_op('__eq__',
290
+ 'return mpf_eq(sval, tval)',
291
+ 'return mpf_eq(sval, from_int(other))',
292
+ 'return (tval[1] == fzero) and mpf_eq(tval[0], sval)')
293
+
294
+ _mpf.__add__ = binary_op('__add__',
295
+ 'val = mpf_add(sval, tval, prec, rounding)' + return_mpf,
296
+ 'val = mpf_add(sval, from_int(other), prec, rounding)' + return_mpf,
297
+ 'val = mpc_add_mpf(tval, sval, prec, rounding)' + return_mpc)
298
+
299
+ _mpf.__sub__ = binary_op('__sub__',
300
+ 'val = mpf_sub(sval, tval, prec, rounding)' + return_mpf,
301
+ 'val = mpf_sub(sval, from_int(other), prec, rounding)' + return_mpf,
302
+ 'val = mpc_sub((sval, fzero), tval, prec, rounding)' + return_mpc)
303
+
304
+ _mpf.__mul__ = binary_op('__mul__',
305
+ 'val = mpf_mul(sval, tval, prec, rounding)' + return_mpf,
306
+ 'val = mpf_mul_int(sval, other, prec, rounding)' + return_mpf,
307
+ 'val = mpc_mul_mpf(tval, sval, prec, rounding)' + return_mpc)
308
+
309
+ _mpf.__div__ = binary_op('__div__',
310
+ 'val = mpf_div(sval, tval, prec, rounding)' + return_mpf,
311
+ 'val = mpf_div(sval, from_int(other), prec, rounding)' + return_mpf,
312
+ 'val = mpc_mpf_div(sval, tval, prec, rounding)' + return_mpc)
313
+
314
+ _mpf.__mod__ = binary_op('__mod__',
315
+ 'val = mpf_mod(sval, tval, prec, rounding)' + return_mpf,
316
+ 'val = mpf_mod(sval, from_int(other), prec, rounding)' + return_mpf,
317
+ 'raise NotImplementedError("complex modulo")')
318
+
319
+ _mpf.__pow__ = binary_op('__pow__',
320
+ mpf_pow_same,
321
+ 'val = mpf_pow_int(sval, other, prec, rounding)' + return_mpf,
322
+ 'val = mpc_pow((sval, fzero), tval, prec, rounding)' + return_mpc)
323
+
324
+ _mpf.__radd__ = _mpf.__add__
325
+ _mpf.__rmul__ = _mpf.__mul__
326
+ _mpf.__truediv__ = _mpf.__div__
327
+ _mpf.__rtruediv__ = _mpf.__rdiv__
328
+
329
+
330
+ class _constant(_mpf):
331
+ """Represents a mathematical constant with dynamic precision.
332
+ When printed or used in an arithmetic operation, a constant
333
+ is converted to a regular mpf at the working precision. A
334
+ regular mpf can also be obtained using the operation +x."""
335
+
336
+ def __new__(cls, func, name, docname=''):
337
+ a = object.__new__(cls)
338
+ a.name = name
339
+ a.func = func
340
+ a.__doc__ = getattr(function_docs, docname, '')
341
+ return a
342
+
343
+ def __call__(self, prec=None, dps=None, rounding=None):
344
+ prec2, rounding2 = self.context._prec_rounding
345
+ if not prec: prec = prec2
346
+ if not rounding: rounding = rounding2
347
+ if dps: prec = dps_to_prec(dps)
348
+ return self.context.make_mpf(self.func(prec, rounding))
349
+
350
+ @property
351
+ def _mpf_(self):
352
+ prec, rounding = self.context._prec_rounding
353
+ return self.func(prec, rounding)
354
+
355
+ def __repr__(self):
356
+ return "<%s: %s~>" % (self.name, self.context.nstr(self(dps=15)))
357
+
358
+
359
+ class _mpc(mpnumeric):
360
+ """
361
+ An mpc represents a complex number using a pair of mpf:s (one
362
+ for the real part and another for the imaginary part.) The mpc
363
+ class behaves fairly similarly to Python's complex type.
364
+ """
365
+
366
+ __slots__ = ['_mpc_']
367
+
368
+ def __new__(cls, real=0, imag=0):
369
+ s = object.__new__(cls)
370
+ if isinstance(real, complex_types):
371
+ real, imag = real.real, real.imag
372
+ elif hasattr(real, '_mpc_'):
373
+ s._mpc_ = real._mpc_
374
+ return s
375
+ real = cls.context.mpf(real)
376
+ imag = cls.context.mpf(imag)
377
+ s._mpc_ = (real._mpf_, imag._mpf_)
378
+ return s
379
+
380
+ real = property(lambda self: self.context.make_mpf(self._mpc_[0]))
381
+ imag = property(lambda self: self.context.make_mpf(self._mpc_[1]))
382
+
383
+ def __getstate__(self):
384
+ return to_pickable(self._mpc_[0]), to_pickable(self._mpc_[1])
385
+
386
+ def __setstate__(self, val):
387
+ self._mpc_ = from_pickable(val[0]), from_pickable(val[1])
388
+
389
+ def __repr__(s):
390
+ if s.context.pretty:
391
+ return str(s)
392
+ r = repr(s.real)[4:-1]
393
+ i = repr(s.imag)[4:-1]
394
+ return "%s(real=%s, imag=%s)" % (type(s).__name__, r, i)
395
+
396
+ def __str__(s):
397
+ return "(%s)" % mpc_to_str(s._mpc_, s.context._str_digits)
398
+
399
+ def __complex__(s):
400
+ return mpc_to_complex(s._mpc_, rnd=s.context._prec_rounding[1])
401
+
402
+ def __pos__(s):
403
+ cls, new, (prec, rounding) = s._ctxdata
404
+ v = new(cls)
405
+ v._mpc_ = mpc_pos(s._mpc_, prec, rounding)
406
+ return v
407
+
408
+ def __abs__(s):
409
+ prec, rounding = s.context._prec_rounding
410
+ v = new(s.context.mpf)
411
+ v._mpf_ = mpc_abs(s._mpc_, prec, rounding)
412
+ return v
413
+
414
+ def __neg__(s):
415
+ cls, new, (prec, rounding) = s._ctxdata
416
+ v = new(cls)
417
+ v._mpc_ = mpc_neg(s._mpc_, prec, rounding)
418
+ return v
419
+
420
+ def conjugate(s):
421
+ cls, new, (prec, rounding) = s._ctxdata
422
+ v = new(cls)
423
+ v._mpc_ = mpc_conjugate(s._mpc_, prec, rounding)
424
+ return v
425
+
426
+ def __nonzero__(s):
427
+ return mpc_is_nonzero(s._mpc_)
428
+
429
+ __bool__ = __nonzero__
430
+
431
+ def __hash__(s):
432
+ return mpc_hash(s._mpc_)
433
+
434
+ @classmethod
435
+ def mpc_convert_lhs(cls, x):
436
+ try:
437
+ y = cls.context.convert(x)
438
+ return y
439
+ except TypeError:
440
+ return NotImplemented
441
+
442
+ def __eq__(s, t):
443
+ if not hasattr(t, '_mpc_'):
444
+ if isinstance(t, str):
445
+ return False
446
+ t = s.mpc_convert_lhs(t)
447
+ if t is NotImplemented:
448
+ return t
449
+ return s.real == t.real and s.imag == t.imag
450
+
451
+ def __ne__(s, t):
452
+ b = s.__eq__(t)
453
+ if b is NotImplemented:
454
+ return b
455
+ return not b
456
+
457
+ def _compare(*args):
458
+ raise TypeError("no ordering relation is defined for complex numbers")
459
+
460
+ __gt__ = _compare
461
+ __le__ = _compare
462
+ __gt__ = _compare
463
+ __ge__ = _compare
464
+
465
+ def __add__(s, t):
466
+ cls, new, (prec, rounding) = s._ctxdata
467
+ if not hasattr(t, '_mpc_'):
468
+ t = s.mpc_convert_lhs(t)
469
+ if t is NotImplemented:
470
+ return t
471
+ if hasattr(t, '_mpf_'):
472
+ v = new(cls)
473
+ v._mpc_ = mpc_add_mpf(s._mpc_, t._mpf_, prec, rounding)
474
+ return v
475
+ v = new(cls)
476
+ v._mpc_ = mpc_add(s._mpc_, t._mpc_, prec, rounding)
477
+ return v
478
+
479
+ def __sub__(s, t):
480
+ cls, new, (prec, rounding) = s._ctxdata
481
+ if not hasattr(t, '_mpc_'):
482
+ t = s.mpc_convert_lhs(t)
483
+ if t is NotImplemented:
484
+ return t
485
+ if hasattr(t, '_mpf_'):
486
+ v = new(cls)
487
+ v._mpc_ = mpc_sub_mpf(s._mpc_, t._mpf_, prec, rounding)
488
+ return v
489
+ v = new(cls)
490
+ v._mpc_ = mpc_sub(s._mpc_, t._mpc_, prec, rounding)
491
+ return v
492
+
493
+ def __mul__(s, t):
494
+ cls, new, (prec, rounding) = s._ctxdata
495
+ if not hasattr(t, '_mpc_'):
496
+ if isinstance(t, int_types):
497
+ v = new(cls)
498
+ v._mpc_ = mpc_mul_int(s._mpc_, t, prec, rounding)
499
+ return v
500
+ t = s.mpc_convert_lhs(t)
501
+ if t is NotImplemented:
502
+ return t
503
+ if hasattr(t, '_mpf_'):
504
+ v = new(cls)
505
+ v._mpc_ = mpc_mul_mpf(s._mpc_, t._mpf_, prec, rounding)
506
+ return v
507
+ t = s.mpc_convert_lhs(t)
508
+ v = new(cls)
509
+ v._mpc_ = mpc_mul(s._mpc_, t._mpc_, prec, rounding)
510
+ return v
511
+
512
+ def __div__(s, t):
513
+ cls, new, (prec, rounding) = s._ctxdata
514
+ if not hasattr(t, '_mpc_'):
515
+ t = s.mpc_convert_lhs(t)
516
+ if t is NotImplemented:
517
+ return t
518
+ if hasattr(t, '_mpf_'):
519
+ v = new(cls)
520
+ v._mpc_ = mpc_div_mpf(s._mpc_, t._mpf_, prec, rounding)
521
+ return v
522
+ v = new(cls)
523
+ v._mpc_ = mpc_div(s._mpc_, t._mpc_, prec, rounding)
524
+ return v
525
+
526
+ def __pow__(s, t):
527
+ cls, new, (prec, rounding) = s._ctxdata
528
+ if isinstance(t, int_types):
529
+ v = new(cls)
530
+ v._mpc_ = mpc_pow_int(s._mpc_, t, prec, rounding)
531
+ return v
532
+ t = s.mpc_convert_lhs(t)
533
+ if t is NotImplemented:
534
+ return t
535
+ v = new(cls)
536
+ if hasattr(t, '_mpf_'):
537
+ v._mpc_ = mpc_pow_mpf(s._mpc_, t._mpf_, prec, rounding)
538
+ else:
539
+ v._mpc_ = mpc_pow(s._mpc_, t._mpc_, prec, rounding)
540
+ return v
541
+
542
+ __radd__ = __add__
543
+
544
+ def __rsub__(s, t):
545
+ t = s.mpc_convert_lhs(t)
546
+ if t is NotImplemented:
547
+ return t
548
+ return t - s
549
+
550
+ def __rmul__(s, t):
551
+ cls, new, (prec, rounding) = s._ctxdata
552
+ if isinstance(t, int_types):
553
+ v = new(cls)
554
+ v._mpc_ = mpc_mul_int(s._mpc_, t, prec, rounding)
555
+ return v
556
+ t = s.mpc_convert_lhs(t)
557
+ if t is NotImplemented:
558
+ return t
559
+ return t * s
560
+
561
+ def __rdiv__(s, t):
562
+ t = s.mpc_convert_lhs(t)
563
+ if t is NotImplemented:
564
+ return t
565
+ return t / s
566
+
567
+ def __rpow__(s, t):
568
+ t = s.mpc_convert_lhs(t)
569
+ if t is NotImplemented:
570
+ return t
571
+ return t ** s
572
+
573
+ __truediv__ = __div__
574
+ __rtruediv__ = __rdiv__
575
+
576
+ def ae(s, t, rel_eps=None, abs_eps=None):
577
+ return s.context.almosteq(s, t, rel_eps, abs_eps)
578
+
579
+
580
+ complex_types = (complex, _mpc)
581
+
582
+
583
+ class PythonMPContext(object):
584
+
585
+ def __init__(ctx):
586
+ ctx._prec_rounding = [53, round_nearest]
587
+ ctx.mpf = type('mpf', (_mpf,), {})
588
+ ctx.mpc = type('mpc', (_mpc,), {})
589
+ ctx.mpf._ctxdata = [ctx.mpf, new, ctx._prec_rounding]
590
+ ctx.mpc._ctxdata = [ctx.mpc, new, ctx._prec_rounding]
591
+ ctx.mpf.context = ctx
592
+ ctx.mpc.context = ctx
593
+ ctx.constant = type('constant', (_constant,), {})
594
+ ctx.constant._ctxdata = [ctx.mpf, new, ctx._prec_rounding]
595
+ ctx.constant.context = ctx
596
+
597
+ def make_mpf(ctx, v):
598
+ a = new(ctx.mpf)
599
+ a._mpf_ = v
600
+ return a
601
+
602
+ def make_mpc(ctx, v):
603
+ a = new(ctx.mpc)
604
+ a._mpc_ = v
605
+ return a
606
+
607
+ def default(ctx):
608
+ ctx._prec = ctx._prec_rounding[0] = 53
609
+ ctx._dps = 15
610
+ ctx.trap_complex = False
611
+
612
+ def _set_prec(ctx, n):
613
+ ctx._prec = ctx._prec_rounding[0] = max(1, int(n))
614
+ ctx._dps = prec_to_dps(n)
615
+
616
+ def _set_dps(ctx, n):
617
+ ctx._prec = ctx._prec_rounding[0] = dps_to_prec(n)
618
+ ctx._dps = max(1, int(n))
619
+
620
+ prec = property(lambda ctx: ctx._prec, _set_prec)
621
+ dps = property(lambda ctx: ctx._dps, _set_dps)
622
+
623
+ def convert(ctx, x, strings=True):
624
+ """
625
+ Converts *x* to an ``mpf`` or ``mpc``. If *x* is of type ``mpf``,
626
+ ``mpc``, ``int``, ``float``, ``complex``, the conversion
627
+ will be performed losslessly.
628
+
629
+ If *x* is a string, the result will be rounded to the present
630
+ working precision. Strings representing fractions or complex
631
+ numbers are permitted.
632
+
633
+ >>> from mpmath import *
634
+ >>> mp.dps = 15; mp.pretty = False
635
+ >>> mpmathify(3.5)
636
+ mpf('3.5')
637
+ >>> mpmathify('2.1')
638
+ mpf('2.1000000000000001')
639
+ >>> mpmathify('3/4')
640
+ mpf('0.75')
641
+ >>> mpmathify('2+3j')
642
+ mpc(real='2.0', imag='3.0')
643
+
644
+ """
645
+ if type(x) in ctx.types: return x
646
+ if isinstance(x, int_types): return ctx.make_mpf(from_int(x))
647
+ if isinstance(x, float): return ctx.make_mpf(from_float(x))
648
+ if isinstance(x, complex):
649
+ return ctx.make_mpc((from_float(x.real), from_float(x.imag)))
650
+ if type(x).__module__ == 'numpy': return ctx.npconvert(x)
651
+ if isinstance(x, numbers.Rational): # e.g. Fraction
652
+ try: x = rational.mpq(int(x.numerator), int(x.denominator))
653
+ except: pass
654
+ prec, rounding = ctx._prec_rounding
655
+ if isinstance(x, rational.mpq):
656
+ p, q = x._mpq_
657
+ return ctx.make_mpf(from_rational(p, q, prec))
658
+ if strings and isinstance(x, basestring):
659
+ try:
660
+ _mpf_ = from_str(x, prec, rounding)
661
+ return ctx.make_mpf(_mpf_)
662
+ except ValueError:
663
+ pass
664
+ if hasattr(x, '_mpf_'): return ctx.make_mpf(x._mpf_)
665
+ if hasattr(x, '_mpc_'): return ctx.make_mpc(x._mpc_)
666
+ if hasattr(x, '_mpmath_'):
667
+ return ctx.convert(x._mpmath_(prec, rounding))
668
+ if type(x).__module__ == 'decimal':
669
+ try: return ctx.make_mpf(from_Decimal(x, prec, rounding))
670
+ except: pass
671
+ return ctx._convert_fallback(x, strings)
672
+
673
+ def npconvert(ctx, x):
674
+ """
675
+ Converts *x* to an ``mpf`` or ``mpc``. *x* should be a numpy
676
+ scalar.
677
+ """
678
+ import numpy as np
679
+ if isinstance(x, np.integer): return ctx.make_mpf(from_int(int(x)))
680
+ if isinstance(x, np.floating): return ctx.make_mpf(from_npfloat(x))
681
+ if isinstance(x, np.complexfloating):
682
+ return ctx.make_mpc((from_npfloat(x.real), from_npfloat(x.imag)))
683
+ raise TypeError("cannot create mpf from " + repr(x))
684
+
685
+ def isnan(ctx, x):
686
+ """
687
+ Return *True* if *x* is a NaN (not-a-number), or for a complex
688
+ number, whether either the real or complex part is NaN;
689
+ otherwise return *False*::
690
+
691
+ >>> from mpmath import *
692
+ >>> isnan(3.14)
693
+ False
694
+ >>> isnan(nan)
695
+ True
696
+ >>> isnan(mpc(3.14,2.72))
697
+ False
698
+ >>> isnan(mpc(3.14,nan))
699
+ True
700
+
701
+ """
702
+ if hasattr(x, "_mpf_"):
703
+ return x._mpf_ == fnan
704
+ if hasattr(x, "_mpc_"):
705
+ return fnan in x._mpc_
706
+ if isinstance(x, int_types) or isinstance(x, rational.mpq):
707
+ return False
708
+ x = ctx.convert(x)
709
+ if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'):
710
+ return ctx.isnan(x)
711
+ raise TypeError("isnan() needs a number as input")
712
+
713
+ def isinf(ctx, x):
714
+ """
715
+ Return *True* if the absolute value of *x* is infinite;
716
+ otherwise return *False*::
717
+
718
+ >>> from mpmath import *
719
+ >>> isinf(inf)
720
+ True
721
+ >>> isinf(-inf)
722
+ True
723
+ >>> isinf(3)
724
+ False
725
+ >>> isinf(3+4j)
726
+ False
727
+ >>> isinf(mpc(3,inf))
728
+ True
729
+ >>> isinf(mpc(inf,3))
730
+ True
731
+
732
+ """
733
+ if hasattr(x, "_mpf_"):
734
+ return x._mpf_ in (finf, fninf)
735
+ if hasattr(x, "_mpc_"):
736
+ re, im = x._mpc_
737
+ return re in (finf, fninf) or im in (finf, fninf)
738
+ if isinstance(x, int_types) or isinstance(x, rational.mpq):
739
+ return False
740
+ x = ctx.convert(x)
741
+ if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'):
742
+ return ctx.isinf(x)
743
+ raise TypeError("isinf() needs a number as input")
744
+
745
+ def isnormal(ctx, x):
746
+ """
747
+ Determine whether *x* is "normal" in the sense of floating-point
748
+ representation; that is, return *False* if *x* is zero, an
749
+ infinity or NaN; otherwise return *True*. By extension, a
750
+ complex number *x* is considered "normal" if its magnitude is
751
+ normal::
752
+
753
+ >>> from mpmath import *
754
+ >>> isnormal(3)
755
+ True
756
+ >>> isnormal(0)
757
+ False
758
+ >>> isnormal(inf); isnormal(-inf); isnormal(nan)
759
+ False
760
+ False
761
+ False
762
+ >>> isnormal(0+0j)
763
+ False
764
+ >>> isnormal(0+3j)
765
+ True
766
+ >>> isnormal(mpc(2,nan))
767
+ False
768
+ """
769
+ if hasattr(x, "_mpf_"):
770
+ return bool(x._mpf_[1])
771
+ if hasattr(x, "_mpc_"):
772
+ re, im = x._mpc_
773
+ re_normal = bool(re[1])
774
+ im_normal = bool(im[1])
775
+ if re == fzero: return im_normal
776
+ if im == fzero: return re_normal
777
+ return re_normal and im_normal
778
+ if isinstance(x, int_types) or isinstance(x, rational.mpq):
779
+ return bool(x)
780
+ x = ctx.convert(x)
781
+ if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'):
782
+ return ctx.isnormal(x)
783
+ raise TypeError("isnormal() needs a number as input")
784
+
785
+ def isint(ctx, x, gaussian=False):
786
+ """
787
+ Return *True* if *x* is integer-valued; otherwise return
788
+ *False*::
789
+
790
+ >>> from mpmath import *
791
+ >>> isint(3)
792
+ True
793
+ >>> isint(mpf(3))
794
+ True
795
+ >>> isint(3.2)
796
+ False
797
+ >>> isint(inf)
798
+ False
799
+
800
+ Optionally, Gaussian integers can be checked for::
801
+
802
+ >>> isint(3+0j)
803
+ True
804
+ >>> isint(3+2j)
805
+ False
806
+ >>> isint(3+2j, gaussian=True)
807
+ True
808
+
809
+ """
810
+ if isinstance(x, int_types):
811
+ return True
812
+ if hasattr(x, "_mpf_"):
813
+ sign, man, exp, bc = xval = x._mpf_
814
+ return bool((man and exp >= 0) or xval == fzero)
815
+ if hasattr(x, "_mpc_"):
816
+ re, im = x._mpc_
817
+ rsign, rman, rexp, rbc = re
818
+ isign, iman, iexp, ibc = im
819
+ re_isint = (rman and rexp >= 0) or re == fzero
820
+ if gaussian:
821
+ im_isint = (iman and iexp >= 0) or im == fzero
822
+ return re_isint and im_isint
823
+ return re_isint and im == fzero
824
+ if isinstance(x, rational.mpq):
825
+ p, q = x._mpq_
826
+ return p % q == 0
827
+ x = ctx.convert(x)
828
+ if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'):
829
+ return ctx.isint(x, gaussian)
830
+ raise TypeError("isint() needs a number as input")
831
+
832
+ def fsum(ctx, terms, absolute=False, squared=False):
833
+ """
834
+ Calculates a sum containing a finite number of terms (for infinite
835
+ series, see :func:`~mpmath.nsum`). The terms will be converted to
836
+ mpmath numbers. For len(terms) > 2, this function is generally
837
+ faster and produces more accurate results than the builtin
838
+ Python function :func:`sum`.
839
+
840
+ >>> from mpmath import *
841
+ >>> mp.dps = 15; mp.pretty = False
842
+ >>> fsum([1, 2, 0.5, 7])
843
+ mpf('10.5')
844
+
845
+ With squared=True each term is squared, and with absolute=True
846
+ the absolute value of each term is used.
847
+ """
848
+ prec, rnd = ctx._prec_rounding
849
+ real = []
850
+ imag = []
851
+ for term in terms:
852
+ reval = imval = 0
853
+ if hasattr(term, "_mpf_"):
854
+ reval = term._mpf_
855
+ elif hasattr(term, "_mpc_"):
856
+ reval, imval = term._mpc_
857
+ else:
858
+ term = ctx.convert(term)
859
+ if hasattr(term, "_mpf_"):
860
+ reval = term._mpf_
861
+ elif hasattr(term, "_mpc_"):
862
+ reval, imval = term._mpc_
863
+ else:
864
+ raise NotImplementedError
865
+ if imval:
866
+ if squared:
867
+ if absolute:
868
+ real.append(mpf_mul(reval,reval))
869
+ real.append(mpf_mul(imval,imval))
870
+ else:
871
+ reval, imval = mpc_pow_int((reval,imval),2,prec+10)
872
+ real.append(reval)
873
+ imag.append(imval)
874
+ elif absolute:
875
+ real.append(mpc_abs((reval,imval), prec))
876
+ else:
877
+ real.append(reval)
878
+ imag.append(imval)
879
+ else:
880
+ if squared:
881
+ reval = mpf_mul(reval, reval)
882
+ elif absolute:
883
+ reval = mpf_abs(reval)
884
+ real.append(reval)
885
+ s = mpf_sum(real, prec, rnd, absolute)
886
+ if imag:
887
+ s = ctx.make_mpc((s, mpf_sum(imag, prec, rnd)))
888
+ else:
889
+ s = ctx.make_mpf(s)
890
+ return s
891
+
892
+ def fdot(ctx, A, B=None, conjugate=False):
893
+ r"""
894
+ Computes the dot product of the iterables `A` and `B`,
895
+
896
+ .. math ::
897
+
898
+ \sum_{k=0} A_k B_k.
899
+
900
+ Alternatively, :func:`~mpmath.fdot` accepts a single iterable of pairs.
901
+ In other words, ``fdot(A,B)`` and ``fdot(zip(A,B))`` are equivalent.
902
+ The elements are automatically converted to mpmath numbers.
903
+
904
+ With ``conjugate=True``, the elements in the second vector
905
+ will be conjugated:
906
+
907
+ .. math ::
908
+
909
+ \sum_{k=0} A_k \overline{B_k}
910
+
911
+ **Examples**
912
+
913
+ >>> from mpmath import *
914
+ >>> mp.dps = 15; mp.pretty = False
915
+ >>> A = [2, 1.5, 3]
916
+ >>> B = [1, -1, 2]
917
+ >>> fdot(A, B)
918
+ mpf('6.5')
919
+ >>> list(zip(A, B))
920
+ [(2, 1), (1.5, -1), (3, 2)]
921
+ >>> fdot(_)
922
+ mpf('6.5')
923
+ >>> A = [2, 1.5, 3j]
924
+ >>> B = [1+j, 3, -1-j]
925
+ >>> fdot(A, B)
926
+ mpc(real='9.5', imag='-1.0')
927
+ >>> fdot(A, B, conjugate=True)
928
+ mpc(real='3.5', imag='-5.0')
929
+
930
+ """
931
+ if B is not None:
932
+ A = zip(A, B)
933
+ prec, rnd = ctx._prec_rounding
934
+ real = []
935
+ imag = []
936
+ hasattr_ = hasattr
937
+ types = (ctx.mpf, ctx.mpc)
938
+ for a, b in A:
939
+ if type(a) not in types: a = ctx.convert(a)
940
+ if type(b) not in types: b = ctx.convert(b)
941
+ a_real = hasattr_(a, "_mpf_")
942
+ b_real = hasattr_(b, "_mpf_")
943
+ if a_real and b_real:
944
+ real.append(mpf_mul(a._mpf_, b._mpf_))
945
+ continue
946
+ a_complex = hasattr_(a, "_mpc_")
947
+ b_complex = hasattr_(b, "_mpc_")
948
+ if a_real and b_complex:
949
+ aval = a._mpf_
950
+ bre, bim = b._mpc_
951
+ if conjugate:
952
+ bim = mpf_neg(bim)
953
+ real.append(mpf_mul(aval, bre))
954
+ imag.append(mpf_mul(aval, bim))
955
+ elif b_real and a_complex:
956
+ are, aim = a._mpc_
957
+ bval = b._mpf_
958
+ real.append(mpf_mul(are, bval))
959
+ imag.append(mpf_mul(aim, bval))
960
+ elif a_complex and b_complex:
961
+ #re, im = mpc_mul(a._mpc_, b._mpc_, prec+20)
962
+ are, aim = a._mpc_
963
+ bre, bim = b._mpc_
964
+ if conjugate:
965
+ bim = mpf_neg(bim)
966
+ real.append(mpf_mul(are, bre))
967
+ real.append(mpf_neg(mpf_mul(aim, bim)))
968
+ imag.append(mpf_mul(are, bim))
969
+ imag.append(mpf_mul(aim, bre))
970
+ else:
971
+ raise NotImplementedError
972
+ s = mpf_sum(real, prec, rnd)
973
+ if imag:
974
+ s = ctx.make_mpc((s, mpf_sum(imag, prec, rnd)))
975
+ else:
976
+ s = ctx.make_mpf(s)
977
+ return s
978
+
979
+ def _wrap_libmp_function(ctx, mpf_f, mpc_f=None, mpi_f=None, doc="<no doc>"):
980
+ """
981
+ Given a low-level mpf_ function, and optionally similar functions
982
+ for mpc_ and mpi_, defines the function as a context method.
983
+
984
+ It is assumed that the return type is the same as that of
985
+ the input; the exception is that propagation from mpf to mpc is possible
986
+ by raising ComplexResult.
987
+
988
+ """
989
+ def f(x, **kwargs):
990
+ if type(x) not in ctx.types:
991
+ x = ctx.convert(x)
992
+ prec, rounding = ctx._prec_rounding
993
+ if kwargs:
994
+ prec = kwargs.get('prec', prec)
995
+ if 'dps' in kwargs:
996
+ prec = dps_to_prec(kwargs['dps'])
997
+ rounding = kwargs.get('rounding', rounding)
998
+ if hasattr(x, '_mpf_'):
999
+ try:
1000
+ return ctx.make_mpf(mpf_f(x._mpf_, prec, rounding))
1001
+ except ComplexResult:
1002
+ # Handle propagation to complex
1003
+ if ctx.trap_complex:
1004
+ raise
1005
+ return ctx.make_mpc(mpc_f((x._mpf_, fzero), prec, rounding))
1006
+ elif hasattr(x, '_mpc_'):
1007
+ return ctx.make_mpc(mpc_f(x._mpc_, prec, rounding))
1008
+ raise NotImplementedError("%s of a %s" % (name, type(x)))
1009
+ name = mpf_f.__name__[4:]
1010
+ f.__doc__ = function_docs.__dict__.get(name, "Computes the %s of x" % doc)
1011
+ return f
1012
+
1013
+ # Called by SpecialFunctions.__init__()
1014
+ @classmethod
1015
+ def _wrap_specfun(cls, name, f, wrap):
1016
+ if wrap:
1017
+ def f_wrapped(ctx, *args, **kwargs):
1018
+ convert = ctx.convert
1019
+ args = [convert(a) for a in args]
1020
+ prec = ctx.prec
1021
+ try:
1022
+ ctx.prec += 10
1023
+ retval = f(ctx, *args, **kwargs)
1024
+ finally:
1025
+ ctx.prec = prec
1026
+ return +retval
1027
+ else:
1028
+ f_wrapped = f
1029
+ f_wrapped.__doc__ = function_docs.__dict__.get(name, f.__doc__)
1030
+ setattr(cls, name, f_wrapped)
1031
+
1032
+ def _convert_param(ctx, x):
1033
+ if hasattr(x, "_mpc_"):
1034
+ v, im = x._mpc_
1035
+ if im != fzero:
1036
+ return x, 'C'
1037
+ elif hasattr(x, "_mpf_"):
1038
+ v = x._mpf_
1039
+ else:
1040
+ if type(x) in int_types:
1041
+ return int(x), 'Z'
1042
+ p = None
1043
+ if isinstance(x, tuple):
1044
+ p, q = x
1045
+ elif hasattr(x, '_mpq_'):
1046
+ p, q = x._mpq_
1047
+ elif isinstance(x, basestring) and '/' in x:
1048
+ p, q = x.split('/')
1049
+ p = int(p)
1050
+ q = int(q)
1051
+ if p is not None:
1052
+ if not p % q:
1053
+ return p // q, 'Z'
1054
+ return ctx.mpq(p,q), 'Q'
1055
+ x = ctx.convert(x)
1056
+ if hasattr(x, "_mpc_"):
1057
+ v, im = x._mpc_
1058
+ if im != fzero:
1059
+ return x, 'C'
1060
+ elif hasattr(x, "_mpf_"):
1061
+ v = x._mpf_
1062
+ else:
1063
+ return x, 'U'
1064
+ sign, man, exp, bc = v
1065
+ if man:
1066
+ if exp >= -4:
1067
+ if sign:
1068
+ man = -man
1069
+ if exp >= 0:
1070
+ return int(man) << exp, 'Z'
1071
+ if exp >= -4:
1072
+ p, q = int(man), (1<<(-exp))
1073
+ return ctx.mpq(p,q), 'Q'
1074
+ x = ctx.make_mpf(v)
1075
+ return x, 'R'
1076
+ elif not exp:
1077
+ return 0, 'Z'
1078
+ else:
1079
+ return x, 'U'
1080
+
1081
+ def _mpf_mag(ctx, x):
1082
+ sign, man, exp, bc = x
1083
+ if man:
1084
+ return exp+bc
1085
+ if x == fzero:
1086
+ return ctx.ninf
1087
+ if x == finf or x == fninf:
1088
+ return ctx.inf
1089
+ return ctx.nan
1090
+
1091
+ def mag(ctx, x):
1092
+ """
1093
+ Quick logarithmic magnitude estimate of a number. Returns an
1094
+ integer or infinity `m` such that `|x| <= 2^m`. It is not
1095
+ guaranteed that `m` is an optimal bound, but it will never
1096
+ be too large by more than 2 (and probably not more than 1).
1097
+
1098
+ **Examples**
1099
+
1100
+ >>> from mpmath import *
1101
+ >>> mp.pretty = True
1102
+ >>> mag(10), mag(10.0), mag(mpf(10)), int(ceil(log(10,2)))
1103
+ (4, 4, 4, 4)
1104
+ >>> mag(10j), mag(10+10j)
1105
+ (4, 5)
1106
+ >>> mag(0.01), int(ceil(log(0.01,2)))
1107
+ (-6, -6)
1108
+ >>> mag(0), mag(inf), mag(-inf), mag(nan)
1109
+ (-inf, +inf, +inf, nan)
1110
+
1111
+ """
1112
+ if hasattr(x, "_mpf_"):
1113
+ return ctx._mpf_mag(x._mpf_)
1114
+ elif hasattr(x, "_mpc_"):
1115
+ r, i = x._mpc_
1116
+ if r == fzero:
1117
+ return ctx._mpf_mag(i)
1118
+ if i == fzero:
1119
+ return ctx._mpf_mag(r)
1120
+ return 1+max(ctx._mpf_mag(r), ctx._mpf_mag(i))
1121
+ elif isinstance(x, int_types):
1122
+ if x:
1123
+ return bitcount(abs(x))
1124
+ return ctx.ninf
1125
+ elif isinstance(x, rational.mpq):
1126
+ p, q = x._mpq_
1127
+ if p:
1128
+ return 1 + bitcount(abs(p)) - bitcount(q)
1129
+ return ctx.ninf
1130
+ else:
1131
+ x = ctx.convert(x)
1132
+ if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
1133
+ return ctx.mag(x)
1134
+ else:
1135
+ raise TypeError("requires an mpf/mpc")
1136
+
1137
+
1138
+ # Register with "numbers" ABC
1139
+ # We do not subclass, hence we do not use the @abstractmethod checks. While
1140
+ # this is less invasive it may turn out that we do not actually support
1141
+ # parts of the expected interfaces. See
1142
+ # http://docs.python.org/2/library/numbers.html for list of abstract
1143
+ # methods.
1144
+ try:
1145
+ import numbers
1146
+ numbers.Complex.register(_mpc)
1147
+ numbers.Real.register(_mpf)
1148
+ except ImportError:
1149
+ pass