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
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
--0.4--
|
|
2
|
+
Released November 3, 2007
|
|
3
|
+
|
|
4
|
+
* new string conversion code (much faster; unlimited exponents)
|
|
5
|
+
* fixed bug in factorial (it gave the wrong value, though gamma worked)
|
|
6
|
+
* division now uses a rigorous algorithm for directed rounding
|
|
7
|
+
(mpmath previously used a heuristic that got the last bit wrong
|
|
8
|
+
in 1/10000 of cases)
|
|
9
|
+
* misc. performance improvements (arithmetic is 15% faster)
|
|
10
|
+
* refactored parts of the code; added many more docstrings and tests
|
|
11
|
+
* added a function rand() for generating full-precision random numbers
|
|
12
|
+
* rewrote the benchmark script to compare against Decimal and to
|
|
13
|
+
automatically generate timings with psyco both disabled and enabled
|
|
14
|
+
* rewrote unit tests to use py.test
|
|
15
|
+
|
|
1
16
|
--0.3--
|
|
2
17
|
Released October 5, 2007
|
|
3
18
|
|
{mpmath-0.3 → mpmath-0.4}/README
RENAMED
|
@@ -12,6 +12,7 @@ LICENSE file for details)
|
|
|
12
12
|
0. History
|
|
13
13
|
----------
|
|
14
14
|
|
|
15
|
+
* Version 0.4 released on November 3, 2007
|
|
15
16
|
* Version 0.3 released on October 5, 2007
|
|
16
17
|
* Version 0.2 released on October 2, 2007
|
|
17
18
|
* Version 0.1 released on September 27, 2007
|
|
@@ -40,6 +41,9 @@ http://mpmath.googlecode.com/svn/trunk/
|
|
|
40
41
|
2. Documentation and usage
|
|
41
42
|
--------------------------
|
|
42
43
|
|
|
44
|
+
Note: some additional documentation is available on the mpmath website.
|
|
45
|
+
The unit tests and internal docstrings may also be helpful.
|
|
46
|
+
|
|
43
47
|
Import mpmath with
|
|
44
48
|
|
|
45
49
|
from mpmath import *
|
|
@@ -51,7 +55,7 @@ Python's float and complex types:
|
|
|
51
55
|
mpf('0.66666666666666663')
|
|
52
56
|
|
|
53
57
|
>>> mpc(0, -1)
|
|
54
|
-
mpc(real='0', imag='-1')
|
|
58
|
+
mpc(real='0.0', imag='-1.0')
|
|
55
59
|
|
|
56
60
|
>>> mpf(-0.6) ** mpf(-0.2)
|
|
57
61
|
mpc(real='0.89603999408558288', imag='-0.65101116249684809')
|
|
@@ -158,15 +162,12 @@ and verifies a 15-digit approximation interval for pi:
|
|
|
158
162
|
singularities, and/or with the precision set to (say) several hundred
|
|
159
163
|
digits, the last few digits in a result may be wrong.
|
|
160
164
|
|
|
161
|
-
* Directed rounding works for
|
|
165
|
+
* Directed rounding works for arithmetic operations. It is implemented
|
|
162
166
|
heuristically for other operations, and their results may be off by one
|
|
163
167
|
or two bits in the last place (if otherwise accurate).
|
|
164
168
|
|
|
165
|
-
* binary <-> decimal conversion currently uses the decimal module, which
|
|
166
|
-
is very slow and fails for extremely large and small numbers
|
|
167
|
-
|
|
168
169
|
* Some IEEE 754 features such as infinities, NaN and denormal rounding
|
|
169
|
-
are not
|
|
170
|
+
are not supported
|
|
170
171
|
|
|
171
172
|
|
|
172
173
|
4. Help and bug reports
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
import math
|
|
3
3
|
from time import clock
|
|
4
|
-
|
|
5
|
-
from mpmath.lib import
|
|
6
|
-
|
|
4
|
+
|
|
5
|
+
from mpmath.lib import pi_agm, bin_to_radix, numeral
|
|
6
|
+
|
|
7
7
|
|
|
8
8
|
def display_fraction(digits, skip=0, colwidth=10, columns=5):
|
|
9
9
|
perline = colwidth * columns
|
|
@@ -25,27 +25,21 @@ def display_fraction(digits, skip=0, colwidth=10, columns=5):
|
|
|
25
25
|
buf = buf[colwidth:]
|
|
26
26
|
print s + ":", printed + colwidth*columns
|
|
27
27
|
|
|
28
|
-
def calculateit(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if intpart == "0":
|
|
32
|
-
skip = 0
|
|
33
|
-
else:
|
|
34
|
-
skip = len(intpart)
|
|
28
|
+
def calculateit(base, n, tofile):
|
|
29
|
+
intpart = numeral(3, base)
|
|
30
|
+
skip = 1
|
|
35
31
|
|
|
36
32
|
prec = int(n*math.log(base,2))+10
|
|
37
|
-
mpf.prec = prec
|
|
38
33
|
|
|
39
34
|
print "Step 1 of 2: calculating binary value..."
|
|
40
35
|
t = clock()
|
|
41
|
-
a =
|
|
42
|
-
a = mpf(normalize(a, -prec, prec, ROUND_FLOOR))
|
|
36
|
+
a = pi_agm(prec, verbose=True, verbose_base=base)
|
|
43
37
|
step1_time = clock() - t
|
|
44
38
|
|
|
45
39
|
print "Step 2 of 2: converting to specified base..."
|
|
46
40
|
t = clock()
|
|
47
|
-
d = bin_to_radix(a
|
|
48
|
-
d =
|
|
41
|
+
d = bin_to_radix(a, prec, base, n)
|
|
42
|
+
d = numeral(d, base, n)
|
|
49
43
|
step2_time = clock() - t
|
|
50
44
|
|
|
51
45
|
print "\nWriting output...\n"
|
|
@@ -70,7 +64,7 @@ def interactive():
|
|
|
70
64
|
if tofile:
|
|
71
65
|
tofile = open(tofile, "w")
|
|
72
66
|
|
|
73
|
-
calculateit(
|
|
67
|
+
calculateit(base, digits, tofile)
|
|
74
68
|
raw_input("\nPress enter to close this script.")
|
|
75
69
|
|
|
76
70
|
interactive()
|
|
@@ -178,15 +178,16 @@ def gamma(x):
|
|
|
178
178
|
else:
|
|
179
179
|
x -= 1
|
|
180
180
|
prec, a, c = _get_spouge_coefficients(mpf.prec + 8)
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
# TODO: figure out when we can just use Stirling's formula
|
|
182
|
+
if isinstance(x, mpf) and x.exp >= 0:
|
|
183
|
+
s = _spouge_sum(x.man << x.exp, prec, a, c)
|
|
183
184
|
else:
|
|
184
|
-
|
|
185
|
-
s = _spouge_sum(xs, prec, a, c)
|
|
185
|
+
s = _spouge_sum(x, prec, a, c)
|
|
186
186
|
# TODO: higher precision may be needed here when the precision
|
|
187
187
|
# and/or size of x are extremely large
|
|
188
|
+
xpa = x + a
|
|
188
189
|
mpf.prec += 10
|
|
189
|
-
g = exp(log(
|
|
190
|
+
g = exp(log(xpa) * (x + 0.5) - xpa) * s
|
|
190
191
|
|
|
191
192
|
mpf.prec = oldprec
|
|
192
193
|
return +g
|
|
@@ -196,7 +197,7 @@ def factorial(x):
|
|
|
196
197
|
"""Returns the factorial of x, defined in terms of the gamma
|
|
197
198
|
function for non-integer x. An exception is raised if x is a
|
|
198
199
|
negative integer."""
|
|
199
|
-
return gamma(x
|
|
200
|
+
return gamma(x+1)
|
|
200
201
|
|
|
201
202
|
|
|
202
203
|
#---------------------------------------------------------------------------#
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Arithmetic operations and functions on complex numbers, represented on
|
|
3
|
+
rectangular form as tuples of real floating-point numbers.
|
|
4
|
+
|
|
5
|
+
This module is quite compact, since most of the dirty work can be
|
|
6
|
+
delegated to functions that work on real numbers.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from util import *
|
|
10
|
+
from floatop import *
|
|
11
|
+
from functions import *
|
|
12
|
+
from squareroot import *
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Use fastest rounding mode for intermediate calculations
|
|
16
|
+
RF = ROUND_FLOOR
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
#----------------------------------------------------------------------
|
|
20
|
+
# Complex parts
|
|
21
|
+
#
|
|
22
|
+
|
|
23
|
+
def fcabs(a, b, prec, rounding):
|
|
24
|
+
"""
|
|
25
|
+
Absolute value of a complex number, |a+bi|. Returns a single
|
|
26
|
+
real number.
|
|
27
|
+
"""
|
|
28
|
+
return fhypot(a, b, prec, rounding)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
#----------------------------------------------------------------------
|
|
32
|
+
# Arithmetic
|
|
33
|
+
#
|
|
34
|
+
|
|
35
|
+
def fcmul(a, b, c, d, prec, rounding):
|
|
36
|
+
"""
|
|
37
|
+
Complex multiplication.
|
|
38
|
+
|
|
39
|
+
Returns the real and imaginary part of (a+bi)*(c+di), rounded to
|
|
40
|
+
the specified precision. The rounding mode applies to the real and
|
|
41
|
+
imaginary parts separately.
|
|
42
|
+
|
|
43
|
+
Implemented the straightforward way. TODO: use a more stable
|
|
44
|
+
algorithm to avoid cancellation.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
# All-real case
|
|
48
|
+
if b == d == fzero:
|
|
49
|
+
return fmul(a, c, prec, rounding), fzero
|
|
50
|
+
|
|
51
|
+
ep = prec + 10
|
|
52
|
+
|
|
53
|
+
re = fsub(fmul(a,c, ep, RF), fmul(b,d, ep, RF), prec, rounding)
|
|
54
|
+
im = fadd(fmul(a,d, ep, RF), fmul(b,c, ep, RF), prec, rounding)
|
|
55
|
+
return re, im
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
#----------------------------------------------------------------------
|
|
59
|
+
# Square root
|
|
60
|
+
#
|
|
61
|
+
|
|
62
|
+
def fcsqrt(a, b, prec, rounding):
|
|
63
|
+
"""
|
|
64
|
+
Complex square root (principal branch).
|
|
65
|
+
|
|
66
|
+
We have sqrt(a+bi) = sqrt((r+a)/2) + b/sqrt(2*(r+a))*i where
|
|
67
|
+
r = abs(a+bi), when a+bi is not a negative real number.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
if a == b == fzero:
|
|
71
|
+
return (a, b)
|
|
72
|
+
|
|
73
|
+
# When a+bi is a negative real number, we get a real sqrt times i
|
|
74
|
+
if a[0] < 0 and b == fzero:
|
|
75
|
+
im = fsqrt(fneg_exact(a), prec, rounding)
|
|
76
|
+
return (fzero, im)
|
|
77
|
+
|
|
78
|
+
ep = prec+20
|
|
79
|
+
|
|
80
|
+
t = fadd(fcabs(a, b, ep, RF), a, ep, RF) # t = abs(a+bi) + a
|
|
81
|
+
u = fmul(t, fhalf, ep, RF) # u = t / 2
|
|
82
|
+
re = fsqrt(u, prec, rounding) # re = sqrt(u)
|
|
83
|
+
v = fmul(t, ftwo, ep, RF) # v = t * 2
|
|
84
|
+
w = fsqrt(v, ep, RF) # w = sqrt(v)
|
|
85
|
+
im = fdiv(b, w, prec, rounding) # im = b / w
|
|
86
|
+
|
|
87
|
+
return re, im
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
#----------------------------------------------------------------------
|
|
91
|
+
# Exp and log
|
|
92
|
+
#
|
|
93
|
+
|
|
94
|
+
def fcexp(a, b, prec, rounding):
|
|
95
|
+
"""
|
|
96
|
+
Complex exponential function.
|
|
97
|
+
|
|
98
|
+
We use the direct formula exp(a+bi) = exp(a) * (cos(b) + sin(b)*i)
|
|
99
|
+
for the computation. This formula is very nice because it is
|
|
100
|
+
perfectly stable; since we just do real multiplications, the only
|
|
101
|
+
numerical errors that can creep in are single-ulp rounding errors.
|
|
102
|
+
|
|
103
|
+
The formula is efficient since mpmath's real exp is quite fast and
|
|
104
|
+
since we can compute cos and sin simultaneously.
|
|
105
|
+
|
|
106
|
+
It is no problem if a and b are large; if the implementations of
|
|
107
|
+
exp/cos/sin are accurate and efficient for all real numbers, then
|
|
108
|
+
so is this function for all complex numbers.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
mag = fexp(a, prec+4, rounding)
|
|
112
|
+
|
|
113
|
+
c, s = cos_sin(b, prec+4, rounding)
|
|
114
|
+
|
|
115
|
+
re = fmul(mag, c, prec, rounding)
|
|
116
|
+
im = fmul(mag, s, prec, rounding)
|
|
117
|
+
return re, im
|
|
118
|
+
|
|
119
|
+
# TODO: log
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
#----------------------------------------------------------------------
|
|
123
|
+
# Trigonometric functions
|
|
124
|
+
#
|
|
125
|
+
|
|
126
|
+
def fccos(a, b, prec, rounding):
|
|
127
|
+
"""
|
|
128
|
+
Complex cosine.
|
|
129
|
+
|
|
130
|
+
The formula used is cos(a+bi) = cos(a)*cosh(b) - sin(a)*sinh(b)*i.
|
|
131
|
+
|
|
132
|
+
The same comments apply as for the complex exp: only real
|
|
133
|
+
multiplications are performed, so no cancellation errors are
|
|
134
|
+
possible. The formula is also efficient since we can compute both
|
|
135
|
+
pairs (cos, sin) and (cosh, sinh) in single steps.
|
|
136
|
+
"""
|
|
137
|
+
ep = prec + 6
|
|
138
|
+
|
|
139
|
+
c, s = cos_sin(a, ep, RF)
|
|
140
|
+
ch, sh = cosh_sinh(b, ep, RF)
|
|
141
|
+
|
|
142
|
+
re = fmul(c, ch, prec, rounding)
|
|
143
|
+
im = fmul(s, sh, prec, rounding)
|
|
144
|
+
|
|
145
|
+
return re, fneg_exact(im)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def fcsin(a, b, prec, rounding):
|
|
149
|
+
"""
|
|
150
|
+
Complex sine.
|
|
151
|
+
|
|
152
|
+
We have sin(a+bi) = sin(a)*cosh(b) + cos(a)*sinh(b)*i.
|
|
153
|
+
See the docstring for fccos for additional comments.
|
|
154
|
+
"""
|
|
155
|
+
ep = prec + 6
|
|
156
|
+
|
|
157
|
+
c, s = cos_sin(a, ep, RF)
|
|
158
|
+
ch, sh = cosh_sinh(b, ep, RF)
|
|
159
|
+
|
|
160
|
+
re = fmul(s, ch, prec, rounding)
|
|
161
|
+
im = fmul(c, sh, prec, rounding)
|
|
162
|
+
|
|
163
|
+
return re, im
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# TODO: complex tan
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
#----------------------------------------------------------------------
|
|
170
|
+
# Hyperbolic functions
|
|
171
|
+
#
|
|
172
|
+
|
|
173
|
+
def fccosh(a, b, prec, rounding):
|
|
174
|
+
"""Complex hyperbolic cosine. Computed as cosh(z) = cos(z*i)."""
|
|
175
|
+
return fccos(b, fneg_exact(a), prec, rounding)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def fcsinh(a, b, prec, rounding):
|
|
179
|
+
"""Complex hyperbolic sine. Computed as sinh(z) = -i*sin(z*i)."""
|
|
180
|
+
b, a = fcsin(b, a, prec, rounding)
|
|
181
|
+
return a, b
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mathematical constants
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import math
|
|
7
|
+
|
|
8
|
+
from util import *
|
|
9
|
+
from floatop import *
|
|
10
|
+
from squareroot import *
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def constant_memo(f):
|
|
14
|
+
"""
|
|
15
|
+
Memoization for calculation of constants using fixed-point
|
|
16
|
+
arithmetic. Only store the value computed with highest precision;
|
|
17
|
+
if a lower or equal precision is requested later, the result can
|
|
18
|
+
be generated directly through downshifting the cached value.
|
|
19
|
+
"""
|
|
20
|
+
f.memo_prec = -1
|
|
21
|
+
f.memo_val = None
|
|
22
|
+
|
|
23
|
+
def g(prec):
|
|
24
|
+
if prec == f.memo_prec:
|
|
25
|
+
return f.memo_val
|
|
26
|
+
if prec < f.memo_prec:
|
|
27
|
+
return f.memo_val >> (f.memo_prec-prec)
|
|
28
|
+
f.memo_val = f(prec)
|
|
29
|
+
f.memo_prec = prec
|
|
30
|
+
return f.memo_val
|
|
31
|
+
|
|
32
|
+
g.__name__ = f.__name__
|
|
33
|
+
g.__doc__ = f.__doc__
|
|
34
|
+
return g
|
|
35
|
+
|
|
36
|
+
def acot(n, prec, hyperbolic):
|
|
37
|
+
"""
|
|
38
|
+
Compute acot of an integer using fixed-point arithmetic. With
|
|
39
|
+
hyperbolic=True, compute acoth. We use the series expansion
|
|
40
|
+
|
|
41
|
+
1 1 1
|
|
42
|
+
acot(n) = --- - ---- + ---- - ...,
|
|
43
|
+
3 5
|
|
44
|
+
n 3 n 5 n
|
|
45
|
+
|
|
46
|
+
optimized for integer arguments. In the hyperbolic case, all
|
|
47
|
+
negative terms are changed to positive ones.
|
|
48
|
+
"""
|
|
49
|
+
s = t = (1 << prec) // n # 1 / n
|
|
50
|
+
k = 3
|
|
51
|
+
while 1:
|
|
52
|
+
# Repeatedly divide by k * n**2, and add
|
|
53
|
+
t //= (n*n)
|
|
54
|
+
term = t // k
|
|
55
|
+
if not term:
|
|
56
|
+
break
|
|
57
|
+
# Alternate signs
|
|
58
|
+
if hyperbolic or not k & 2:
|
|
59
|
+
s += term
|
|
60
|
+
else:
|
|
61
|
+
s -= term
|
|
62
|
+
k += 2
|
|
63
|
+
return s
|
|
64
|
+
|
|
65
|
+
def machin(coefs, prec, hyperbolic=False):
|
|
66
|
+
"""
|
|
67
|
+
Evaluate a Machin-like formula, i.e., a linear combination of
|
|
68
|
+
acot(n) or acoth(n) for specific integer values of n, using fixed-
|
|
69
|
+
point arithmetic.
|
|
70
|
+
|
|
71
|
+
The input should be a list [(c, n), ...], giving c*acot[h](n) + ...
|
|
72
|
+
"""
|
|
73
|
+
extraprec = 10
|
|
74
|
+
s = 0
|
|
75
|
+
for a, b in coefs:
|
|
76
|
+
s += a * acot(b, prec+extraprec, hyperbolic)
|
|
77
|
+
return (s >> extraprec)
|
|
78
|
+
|
|
79
|
+
def agm_status(prec, step, adiff, verbose_base):
|
|
80
|
+
logdiff = math.log(max(1, adiff), verbose_base)
|
|
81
|
+
digits = int(prec/math.log(verbose_base,2) - logdiff)
|
|
82
|
+
print " iteration", step, ("(accuracy ~= %i base-%i digits)" % \
|
|
83
|
+
(digits, verbose_base))
|
|
84
|
+
|
|
85
|
+
def pi_agm(prec, verbose=False, verbose_base=10):
|
|
86
|
+
"""
|
|
87
|
+
Compute floor(pi * 2**prec) as a big integer using the Brent-
|
|
88
|
+
Salamin algorithm based on the arithmetic-geometric mean.
|
|
89
|
+
|
|
90
|
+
See for example Wikipedia (http://en.wikipedia.org/wiki/Brent-
|
|
91
|
+
Salamin_algorithm) or "Pi and the AGM" by Jonathan and Peter
|
|
92
|
+
Borwein (Wiley, 1987). The algorithm (as stated in the Wikipedia
|
|
93
|
+
article) consists of setting
|
|
94
|
+
|
|
95
|
+
a_0 = 1
|
|
96
|
+
b_0 = 1/sqrt(2)
|
|
97
|
+
t_0 = 1/4
|
|
98
|
+
p_0 = 1
|
|
99
|
+
|
|
100
|
+
and computing
|
|
101
|
+
|
|
102
|
+
a_{n+1} = (a_n + b_n)/2
|
|
103
|
+
b_{n+1} = sqrt(a_n * b_n)
|
|
104
|
+
t_{n+1} = t_n - p_n*(a_n - a_{n+1})**2
|
|
105
|
+
p_{n+1} = 2*p_n
|
|
106
|
+
|
|
107
|
+
for n = 0, 1, 2, 3, ..., after which the approximation is given by
|
|
108
|
+
pi ~= (a_n + b_n)**2 / (4*t_n). Each step roughly doubles the
|
|
109
|
+
number of correct digits.
|
|
110
|
+
"""
|
|
111
|
+
extraprec = 50
|
|
112
|
+
prec += extraprec
|
|
113
|
+
|
|
114
|
+
# Initialial values. a, b and t are fixed-point numbers
|
|
115
|
+
a = 1 << prec
|
|
116
|
+
b = sqrt_fixed2(a >> 1, prec)
|
|
117
|
+
t = a >> 2
|
|
118
|
+
p = 1
|
|
119
|
+
|
|
120
|
+
step = 1
|
|
121
|
+
while 1:
|
|
122
|
+
an = (a + b) >> 1
|
|
123
|
+
adiff = a - an
|
|
124
|
+
if verbose:
|
|
125
|
+
agm_status(prec, step, adiff, verbose_base)
|
|
126
|
+
# No change in a
|
|
127
|
+
if p > 16 and abs(adiff) < 1000:
|
|
128
|
+
break
|
|
129
|
+
prod = (a * b) >> prec
|
|
130
|
+
b = sqrt_fixed2(prod, prec)
|
|
131
|
+
t = t - p*((adiff**2) >> prec)
|
|
132
|
+
p = 2*p
|
|
133
|
+
a = an
|
|
134
|
+
step += 1
|
|
135
|
+
if verbose:
|
|
136
|
+
print " final division"
|
|
137
|
+
pi = ((((a+b)**2) >> 2) // t)
|
|
138
|
+
return pi >> extraprec
|
|
139
|
+
|
|
140
|
+
@constant_memo
|
|
141
|
+
def pi_fixed(prec):
|
|
142
|
+
"""
|
|
143
|
+
Compute floor(pi * 2**prec) as a big integer.
|
|
144
|
+
|
|
145
|
+
For low precisions, Machin's formula pi = 16*acot(5)-4*acot(239)
|
|
146
|
+
is used. For high precisions, the more efficient arithmetic-
|
|
147
|
+
geometric mean iteration is used.
|
|
148
|
+
"""
|
|
149
|
+
if prec < 10000:
|
|
150
|
+
return machin([(16, 5), (-4, 239)], prec)
|
|
151
|
+
else:
|
|
152
|
+
return pi_agm(prec)
|
|
153
|
+
|
|
154
|
+
def fpi(prec, rounding):
|
|
155
|
+
"""Compute a floating-point approximation of pi"""
|
|
156
|
+
return normalize(pi_fixed(prec+5), -prec-5, prec, rounding)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# Logarithms of integers can be computed easily using
|
|
160
|
+
# Machin-like formulas
|
|
161
|
+
|
|
162
|
+
@constant_memo
|
|
163
|
+
def log2_fixed(prec):
|
|
164
|
+
return machin([(18, 26), (-2, 4801), (8, 8749)], prec, True)
|
|
165
|
+
|
|
166
|
+
def flog2(prec, rounding):
|
|
167
|
+
return normalize(log2_fixed(prec+5), -prec-5, prec, rounding)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@constant_memo
|
|
171
|
+
def log10_fixed(prec):
|
|
172
|
+
return machin([(46, 31), (34, 49), (20, 161)], prec, True)
|
|
173
|
+
|
|
174
|
+
def flog10(prec, rounding):
|
|
175
|
+
return normalize(log10_fixed(prec+5), -prec-5, prec, rounding)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
"""
|
|
179
|
+
Euler's constant (gamma) is computed using the Brent-McMillan formula,
|
|
180
|
+
gamma ~= A(n)/B(n) - log(n), where
|
|
181
|
+
|
|
182
|
+
A(n) = sum_{k=0,1,2,...} (n**k / k!)**2 * H(k)
|
|
183
|
+
B(n) = sum_{k=0,1,2,...} (n**k / k!)**2
|
|
184
|
+
H(k) = 1 + 1/2 + 1/3 + ... + 1/k
|
|
185
|
+
|
|
186
|
+
The error is bounded by O(exp(-4n)). Choosing n to be a power
|
|
187
|
+
of two, 2**p, the logarithm becomes particularly easy to calculate.
|
|
188
|
+
|
|
189
|
+
Reference:
|
|
190
|
+
Xavier Gourdon & Pascal Sebah, The Euler constant: gamma
|
|
191
|
+
http://numbers.computation.free.fr/Constants/Gamma/gamma.pdf
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
@constant_memo
|
|
195
|
+
def gamma_fixed(prec):
|
|
196
|
+
prec += 30
|
|
197
|
+
# choose p such that exp(-4*(2**p)) < 2**-n
|
|
198
|
+
p = int(math.log((prec/4) * math.log(2), 2)) + 1
|
|
199
|
+
n = 1<<p
|
|
200
|
+
r = one = 1<<prec
|
|
201
|
+
H, A, B, npow, k, d = 0, 0, 0, 1, 1, 1
|
|
202
|
+
while r:
|
|
203
|
+
A += (r * H) >> prec
|
|
204
|
+
B += r
|
|
205
|
+
r = r * (n*n) // (k*k)
|
|
206
|
+
H += one // k
|
|
207
|
+
k += 1
|
|
208
|
+
S = ((A<<prec) // B) - p*log2_fixed(prec)
|
|
209
|
+
return S >> 30
|
|
210
|
+
|
|
211
|
+
def fgamma(prec, rounding):
|
|
212
|
+
return normalize(gamma_fixed(prec+5), -prec-5, prec, rounding)
|