mpmath 0.3__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.3 → mpmath-0.4}/CHANGES +15 -0
- {mpmath-0.3 → mpmath-0.4}/PKG-INFO +1 -1
- {mpmath-0.3 → mpmath-0.4}/README +7 -6
- {mpmath-0.3 → mpmath-0.4}/demo/pidigits.py +10 -16
- {mpmath-0.3 → mpmath-0.4}/mpmath/functions2.py +7 -6
- 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.3 → mpmath-0.4}/mpmath/mpmath.py +70 -44
- {mpmath-0.3 → 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.3 → mpmath-0.4}/tests/test_functions2.py +2 -11
- {mpmath-0.3 → mpmath-0.4}/tests/test_hp.py +8 -11
- {mpmath-0.3 → mpmath-0.4}/tests/test_mpmath.py +21 -150
- mpmath-0.3/mpmath/lib.py +0 -1208
- mpmath-0.3/tests/benchmark.py +0 -71
- {mpmath-0.3 → mpmath-0.4}/LICENSE +0 -0
- {mpmath-0.3 → mpmath-0.4}/mpmath/__init__.py +0 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contents of this module:
|
|
3
|
+
|
|
4
|
+
* Integer and bit-level operations
|
|
5
|
+
* Miscellaneous utilities
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import math
|
|
10
|
+
import decimal
|
|
11
|
+
|
|
12
|
+
# Same as standard Python float
|
|
13
|
+
STANDARD_PREC = 53
|
|
14
|
+
|
|
15
|
+
LOG2_10 = math.log(10,2) # 3.3219...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# All supported rounding modes. We define them as integer constants for easy
|
|
19
|
+
# management, but change __repr__ to give more information on inspection
|
|
20
|
+
|
|
21
|
+
class Rounding(int):
|
|
22
|
+
|
|
23
|
+
def __new__(cls, level, name):
|
|
24
|
+
a = int.__new__(cls, level)
|
|
25
|
+
a.name = name
|
|
26
|
+
return a
|
|
27
|
+
|
|
28
|
+
def __repr__(self):
|
|
29
|
+
return self.name
|
|
30
|
+
|
|
31
|
+
__str__ = __repr__
|
|
32
|
+
|
|
33
|
+
ROUND_DOWN = Rounding(1, 'ROUND_DOWN')
|
|
34
|
+
ROUND_UP = Rounding(2, 'ROUND_UP')
|
|
35
|
+
ROUND_FLOOR = Rounding(3, 'ROUND_FLOOR')
|
|
36
|
+
ROUND_CEILING = Rounding(4, 'ROUND_CEILING')
|
|
37
|
+
ROUND_HALF_UP = Rounding(5, 'ROUND_HALF_UP')
|
|
38
|
+
ROUND_HALF_DOWN = Rounding(6, 'ROUND_HALF_DOWN')
|
|
39
|
+
ROUND_HALF_EVEN = Rounding(7, 'ROUND_HALF_EVEN')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def giant_steps(start, target):
|
|
43
|
+
"""Generate a list of precisions ranging from 'start' to 'target'
|
|
44
|
+
that doubles with each step. This is used by quadratically
|
|
45
|
+
convergent iterations (that is, Newton iterations), where we want
|
|
46
|
+
to keep the precision at the same level as the accuracy in each
|
|
47
|
+
step to minimize work.
|
|
48
|
+
|
|
49
|
+
For example, to find a sequence of precisions to reach 1000 bits
|
|
50
|
+
starting from a 53-bit estimate, giant_steps(53, 1000) gives
|
|
51
|
+
|
|
52
|
+
[64, 126, 251, 501, 1000]
|
|
53
|
+
|
|
54
|
+
So, if we start Newton's method with a 53-bit accurate initial
|
|
55
|
+
guess, the first iteration should be carried out at 64-bit
|
|
56
|
+
precision, the second at 126-bit precision, and so on.
|
|
57
|
+
|
|
58
|
+
Note the conservative rounding (1000 to 501, etc); this is used
|
|
59
|
+
guard against unit errors in the last place."""
|
|
60
|
+
L = [target]
|
|
61
|
+
while L[-1] > start*2:
|
|
62
|
+
L = L + [L[-1]//2 + 1]
|
|
63
|
+
return L[::-1]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def rshift_quick(x, n):
|
|
67
|
+
"""For an integer x, calculate x >> n with the fastest (floor)
|
|
68
|
+
rounding. Unlike the plain Python expression (x >> n), n is
|
|
69
|
+
allowed to be negative, in which case a left shift is performed."""
|
|
70
|
+
if n >= 0: return x >> n
|
|
71
|
+
else: return x << (-n)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def lshift_quick(x, n):
|
|
75
|
+
"""For an integer x, calculate x << n. Unlike the plain Python
|
|
76
|
+
expression (x << n), n is allowed to be negative, in which case a
|
|
77
|
+
right shift with default (floor) rounding is performed."""
|
|
78
|
+
if n >= 0: return x << n
|
|
79
|
+
else: return x >> (-n)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def make_fixed(s, prec):
|
|
83
|
+
"""Convert a floating-point number to a fixed-point big integer"""
|
|
84
|
+
man, exp, bc = s
|
|
85
|
+
offset = exp + prec
|
|
86
|
+
if offset >= 0:
|
|
87
|
+
return man << offset
|
|
88
|
+
else:
|
|
89
|
+
return man >> (-offset)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def bitcount(n, log=math.log, table=(0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4)):
|
|
93
|
+
"""Give size of n in bits; i.e. the position of the highest set bit
|
|
94
|
+
in n. If n is negative, the absolute value is used. The bitcount of
|
|
95
|
+
zero is taken to be 0."""
|
|
96
|
+
|
|
97
|
+
if not n: return 0
|
|
98
|
+
if n < 0: n = -n
|
|
99
|
+
|
|
100
|
+
# math.log gives a good estimate, and never overflows, but
|
|
101
|
+
# is not always exact. Subtract 2 to underestimate, then
|
|
102
|
+
# count remaining bits by table lookup
|
|
103
|
+
bc = int(log(n, 2)) - 2
|
|
104
|
+
if bc < 0:
|
|
105
|
+
bc = 0
|
|
106
|
+
return bc + table[n >> bc]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# from decimal.py -- faster for small precs
|
|
110
|
+
def bitcount2(n, correction = {
|
|
111
|
+
'0': 4, '1': 3, '2': 2, '3': 2,
|
|
112
|
+
'4': 1, '5': 1, '6': 1, '7': 1,
|
|
113
|
+
'8': 0, '9': 0, 'a': 0, 'b': 0,
|
|
114
|
+
'c': 0, 'd': 0, 'e': 0, 'f': 0}):
|
|
115
|
+
if n < 0:
|
|
116
|
+
n = -n
|
|
117
|
+
hex_n = "%x" % n
|
|
118
|
+
return 4*len(hex_n) - correction[hex_n[0]]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def trailing_zeros(n):
|
|
122
|
+
"""Count trailing zero bits in an integer. If n is negative, it is
|
|
123
|
+
replaced by its absolute value."""
|
|
124
|
+
if n & 1: return 0
|
|
125
|
+
if not n: return 0
|
|
126
|
+
if n < 0: n = -n
|
|
127
|
+
t = 0
|
|
128
|
+
while not n & 0xffffffffffffffff: n >>= 64; t += 64
|
|
129
|
+
while not n & 0xff: n >>= 8; t += 8
|
|
130
|
+
while not n & 1: n >>= 1; t += 1
|
|
131
|
+
return t
|
|
132
|
+
|
|
133
|
+
#----------------------------------------------------------------------------
|
|
134
|
+
# Integer shifting with directed rounding
|
|
135
|
+
#
|
|
136
|
+
|
|
137
|
+
def round_floor(x, n):
|
|
138
|
+
if not n or not x: return x
|
|
139
|
+
if n < 0: return x << -n
|
|
140
|
+
return x >> n
|
|
141
|
+
|
|
142
|
+
def round_ceiling(x, n):
|
|
143
|
+
if not n or not x: return x
|
|
144
|
+
if n < 0: return x << -n
|
|
145
|
+
return -((-x) >> n)
|
|
146
|
+
|
|
147
|
+
def round_down(x, n):
|
|
148
|
+
if not n or not x: return x
|
|
149
|
+
if n < 0: return x << -n
|
|
150
|
+
if x > 0:
|
|
151
|
+
return x >> n
|
|
152
|
+
else:
|
|
153
|
+
return -((-x) >> n)
|
|
154
|
+
|
|
155
|
+
def round_up(x, n):
|
|
156
|
+
if not n or not x: return x
|
|
157
|
+
if n < 0: return x << -n
|
|
158
|
+
if x > 0:
|
|
159
|
+
return -((-x) >> n)
|
|
160
|
+
else:
|
|
161
|
+
return x >> n
|
|
162
|
+
|
|
163
|
+
def round_half_up(x, n):
|
|
164
|
+
if not n or not x: return x
|
|
165
|
+
if n < 0: return x << -n
|
|
166
|
+
positive = x > 0
|
|
167
|
+
if positive: t = x >> (n-1)
|
|
168
|
+
else: t = (-x) >> (n-1)
|
|
169
|
+
if t & 1:
|
|
170
|
+
if positive: return (t>>1)+1
|
|
171
|
+
else: return -((t>>1)+1)
|
|
172
|
+
if positive: return t>>1
|
|
173
|
+
else: return -(t>>1)
|
|
174
|
+
|
|
175
|
+
def round_half_down(x, n):
|
|
176
|
+
if not n or not x: return x
|
|
177
|
+
if n < 0: return x << -n
|
|
178
|
+
positive = x > 0
|
|
179
|
+
if positive: t = x >> (n-1)
|
|
180
|
+
else: t = (-x) >> (n-1)
|
|
181
|
+
if t & 1 and x & ((1<<(n-1))-1):
|
|
182
|
+
if positive: return (t>>1)+1
|
|
183
|
+
else: return -((t>>1)+1)
|
|
184
|
+
if positive: return t>>1
|
|
185
|
+
else: return -(t>>1)
|
|
186
|
+
|
|
187
|
+
def round_half_even(x, n):
|
|
188
|
+
if not n or not x: return x
|
|
189
|
+
if n < 0: return x << -n
|
|
190
|
+
positive = x > 0
|
|
191
|
+
if positive: t = x >> (n-1)
|
|
192
|
+
else: t = (-x) >> (n-1)
|
|
193
|
+
if t & 1 and (t&2 or x & ((1<<(n-1))-1)):
|
|
194
|
+
if positive: return (t>>1)+1
|
|
195
|
+
else: return -((t>>1)+1)
|
|
196
|
+
if positive: return t>>1
|
|
197
|
+
else: return -(t>>1)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
rounding_functions = {
|
|
201
|
+
ROUND_FLOOR : round_floor,
|
|
202
|
+
ROUND_CEILING : round_ceiling,
|
|
203
|
+
ROUND_DOWN : round_down,
|
|
204
|
+
ROUND_UP : round_up,
|
|
205
|
+
ROUND_HALF_UP : round_half_up,
|
|
206
|
+
ROUND_HALF_DOWN : round_half_down,
|
|
207
|
+
ROUND_HALF_EVEN : round_half_even
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def rshift(x, n, rounding):
|
|
212
|
+
"""Shift x (a plain Python integer) n bits to the right (i.e.,
|
|
213
|
+
calculate x/(2**n)), and round to the nearest integer in accordance
|
|
214
|
+
with the specified rounding mode. The exponent n may be negative,
|
|
215
|
+
in which case x is shifted to the left (and no rounding is
|
|
216
|
+
necessary)."""
|
|
217
|
+
return rounding_functions[rounding](x, n)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# TODO: speed up for bases 2, 4, 8, 16, ...
|
|
222
|
+
|
|
223
|
+
def bin_to_radix(x, xbits, base, bdigits):
|
|
224
|
+
"""
|
|
225
|
+
Radix conversion for fixed-point numbers. That is, convert
|
|
226
|
+
x * 2**xbits to floor(x * 10**bdigits).
|
|
227
|
+
"""
|
|
228
|
+
return x * (base**bdigits) >> xbits
|
|
229
|
+
|
|
230
|
+
stddigits = '0123456789abcdefghijklmnopqrstuvwxyz'
|
|
231
|
+
|
|
232
|
+
def small_numeral(n, base=10, digits=stddigits):
|
|
233
|
+
"""
|
|
234
|
+
Return the string numeral of a positive integer in an arbitrary
|
|
235
|
+
base. Most efficient for small input.
|
|
236
|
+
"""
|
|
237
|
+
if base == 10:
|
|
238
|
+
return str(n)
|
|
239
|
+
digs = []
|
|
240
|
+
while n:
|
|
241
|
+
n, digit = divmod(n, base)
|
|
242
|
+
digs.append(digits[digit])
|
|
243
|
+
return "".join(digs[::-1])
|
|
244
|
+
|
|
245
|
+
def numeral(n, base=10, size=0, digits=stddigits):
|
|
246
|
+
"""
|
|
247
|
+
Represent the integer n as a string of digits in the given base.
|
|
248
|
+
Recursive division is used to make this function about 3x faster
|
|
249
|
+
than Python's str() for converting integers to decimal strings.
|
|
250
|
+
|
|
251
|
+
The 'size' parameters specifies the number of digits in n; this
|
|
252
|
+
number is only used to determine splitting points and need not
|
|
253
|
+
be exact.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
if n < 0:
|
|
257
|
+
return "-" + numeral(-n, base, size, digits)
|
|
258
|
+
|
|
259
|
+
# Fast enough to do directly
|
|
260
|
+
if size < 250:
|
|
261
|
+
return small_numeral(n, base, digits)
|
|
262
|
+
|
|
263
|
+
# Divide in half
|
|
264
|
+
half = (size // 2) + (size & 1)
|
|
265
|
+
A, B = divmod(n, base**half)
|
|
266
|
+
ad = numeral(A, base, half, digits)
|
|
267
|
+
bd = numeral(B, base, half, digits).rjust(half, "0")
|
|
268
|
+
return ad + bd
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
from lib import *
|
|
2
2
|
from decimal import Decimal
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
class mpnumeric(object):
|
|
5
6
|
"""Base class for mpf and mpc. Calling mpnumeric(x) returns an mpf
|
|
6
7
|
if x can be converted to an mpf (if it is a float, int, mpf, ...),
|
|
7
8
|
and an mpc if x is complex."""
|
|
9
|
+
|
|
8
10
|
def __new__(cls, val):
|
|
11
|
+
# TODO: should maybe normalize here
|
|
9
12
|
if isinstance(val, cls):
|
|
10
13
|
return val
|
|
11
14
|
if isinstance(val, complex):
|
|
12
15
|
return mpc(val)
|
|
13
16
|
return mpf(val)
|
|
14
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
|
+
|
|
15
42
|
class context(type):
|
|
16
43
|
"""Metaclass for mpf and mpc. Holds global working precision."""
|
|
17
44
|
|
|
@@ -44,14 +71,15 @@ class context(type):
|
|
|
44
71
|
|
|
45
72
|
int_types = (int, long)
|
|
46
73
|
|
|
74
|
+
|
|
47
75
|
def _convert(x):
|
|
48
76
|
"""Convet x to mpf data"""
|
|
49
77
|
if isinstance(x, float):
|
|
50
|
-
return
|
|
78
|
+
return from_float(x, mpf._prec, mpf._rounding)
|
|
51
79
|
if isinstance(x, int_types):
|
|
52
|
-
return
|
|
80
|
+
return from_int(x, mpf._prec, mpf._rounding)
|
|
53
81
|
if isinstance(x, (Decimal, str)):
|
|
54
|
-
return
|
|
82
|
+
return from_str(x, mpf._prec, mpf._rounding)
|
|
55
83
|
raise TypeError("cannot create mpf from " + repr(x))
|
|
56
84
|
|
|
57
85
|
|
|
@@ -93,7 +121,7 @@ class mpf(mpnumeric):
|
|
|
93
121
|
"""A new mpf can be created from a Python float, an int, a
|
|
94
122
|
Decimal, or a decimal string representing a number in
|
|
95
123
|
floating-point format. Examples:
|
|
96
|
-
|
|
124
|
+
|
|
97
125
|
mpf(25)
|
|
98
126
|
mpf(2.5)
|
|
99
127
|
mpf('2.5')
|
|
@@ -120,10 +148,10 @@ class mpf(mpnumeric):
|
|
|
120
148
|
|
|
121
149
|
def __repr__(s):
|
|
122
150
|
st = "mpf('%s')"
|
|
123
|
-
return st %
|
|
151
|
+
return st % to_str(s.val, mpf._dps+2)
|
|
124
152
|
|
|
125
153
|
def __str__(s):
|
|
126
|
-
return
|
|
154
|
+
return to_str(s.val, mpf._dps)
|
|
127
155
|
|
|
128
156
|
def __hash__(s):
|
|
129
157
|
try:
|
|
@@ -136,14 +164,17 @@ class mpf(mpnumeric):
|
|
|
136
164
|
return hash(self.val)
|
|
137
165
|
|
|
138
166
|
def __int__(s):
|
|
139
|
-
return
|
|
167
|
+
return to_int(s.val)
|
|
140
168
|
|
|
141
169
|
def __float__(s):
|
|
142
|
-
return
|
|
170
|
+
return to_float(s.val)
|
|
143
171
|
|
|
144
172
|
def __complex__(s):
|
|
145
173
|
return float(s) + 0j
|
|
146
174
|
|
|
175
|
+
def __nonzero__(s):
|
|
176
|
+
return bool(s.man)
|
|
177
|
+
|
|
147
178
|
def __eq__(s, t):
|
|
148
179
|
if not isinstance(t, mpf):
|
|
149
180
|
if isinstance(t, complex_types):
|
|
@@ -256,7 +287,7 @@ class mpf(mpnumeric):
|
|
|
256
287
|
return power(s, t)
|
|
257
288
|
|
|
258
289
|
def __rpow__(s, t):
|
|
259
|
-
return
|
|
290
|
+
return convert_lossless(t) ** s
|
|
260
291
|
|
|
261
292
|
def sqrt(s):
|
|
262
293
|
return sqrt(s)
|
|
@@ -307,7 +338,6 @@ def make_mpf(tpl, construct=object.__new__, cls=mpf):
|
|
|
307
338
|
return a
|
|
308
339
|
|
|
309
340
|
|
|
310
|
-
|
|
311
341
|
class mpc(mpnumeric):
|
|
312
342
|
"""An mpc represents a complex number using a pair of mpf:s (one
|
|
313
343
|
for the real part and another for the imaginary part.) The mpc
|
|
@@ -380,11 +410,8 @@ class mpc(mpnumeric):
|
|
|
380
410
|
def __mul__(s, t):
|
|
381
411
|
if not isinstance(t, mpc):
|
|
382
412
|
t = mpc(t)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
return mpc(a*c, 0)
|
|
386
|
-
else:
|
|
387
|
-
return mpc(a*c-b*d, a*d+b*c)
|
|
413
|
+
return mpc(*fcmul(s.real.val, s.imag.val, t.real.val, t.imag.val,
|
|
414
|
+
mpf._prec, mpf._rounding))
|
|
388
415
|
|
|
389
416
|
__rmul__ = __mul__
|
|
390
417
|
|
|
@@ -418,7 +445,7 @@ class mpc(mpnumeric):
|
|
|
418
445
|
return power(s, n)
|
|
419
446
|
|
|
420
447
|
def __rpow__(s, t):
|
|
421
|
-
return
|
|
448
|
+
return convert_lossless(t) ** s
|
|
422
449
|
|
|
423
450
|
# TODO: refactor and merge with mpf.ae
|
|
424
451
|
def ae(s, t, rel_eps=None, abs_eps=None):
|
|
@@ -472,7 +499,10 @@ class constant(mpf):
|
|
|
472
499
|
# return "<%s: %s~>" % (self.name, mpf.__str__(self))
|
|
473
500
|
|
|
474
501
|
|
|
502
|
+
_180 = from_int(180, 10, ROUND_FLOOR)
|
|
503
|
+
|
|
475
504
|
pi = constant(fpi, "pi")
|
|
505
|
+
degree = constant(lambda p, r: fdiv(fpi(p+4, ROUND_FLOOR), _180, p, r), "degree")
|
|
476
506
|
e = constant(lambda p, r: fexp(fone, p, r), "e")
|
|
477
507
|
cgamma = constant(fgamma, "Euler's constant gamma")
|
|
478
508
|
clog2 = constant(flog2, "log(2)")
|
|
@@ -483,7 +513,7 @@ def sqrt(x):
|
|
|
483
513
|
"""For real x >= 0, returns the square root of x. For negative or
|
|
484
514
|
complex x, returns the principal branch of the complex square root
|
|
485
515
|
of x."""
|
|
486
|
-
x =
|
|
516
|
+
x = convert_lossless(x)
|
|
487
517
|
if isinstance(x, mpf) and x.val[0] >= 0:
|
|
488
518
|
return make_mpf(fsqrt(x.val, mpf._prec, mpf._rounding))
|
|
489
519
|
x = mpc(x)
|
|
@@ -500,7 +530,7 @@ def hypot(x, y):
|
|
|
500
530
|
# can construct all of them the same way (unlike log, sqrt, etc)
|
|
501
531
|
def ef(name, real_f, complex_f, doc):
|
|
502
532
|
def f(x):
|
|
503
|
-
x =
|
|
533
|
+
x = convert_lossless(x)
|
|
504
534
|
if isinstance(x, mpf):
|
|
505
535
|
return make_mpf(real_f(x.val, mpf._prec, mpf._rounding))
|
|
506
536
|
else:
|
|
@@ -519,7 +549,7 @@ sinh = ef('sinh', fsinh, fcsinh, "Returns the hyperbolic sine of x.")
|
|
|
519
549
|
# TODO: implement tanh and complex tan in lib instead
|
|
520
550
|
def tan(x):
|
|
521
551
|
"""Returns the tangent of x."""
|
|
522
|
-
x =
|
|
552
|
+
x = convert_lossless(x)
|
|
523
553
|
if isinstance(x, mpf):
|
|
524
554
|
return make_mpf(ftan(x.val, mpf._prec, mpf._rounding))
|
|
525
555
|
# the complex division can cause enormous cancellation.
|
|
@@ -531,7 +561,7 @@ def tan(x):
|
|
|
531
561
|
|
|
532
562
|
def tanh(x):
|
|
533
563
|
"""Returns the hyperbolic tangent of x."""
|
|
534
|
-
x =
|
|
564
|
+
x = convert_lossless(x)
|
|
535
565
|
oldprec = mpf._prec
|
|
536
566
|
a = abs(x)
|
|
537
567
|
mpf._prec += 10
|
|
@@ -569,7 +599,7 @@ def log(x, b=None):
|
|
|
569
599
|
a = log(x) / log(b)
|
|
570
600
|
mpf.prec -= 3
|
|
571
601
|
return +a
|
|
572
|
-
x =
|
|
602
|
+
x = convert_lossless(x)
|
|
573
603
|
if not x:
|
|
574
604
|
raise ValueError, "logarithm of 0"
|
|
575
605
|
if isinstance(x, mpf) and x.val[0] > 0:
|
|
@@ -587,7 +617,7 @@ def power(x, y):
|
|
|
587
617
|
|
|
588
618
|
def atan(x):
|
|
589
619
|
"""Returns the inverse tangent of x."""
|
|
590
|
-
x =
|
|
620
|
+
x = convert_lossless(x)
|
|
591
621
|
if isinstance(x, mpf):
|
|
592
622
|
return make_mpf(fatan(x.val, mpf._prec, mpf._rounding))
|
|
593
623
|
# TODO: maybe get this to agree with Python's cmath atan about the
|
|
@@ -631,10 +661,8 @@ def _asin_complex(z):
|
|
|
631
661
|
def asin(x):
|
|
632
662
|
"""Returns the inverse sine of x. Outside the range [-1, 1], the
|
|
633
663
|
result is complex and defined as the principal branch value of
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
"""
|
|
637
|
-
x = mpnumeric(x)
|
|
664
|
+
-i * log(i * x + sqrt(1 - x**2))."""
|
|
665
|
+
x = convert_lossless(x)
|
|
638
666
|
if isinstance(x, mpf) and abs(x) <= 1:
|
|
639
667
|
return _asin_complex(x).real
|
|
640
668
|
return _asin_complex(x)
|
|
@@ -648,21 +676,16 @@ def _acos_complex(z):
|
|
|
648
676
|
def acos(x):
|
|
649
677
|
"""Returns the inverse cosine of x. Outside the range [-1, 1], the
|
|
650
678
|
result is complex and defined as the principal branch value of
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
"""
|
|
654
|
-
x = mpnumeric(x)
|
|
679
|
+
pi/2 + i * log(i * x + sqrt(1 - x**2))."""
|
|
680
|
+
x = convert_lossless(x)
|
|
655
681
|
if isinstance(x, mpf) and abs(x) <= 1:
|
|
656
682
|
return _acos_complex(x).real
|
|
657
683
|
return _acos_complex(x)
|
|
658
684
|
|
|
659
685
|
def asinh(x):
|
|
660
686
|
"""Returns the inverse hyperbolic sine of x. For complex x, the
|
|
661
|
-
result is the principal branch value of
|
|
662
|
-
|
|
663
|
-
log(x + sqrt(1 + x**2)).
|
|
664
|
-
"""
|
|
665
|
-
x = mpnumeric(x)
|
|
687
|
+
result is the principal branch value of log(x + sqrt(1 + x**2))."""
|
|
688
|
+
x = convert_lossless(x)
|
|
666
689
|
oldprec = mpf._prec
|
|
667
690
|
a = abs(x)
|
|
668
691
|
mpf._prec += 10
|
|
@@ -679,7 +702,7 @@ def acosh(x):
|
|
|
679
702
|
"""Returns the inverse hyperbolic cosine of x. The value is
|
|
680
703
|
given by log(x + sqrt(1 + x**2)), where the principal branch is
|
|
681
704
|
used when the result is complex."""
|
|
682
|
-
x =
|
|
705
|
+
x = convert_lossless(x)
|
|
683
706
|
mpf._prec += 10
|
|
684
707
|
t = log(x + sqrt(x-1)*sqrt(x+1))
|
|
685
708
|
mpf._prec -= 10
|
|
@@ -688,11 +711,8 @@ def acosh(x):
|
|
|
688
711
|
def atanh(x):
|
|
689
712
|
"""Returns the inverse hyperbolic tangent of x. Outside the range
|
|
690
713
|
[-1, 1], the result is complex and defined as the principal branch
|
|
691
|
-
value of
|
|
692
|
-
|
|
693
|
-
(log(1+x) - log(1-x))/2.
|
|
694
|
-
"""
|
|
695
|
-
x = mpnumeric(x)
|
|
714
|
+
value of (log(1+x) - log(1-x))/2."""
|
|
715
|
+
x = convert_lossless(x)
|
|
696
716
|
oldprec = mpf._prec
|
|
697
717
|
a = abs(x)
|
|
698
718
|
mpf._prec += 10
|
|
@@ -706,8 +726,14 @@ def atanh(x):
|
|
|
706
726
|
mpf._prec = oldprec
|
|
707
727
|
return +t
|
|
708
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"]
|
|
709
738
|
|
|
710
|
-
__all__ = ["mpnumeric", "mpf", "mpc", "pi", "e", "cgamma", "clog2", "clog10", "j",
|
|
711
|
-
"sqrt", "hypot", "exp", "log", "cos", "sin", "tan", "atan", "atan2", "power",
|
|
712
|
-
"asin", "acos", "sinh", "cosh", "tanh", "asinh", "acosh", "atanh", "arg"]
|
|
713
739
|
|
|
@@ -2,10 +2,10 @@ from distutils.core import setup
|
|
|
2
2
|
|
|
3
3
|
setup(name='mpmath',
|
|
4
4
|
description = 'Python library for arbitrary-precision floating-point arithmetic',
|
|
5
|
-
version='0.
|
|
5
|
+
version='0.4',
|
|
6
6
|
url='http://mpmath.googlecode.com',
|
|
7
7
|
author='Fredrik Johansson',
|
|
8
8
|
author_email='fredrik.johansson@gmail.com',
|
|
9
9
|
license = 'BSD',
|
|
10
|
-
packages=['mpmath'],
|
|
10
|
+
packages=['mpmath', 'mpmath/lib'],
|
|
11
11
|
)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from mpmath import *
|
|
2
|
+
from mpmath.lib import *
|
|
3
|
+
from decimal import getcontext, Decimal
|
|
4
|
+
import dmath
|
|
5
|
+
from random import seed, random, randint
|
|
6
|
+
|
|
7
|
+
def getrandom(type):
|
|
8
|
+
if type == 'mpf':
|
|
9
|
+
return mpf(random() * 2.0**randint(-10, 10)) ** 0.5
|
|
10
|
+
if type == 'mpfval':
|
|
11
|
+
return (mpf(random() * 2.0**randint(-10, 10)) ** 0.5).val
|
|
12
|
+
if type == 'Decimal':
|
|
13
|
+
return Decimal(repr(random() * 2.0**randint(-10, 10))).sqrt()
|
|
14
|
+
raise TypeError
|
|
15
|
+
|
|
16
|
+
def rndnums(type, N):
|
|
17
|
+
seed(1234)
|
|
18
|
+
xs = [getrandom(type) for i in xrange(N)]
|
|
19
|
+
ys = xs[::-1]
|
|
20
|
+
xys = zip(xs, ys)
|
|
21
|
+
return xs, ys, xys
|
|
22
|
+
|
|
23
|
+
def setprec(type, prec):
|
|
24
|
+
if type == 'Decimal':
|
|
25
|
+
getcontext().prec = prec
|
|
26
|
+
else:
|
|
27
|
+
mpf.dps = prec
|
|
28
|
+
# change prec value to bits for mpfval use
|
|
29
|
+
prec = mpf.prec
|
|
30
|
+
return prec
|
|
31
|
+
|
|
32
|
+
testcode = \
|
|
33
|
+
"""
|
|
34
|
+
def testit(prec, N):
|
|
35
|
+
from time import clock
|
|
36
|
+
RF = ROUND_HALF_EVEN
|
|
37
|
+
prec = setprec('TYPE', prec)
|
|
38
|
+
xs, ys, xys = rndnums('TYPE', N)
|
|
39
|
+
t = 1e100
|
|
40
|
+
for i in range(3):
|
|
41
|
+
t1 = clock()
|
|
42
|
+
for x, y in xys:
|
|
43
|
+
OP
|
|
44
|
+
t2 = clock()
|
|
45
|
+
t = min(t, t2-t1)
|
|
46
|
+
return t
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
tests = []
|
|
50
|
+
atests = [
|
|
51
|
+
('Convert to integer (int(x))', 'int(x)', 'int(x)', 'to_int(x)'),
|
|
52
|
+
('Convert to string (str(x))', 'str(x)', 'str(x)', 'to_str(x, int(prec/3.321))'),
|
|
53
|
+
('Convert to float (float(x))', 'float(x)', 'float(x)', 'to_float(x)'),
|
|
54
|
+
('Equality (x==y)', 'x==y', 'x==y', 'feq(x, y)'),
|
|
55
|
+
('Comparison (x<y)', 'x<y', 'x<y', 'fcmp(x, y) < 0'),
|
|
56
|
+
('Addition (x+y)', 'x+y', 'x+y', 'fadd(x, y, prec, RF)'),
|
|
57
|
+
('Subtraction (x-y)', 'x+y', 'x+y', 'fsub(x, y, prec, RF)'),
|
|
58
|
+
('Multiplication (x*y)', 'x*y', 'x*y', 'fmul(x, y, prec, RF)'),
|
|
59
|
+
('Division (x/y)', 'x/y', 'x/y', 'fdiv(x, y, prec, RF)'),
|
|
60
|
+
('Square root (x^0.5)', 'x.sqrt()', 'sqrt(x)', 'fsqrt(x, prec, RF)'),
|
|
61
|
+
('Integer power (x^42)', 'x**42', 'x**42', 'fpow(x, 42, prec, RF)'),
|
|
62
|
+
('Exponential function (exp(x))', 'dmath.exp(x)', 'exp(x)', 'fexp(x, prec, RF)'),
|
|
63
|
+
('Natural logarithm (log(x))', 'dmath.log(x+1)', 'log(x)', 'flog(x, prec, RF)'),
|
|
64
|
+
('Sine (sin(x))', 'dmath.sin(x)', 'sin(x)', 'fsin(x, prec, RF)'),
|
|
65
|
+
('Tangent (tan(x))', 'dmath.tan(x)', 'tan(x)', 'ftan(x, prec, RF)'),
|
|
66
|
+
('Inverse tangent(atan(x))', 'dmath.atan(x)', 'atan(x)', 'fatan(x, prec, RF)'),
|
|
67
|
+
('Hyperbolic cosine (cosh(x))', 'dmath.cosh(x)', 'cosh(x)', 'fcosh(x, prec, RF)')
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
slow = ["exp", "log", "sin", "tan", "cos"]
|
|
71
|
+
|
|
72
|
+
for op in atests:
|
|
73
|
+
cases = [op[0]]
|
|
74
|
+
if op[1]:
|
|
75
|
+
exec testcode.replace("OP", op[1]).replace("TYPE", "Decimal")
|
|
76
|
+
cases += [testit]
|
|
77
|
+
else:
|
|
78
|
+
cases += [None]
|
|
79
|
+
exec testcode.replace("OP", op[2]).replace("TYPE", "mpf")
|
|
80
|
+
cases += [testit]
|
|
81
|
+
exec testcode.replace("OP", op[3]).replace("TYPE", "mpfval")
|
|
82
|
+
cases += [testit]
|
|
83
|
+
tests.append(cases)
|
|
84
|
+
|
|
85
|
+
def rd(x):
|
|
86
|
+
if x > 100000: return int(x // 10000) * 10000
|
|
87
|
+
if x > 10000: return int(x // 1000) * 1000
|
|
88
|
+
if x > 1000: return int(x // 100) * 100
|
|
89
|
+
if x > 100: return int(x // 10) * 10
|
|
90
|
+
return int(x)
|
|
91
|
+
|
|
92
|
+
def runtests():
|
|
93
|
+
results = []
|
|
94
|
+
for test in tests:
|
|
95
|
+
name, dectest, mpftest, mpfvaltest = test
|
|
96
|
+
if any(s in name for s in slow):
|
|
97
|
+
N = 1
|
|
98
|
+
precs = [15, 30, 100, 300]
|
|
99
|
+
else:
|
|
100
|
+
N = 10
|
|
101
|
+
precs = [15, 30, 100, 300, 1000]
|
|
102
|
+
header_name = "*" + name + "*"
|
|
103
|
+
rows = []
|
|
104
|
+
for prec in precs:
|
|
105
|
+
print name, prec
|
|
106
|
+
if dectest is None:
|
|
107
|
+
t1 = 1e1000-1e1000
|
|
108
|
+
else:
|
|
109
|
+
t1 = dectest(prec, N)
|
|
110
|
+
t2 = mpftest(prec, N)
|
|
111
|
+
t3 = mpfvaltest(prec, N)
|
|
112
|
+
s = []
|
|
113
|
+
s += ["%i" % prec]
|
|
114
|
+
s += [str(rd(N/t1))]
|
|
115
|
+
s += [str(rd(N/t2)) + (" (%.1fx)" % (t1/t2))]
|
|
116
|
+
s += [str(rd(N/t3)) + (" (%.1fx)" % (t1/t3))]
|
|
117
|
+
rows.append(s)
|
|
118
|
+
results.append((header_name, rows))
|
|
119
|
+
return results
|
|
120
|
+
|
|
121
|
+
import gc
|
|
122
|
+
gc.disable()
|
|
123
|
+
results1 = runtests()
|
|
124
|
+
import psyco
|
|
125
|
+
psyco.full()
|
|
126
|
+
results2 = runtests()
|
|
127
|
+
|
|
128
|
+
import sys
|
|
129
|
+
sys.stdout = open("results.txt", "w")
|
|
130
|
+
|
|
131
|
+
for r1, r2 in zip(results1, results2):
|
|
132
|
+
name = r1[0]
|
|
133
|
+
print name
|
|
134
|
+
print "|| *digits* || *Decimal* || *mpf* || *raw mpf* || *Decimal+psyco* || *mpf+psyco* || *raw mpf+psyco* ||"
|
|
135
|
+
for a, b in zip(r1[1], r2[1]):
|
|
136
|
+
cols = a + b[1:]
|
|
137
|
+
print "|| " + (" || ".join(cols)) + " ||"
|
|
138
|
+
print
|
|
139
|
+
|