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,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
+