shomez commited on
Commit
04caa7d
·
verified ·
1 Parent(s): b32c5bc

Upload libelefun.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. libelefun.py +1428 -0
libelefun.py ADDED
@@ -0,0 +1,1428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module implements computation of elementary transcendental
3
+ functions (powers, logarithms, trigonometric and hyperbolic
4
+ functions, inverse trigonometric and hyperbolic) for real
5
+ floating-point numbers.
6
+
7
+ For complex and interval implementations of the same functions,
8
+ see libmpc and libmpi.
9
+
10
+ """
11
+
12
+ import math
13
+ from bisect import bisect
14
+
15
+ from .backend import xrange
16
+ from .backend import MPZ, MPZ_ZERO, MPZ_ONE, MPZ_TWO, MPZ_FIVE, BACKEND
17
+
18
+ from .libmpf import (
19
+ round_floor, round_ceiling, round_down, round_up,
20
+ round_nearest, round_fast,
21
+ ComplexResult,
22
+ bitcount, bctable, lshift, rshift, giant_steps, sqrt_fixed,
23
+ from_int, to_int, from_man_exp, to_fixed, to_float, from_float,
24
+ from_rational, normalize,
25
+ fzero, fone, fnone, fhalf, finf, fninf, fnan,
26
+ mpf_cmp, mpf_sign, mpf_abs,
27
+ mpf_pos, mpf_neg, mpf_add, mpf_sub, mpf_mul, mpf_div, mpf_shift,
28
+ mpf_rdiv_int, mpf_pow_int, mpf_sqrt,
29
+ reciprocal_rnd, negative_rnd, mpf_perturb,
30
+ isqrt_fast
31
+ )
32
+
33
+ from .libintmath import ifib
34
+
35
+
36
+ #-------------------------------------------------------------------------------
37
+ # Tuning parameters
38
+ #-------------------------------------------------------------------------------
39
+
40
+ # Cutoff for computing exp from cosh+sinh. This reduces the
41
+ # number of terms by half, but also requires a square root which
42
+ # is expensive with the pure-Python square root code.
43
+ if BACKEND == 'python':
44
+ EXP_COSH_CUTOFF = 600
45
+ else:
46
+ EXP_COSH_CUTOFF = 400
47
+ # Cutoff for using more than 2 series
48
+ EXP_SERIES_U_CUTOFF = 1500
49
+
50
+ # Also basically determined by sqrt
51
+ if BACKEND == 'python':
52
+ COS_SIN_CACHE_PREC = 400
53
+ else:
54
+ COS_SIN_CACHE_PREC = 200
55
+ COS_SIN_CACHE_STEP = 8
56
+ cos_sin_cache = {}
57
+
58
+ # Number of integer logarithms to cache (for zeta sums)
59
+ MAX_LOG_INT_CACHE = 2000
60
+ log_int_cache = {}
61
+
62
+ LOG_TAYLOR_PREC = 2500 # Use Taylor series with caching up to this prec
63
+ LOG_TAYLOR_SHIFT = 9 # Cache log values in steps of size 2^-N
64
+ log_taylor_cache = {}
65
+ # prec/size ratio of x for fastest convergence in AGM formula
66
+ LOG_AGM_MAG_PREC_RATIO = 20
67
+
68
+ ATAN_TAYLOR_PREC = 3000 # Same as for log
69
+ ATAN_TAYLOR_SHIFT = 7 # steps of size 2^-N
70
+ atan_taylor_cache = {}
71
+
72
+
73
+ # ~= next power of two + 20
74
+ cache_prec_steps = [22,22]
75
+ for k in xrange(1, bitcount(LOG_TAYLOR_PREC)+1):
76
+ cache_prec_steps += [min(2**k,LOG_TAYLOR_PREC)+20] * 2**(k-1)
77
+
78
+
79
+ #----------------------------------------------------------------------------#
80
+ # #
81
+ # Elementary mathematical constants #
82
+ # #
83
+ #----------------------------------------------------------------------------#
84
+
85
+ def constant_memo(f):
86
+ """
87
+ Decorator for caching computed values of mathematical
88
+ constants. This decorator should be applied to a
89
+ function taking a single argument prec as input and
90
+ returning a fixed-point value with the given precision.
91
+ """
92
+ f.memo_prec = -1
93
+ f.memo_val = None
94
+ def g(prec, **kwargs):
95
+ memo_prec = f.memo_prec
96
+ if prec <= memo_prec:
97
+ return f.memo_val >> (memo_prec-prec)
98
+ newprec = int(prec*1.05+10)
99
+ f.memo_val = f(newprec, **kwargs)
100
+ f.memo_prec = newprec
101
+ return f.memo_val >> (newprec-prec)
102
+ g.__name__ = f.__name__
103
+ g.__doc__ = f.__doc__
104
+ return g
105
+
106
+ def def_mpf_constant(fixed):
107
+ """
108
+ Create a function that computes the mpf value for a mathematical
109
+ constant, given a function that computes the fixed-point value.
110
+
111
+ Assumptions: the constant is positive and has magnitude ~= 1;
112
+ the fixed-point function rounds to floor.
113
+ """
114
+ def f(prec, rnd=round_fast):
115
+ wp = prec + 20
116
+ v = fixed(wp)
117
+ if rnd in (round_up, round_ceiling):
118
+ v += 1
119
+ return normalize(0, v, -wp, bitcount(v), prec, rnd)
120
+ f.__doc__ = fixed.__doc__
121
+ return f
122
+
123
+ def bsp_acot(q, a, b, hyperbolic):
124
+ if b - a == 1:
125
+ a1 = MPZ(2*a + 3)
126
+ if hyperbolic or a&1:
127
+ return MPZ_ONE, a1 * q**2, a1
128
+ else:
129
+ return -MPZ_ONE, a1 * q**2, a1
130
+ m = (a+b)//2
131
+ p1, q1, r1 = bsp_acot(q, a, m, hyperbolic)
132
+ p2, q2, r2 = bsp_acot(q, m, b, hyperbolic)
133
+ return q2*p1 + r1*p2, q1*q2, r1*r2
134
+
135
+ # the acoth(x) series converges like the geometric series for x^2
136
+ # N = ceil(p*log(2)/(2*log(x)))
137
+ def acot_fixed(a, prec, hyperbolic):
138
+ """
139
+ Compute acot(a) or acoth(a) for an integer a with binary splitting; see
140
+ http://numbers.computation.free.fr/Constants/Algorithms/splitting.html
141
+ """
142
+ N = int(0.35 * prec/math.log(a) + 20)
143
+ p, q, r = bsp_acot(a, 0,N, hyperbolic)
144
+ return ((p+q)<<prec)//(q*a)
145
+
146
+ def machin(coefs, prec, hyperbolic=False):
147
+ """
148
+ Evaluate a Machin-like formula, i.e., a linear combination of
149
+ acot(n) or acoth(n) for specific integer values of n, using fixed-
150
+ point arithmetic. The input should be a list [(c, n), ...], giving
151
+ c*acot[h](n) + ...
152
+ """
153
+ extraprec = 10
154
+ s = MPZ_ZERO
155
+ for a, b in coefs:
156
+ s += MPZ(a) * acot_fixed(MPZ(b), prec+extraprec, hyperbolic)
157
+ return (s >> extraprec)
158
+
159
+ # Logarithms of integers are needed for various computations involving
160
+ # logarithms, powers, radix conversion, etc
161
+
162
+ @constant_memo
163
+ def ln2_fixed(prec):
164
+ """
165
+ Computes ln(2). This is done with a hyperbolic Machin-type formula,
166
+ with binary splitting at high precision.
167
+ """
168
+ return machin([(18, 26), (-2, 4801), (8, 8749)], prec, True)
169
+
170
+ @constant_memo
171
+ def ln10_fixed(prec):
172
+ """
173
+ Computes ln(10). This is done with a hyperbolic Machin-type formula.
174
+ """
175
+ return machin([(46, 31), (34, 49), (20, 161)], prec, True)
176
+
177
+
178
+ r"""
179
+ For computation of pi, we use the Chudnovsky series:
180
+
181
+ oo
182
+ ___ k
183
+ 1 \ (-1) (6 k)! (A + B k)
184
+ ----- = ) -----------------------
185
+ 12 pi /___ 3 3k+3/2
186
+ (3 k)! (k!) C
187
+ k = 0
188
+
189
+ where A, B, and C are certain integer constants. This series adds roughly
190
+ 14 digits per term. Note that C^(3/2) can be extracted so that the
191
+ series contains only rational terms. This makes binary splitting very
192
+ efficient.
193
+
194
+ The recurrence formulas for the binary splitting were taken from
195
+ ftp://ftp.gmplib.org/pub/src/gmp-chudnovsky.c
196
+
197
+ Previously, Machin's formula was used at low precision and the AGM iteration
198
+ was used at high precision. However, the Chudnovsky series is essentially as
199
+ fast as the Machin formula at low precision and in practice about 3x faster
200
+ than the AGM at high precision (despite theoretically having a worse
201
+ asymptotic complexity), so there is no reason not to use it in all cases.
202
+
203
+ """
204
+
205
+ # Constants in Chudnovsky's series
206
+ CHUD_A = MPZ(13591409)
207
+ CHUD_B = MPZ(545140134)
208
+ CHUD_C = MPZ(640320)
209
+ CHUD_D = MPZ(12)
210
+
211
+ def bs_chudnovsky(a, b, level, verbose):
212
+ """
213
+ Computes the sum from a to b of the series in the Chudnovsky
214
+ formula. Returns g, p, q where p/q is the sum as an exact
215
+ fraction and g is a temporary value used to save work
216
+ for recursive calls.
217
+ """
218
+ if b-a == 1:
219
+ g = MPZ((6*b-5)*(2*b-1)*(6*b-1))
220
+ p = b**3 * CHUD_C**3 // 24
221
+ q = (-1)**b * g * (CHUD_A+CHUD_B*b)
222
+ else:
223
+ if verbose and level < 4:
224
+ print(" binary splitting", a, b)
225
+ mid = (a+b)//2
226
+ g1, p1, q1 = bs_chudnovsky(a, mid, level+1, verbose)
227
+ g2, p2, q2 = bs_chudnovsky(mid, b, level+1, verbose)
228
+ p = p1*p2
229
+ g = g1*g2
230
+ q = q1*p2 + q2*g1
231
+ return g, p, q
232
+
233
+ @constant_memo
234
+ def pi_fixed(prec, verbose=False, verbose_base=None):
235
+ """
236
+ Compute floor(pi * 2**prec) as a big integer.
237
+
238
+ This is done using Chudnovsky's series (see comments in
239
+ libelefun.py for details).
240
+ """
241
+ # The Chudnovsky series gives 14.18 digits per term
242
+ N = int(prec/3.3219280948/14.181647462 + 2)
243
+ if verbose:
244
+ print("binary splitting with N =", N)
245
+ g, p, q = bs_chudnovsky(0, N, 0, verbose)
246
+ sqrtC = isqrt_fast(CHUD_C<<(2*prec))
247
+ v = p*CHUD_C*sqrtC//((q+CHUD_A*p)*CHUD_D)
248
+ return v
249
+
250
+ def degree_fixed(prec):
251
+ return pi_fixed(prec)//180
252
+
253
+ def bspe(a, b):
254
+ """
255
+ Sum series for exp(1)-1 between a, b, returning the result
256
+ as an exact fraction (p, q).
257
+ """
258
+ if b-a == 1:
259
+ return MPZ_ONE, MPZ(b)
260
+ m = (a+b)//2
261
+ p1, q1 = bspe(a, m)
262
+ p2, q2 = bspe(m, b)
263
+ return p1*q2+p2, q1*q2
264
+
265
+ @constant_memo
266
+ def e_fixed(prec):
267
+ """
268
+ Computes exp(1). This is done using the ordinary Taylor series for
269
+ exp, with binary splitting. For a description of the algorithm,
270
+ see:
271
+
272
+ http://numbers.computation.free.fr/Constants/
273
+ Algorithms/splitting.html
274
+ """
275
+ # Slight overestimate of N needed for 1/N! < 2**(-prec)
276
+ # This could be tightened for large N.
277
+ N = int(1.1*prec/math.log(prec) + 20)
278
+ p, q = bspe(0,N)
279
+ return ((p+q)<<prec)//q
280
+
281
+ @constant_memo
282
+ def phi_fixed(prec):
283
+ """
284
+ Computes the golden ratio, (1+sqrt(5))/2
285
+ """
286
+ prec += 10
287
+ a = isqrt_fast(MPZ_FIVE<<(2*prec)) + (MPZ_ONE << prec)
288
+ return a >> 11
289
+
290
+ mpf_phi = def_mpf_constant(phi_fixed)
291
+ mpf_pi = def_mpf_constant(pi_fixed)
292
+ mpf_e = def_mpf_constant(e_fixed)
293
+ mpf_degree = def_mpf_constant(degree_fixed)
294
+ mpf_ln2 = def_mpf_constant(ln2_fixed)
295
+ mpf_ln10 = def_mpf_constant(ln10_fixed)
296
+
297
+
298
+ @constant_memo
299
+ def ln_sqrt2pi_fixed(prec):
300
+ wp = prec + 10
301
+ # ln(sqrt(2*pi)) = ln(2*pi)/2
302
+ return to_fixed(mpf_log(mpf_shift(mpf_pi(wp), 1), wp), prec-1)
303
+
304
+ @constant_memo
305
+ def sqrtpi_fixed(prec):
306
+ return sqrt_fixed(pi_fixed(prec), prec)
307
+
308
+ mpf_sqrtpi = def_mpf_constant(sqrtpi_fixed)
309
+ mpf_ln_sqrt2pi = def_mpf_constant(ln_sqrt2pi_fixed)
310
+
311
+
312
+ #----------------------------------------------------------------------------#
313
+ # #
314
+ # Powers #
315
+ # #
316
+ #----------------------------------------------------------------------------#
317
+
318
+ def mpf_pow(s, t, prec, rnd=round_fast):
319
+ """
320
+ Compute s**t. Raises ComplexResult if s is negative and t is
321
+ fractional.
322
+ """
323
+ ssign, sman, sexp, sbc = s
324
+ tsign, tman, texp, tbc = t
325
+ if ssign and texp < 0:
326
+ raise ComplexResult("negative number raised to a fractional power")
327
+ if texp >= 0:
328
+ return mpf_pow_int(s, (-1)**tsign * (tman<<texp), prec, rnd)
329
+ # s**(n/2) = sqrt(s)**n
330
+ if texp == -1:
331
+ if tman == 1:
332
+ if tsign:
333
+ return mpf_div(fone, mpf_sqrt(s, prec+10,
334
+ reciprocal_rnd[rnd]), prec, rnd)
335
+ return mpf_sqrt(s, prec, rnd)
336
+ else:
337
+ if tsign:
338
+ return mpf_pow_int(mpf_sqrt(s, prec+10,
339
+ reciprocal_rnd[rnd]), -tman, prec, rnd)
340
+ return mpf_pow_int(mpf_sqrt(s, prec+10, rnd), tman, prec, rnd)
341
+ # General formula: s**t = exp(t*log(s))
342
+ # TODO: handle rnd direction of the logarithm carefully
343
+ c = mpf_log(s, prec+10, rnd)
344
+ return mpf_exp(mpf_mul(t, c), prec, rnd)
345
+
346
+ def int_pow_fixed(y, n, prec):
347
+ """n-th power of a fixed point number with precision prec
348
+
349
+ Returns the power in the form man, exp,
350
+ man * 2**exp ~= y**n
351
+ """
352
+ if n == 2:
353
+ return (y*y), 0
354
+ bc = bitcount(y)
355
+ exp = 0
356
+ workprec = 2 * (prec + 4*bitcount(n) + 4)
357
+ _, pm, pe, pbc = fone
358
+ while 1:
359
+ if n & 1:
360
+ pm = pm*y
361
+ pe = pe+exp
362
+ pbc += bc - 2
363
+ pbc = pbc + bctable[int(pm >> pbc)]
364
+ if pbc > workprec:
365
+ pm = pm >> (pbc-workprec)
366
+ pe += pbc - workprec
367
+ pbc = workprec
368
+ n -= 1
369
+ if not n:
370
+ break
371
+ y = y*y
372
+ exp = exp+exp
373
+ bc = bc + bc - 2
374
+ bc = bc + bctable[int(y >> bc)]
375
+ if bc > workprec:
376
+ y = y >> (bc-workprec)
377
+ exp += bc - workprec
378
+ bc = workprec
379
+ n = n // 2
380
+ return pm, pe
381
+
382
+ # froot(s, n, prec, rnd) computes the real n-th root of a
383
+ # positive mpf tuple s.
384
+ # To compute the root we start from a 50-bit estimate for r
385
+ # generated with ordinary floating-point arithmetic, and then refine
386
+ # the value to full accuracy using the iteration
387
+
388
+ # 1 / y \
389
+ # r = --- | (n-1) * r + ---------- |
390
+ # n+1 n \ n r_n**(n-1) /
391
+
392
+ # which is simply Newton's method applied to the equation r**n = y.
393
+ # With giant_steps(start, prec+extra) = [p0,...,pm, prec+extra]
394
+ # and y = man * 2**-shift one has
395
+ # (man * 2**exp)**(1/n) =
396
+ # y**(1/n) * 2**(start-prec/n) * 2**(p0-start) * ... * 2**(prec+extra-pm) *
397
+ # 2**((exp+shift-(n-1)*prec)/n -extra))
398
+ # The last factor is accounted for in the last line of froot.
399
+
400
+ def nthroot_fixed(y, n, prec, exp1):
401
+ start = 50
402
+ try:
403
+ y1 = rshift(y, prec - n*start)
404
+ r = MPZ(int(y1**(1.0/n)))
405
+ except OverflowError:
406
+ y1 = from_int(y1, start)
407
+ fn = from_int(n)
408
+ fn = mpf_rdiv_int(1, fn, start)
409
+ r = mpf_pow(y1, fn, start)
410
+ r = to_int(r)
411
+ extra = 10
412
+ extra1 = n
413
+ prevp = start
414
+ for p in giant_steps(start, prec+extra):
415
+ pm, pe = int_pow_fixed(r, n-1, prevp)
416
+ r2 = rshift(pm, (n-1)*prevp - p - pe - extra1)
417
+ B = lshift(y, 2*p-prec+extra1)//r2
418
+ r = (B + (n-1) * lshift(r, p-prevp))//n
419
+ prevp = p
420
+ return r
421
+
422
+ def mpf_nthroot(s, n, prec, rnd=round_fast):
423
+ """nth-root of a positive number
424
+
425
+ Use the Newton method when faster, otherwise use x**(1/n)
426
+ """
427
+ sign, man, exp, bc = s
428
+ if sign:
429
+ raise ComplexResult("nth root of a negative number")
430
+ if not man:
431
+ if s == fnan:
432
+ return fnan
433
+ if s == fzero:
434
+ if n > 0:
435
+ return fzero
436
+ if n == 0:
437
+ return fone
438
+ return finf
439
+ # Infinity
440
+ if not n:
441
+ return fnan
442
+ if n < 0:
443
+ return fzero
444
+ return finf
445
+ flag_inverse = False
446
+ if n < 2:
447
+ if n == 0:
448
+ return fone
449
+ if n == 1:
450
+ return mpf_pos(s, prec, rnd)
451
+ if n == -1:
452
+ return mpf_div(fone, s, prec, rnd)
453
+ # n < 0
454
+ rnd = reciprocal_rnd[rnd]
455
+ flag_inverse = True
456
+ extra_inverse = 5
457
+ prec += extra_inverse
458
+ n = -n
459
+ if n > 20 and (n >= 20000 or prec < int(233 + 28.3 * n**0.62)):
460
+ prec2 = prec + 10
461
+ fn = from_int(n)
462
+ nth = mpf_rdiv_int(1, fn, prec2)
463
+ r = mpf_pow(s, nth, prec2, rnd)
464
+ s = normalize(r[0], r[1], r[2], r[3], prec, rnd)
465
+ if flag_inverse:
466
+ return mpf_div(fone, s, prec-extra_inverse, rnd)
467
+ else:
468
+ return s
469
+ # Convert to a fixed-point number with prec2 bits.
470
+ prec2 = prec + 2*n - (prec%n)
471
+ # a few tests indicate that
472
+ # for 10 < n < 10**4 a bit more precision is needed
473
+ if n > 10:
474
+ prec2 += prec2//10
475
+ prec2 = prec2 - prec2%n
476
+ # Mantissa may have more bits than we need. Trim it down.
477
+ shift = bc - prec2
478
+ # Adjust exponents to make prec2 and exp+shift multiples of n.
479
+ sign1 = 0
480
+ es = exp+shift
481
+ if es < 0:
482
+ sign1 = 1
483
+ es = -es
484
+ if sign1:
485
+ shift += es%n
486
+ else:
487
+ shift -= es%n
488
+ man = rshift(man, shift)
489
+ extra = 10
490
+ exp1 = ((exp+shift-(n-1)*prec2)//n) - extra
491
+ rnd_shift = 0
492
+ if flag_inverse:
493
+ if rnd == 'u' or rnd == 'c':
494
+ rnd_shift = 1
495
+ else:
496
+ if rnd == 'd' or rnd == 'f':
497
+ rnd_shift = 1
498
+ man = nthroot_fixed(man+rnd_shift, n, prec2, exp1)
499
+ s = from_man_exp(man, exp1, prec, rnd)
500
+ if flag_inverse:
501
+ return mpf_div(fone, s, prec-extra_inverse, rnd)
502
+ else:
503
+ return s
504
+
505
+ def mpf_cbrt(s, prec, rnd=round_fast):
506
+ """cubic root of a positive number"""
507
+ return mpf_nthroot(s, 3, prec, rnd)
508
+
509
+ #----------------------------------------------------------------------------#
510
+ # #
511
+ # Logarithms #
512
+ # #
513
+ #----------------------------------------------------------------------------#
514
+
515
+
516
+ def log_int_fixed(n, prec, ln2=None):
517
+ """
518
+ Fast computation of log(n), caching the value for small n,
519
+ intended for zeta sums.
520
+ """
521
+ if n in log_int_cache:
522
+ value, vprec = log_int_cache[n]
523
+ if vprec >= prec:
524
+ return value >> (vprec - prec)
525
+ wp = prec + 10
526
+ if wp <= LOG_TAYLOR_SHIFT:
527
+ if ln2 is None:
528
+ ln2 = ln2_fixed(wp)
529
+ r = bitcount(n)
530
+ x = n << (wp-r)
531
+ v = log_taylor_cached(x, wp) + r*ln2
532
+ else:
533
+ v = to_fixed(mpf_log(from_int(n), wp+5), wp)
534
+ if n < MAX_LOG_INT_CACHE:
535
+ log_int_cache[n] = (v, wp)
536
+ return v >> (wp-prec)
537
+
538
+ def agm_fixed(a, b, prec):
539
+ """
540
+ Fixed-point computation of agm(a,b), assuming
541
+ a, b both close to unit magnitude.
542
+ """
543
+ i = 0
544
+ while 1:
545
+ anew = (a+b)>>1
546
+ if i > 4 and abs(a-anew) < 8:
547
+ return a
548
+ b = isqrt_fast(a*b)
549
+ a = anew
550
+ i += 1
551
+ return a
552
+
553
+ def log_agm(x, prec):
554
+ """
555
+ Fixed-point computation of -log(x) = log(1/x), suitable
556
+ for large precision. It is required that 0 < x < 1. The
557
+ algorithm used is the Sasaki-Kanada formula
558
+
559
+ -log(x) = pi/agm(theta2(x)^2,theta3(x)^2). [1]
560
+
561
+ For faster convergence in the theta functions, x should
562
+ be chosen closer to 0.
563
+
564
+ Guard bits must be added by the caller.
565
+
566
+ HYPOTHESIS: if x = 2^(-n), n bits need to be added to
567
+ account for the truncation to a fixed-point number,
568
+ and this is the only significant cancellation error.
569
+
570
+ The number of bits lost to roundoff is small and can be
571
+ considered constant.
572
+
573
+ [1] Richard P. Brent, "Fast Algorithms for High-Precision
574
+ Computation of Elementary Functions (extended abstract)",
575
+ http://wwwmaths.anu.edu.au/~brent/pd/RNC7-Brent.pdf
576
+
577
+ """
578
+ x2 = (x*x) >> prec
579
+ # Compute jtheta2(x)**2
580
+ s = a = b = x2
581
+ while a:
582
+ b = (b*x2) >> prec
583
+ a = (a*b) >> prec
584
+ s += a
585
+ s += (MPZ_ONE<<prec)
586
+ s = (s*s)>>(prec-2)
587
+ s = (s*isqrt_fast(x<<prec))>>prec
588
+ # Compute jtheta3(x)**2
589
+ t = a = b = x
590
+ while a:
591
+ b = (b*x2) >> prec
592
+ a = (a*b) >> prec
593
+ t += a
594
+ t = (MPZ_ONE<<prec) + (t<<1)
595
+ t = (t*t)>>prec
596
+ # Final formula
597
+ p = agm_fixed(s, t, prec)
598
+ return (pi_fixed(prec) << prec) // p
599
+
600
+ def log_taylor(x, prec, r=0):
601
+ """
602
+ Fixed-point calculation of log(x). It is assumed that x is close
603
+ enough to 1 for the Taylor series to converge quickly. Convergence
604
+ can be improved by specifying r > 0 to compute
605
+ log(x^(1/2^r))*2^r, at the cost of performing r square roots.
606
+
607
+ The caller must provide sufficient guard bits.
608
+ """
609
+ for i in xrange(r):
610
+ x = isqrt_fast(x<<prec)
611
+ one = MPZ_ONE << prec
612
+ v = ((x-one)<<prec)//(x+one)
613
+ sign = v < 0
614
+ if sign:
615
+ v = -v
616
+ v2 = (v*v) >> prec
617
+ v4 = (v2*v2) >> prec
618
+ s0 = v
619
+ s1 = v//3
620
+ v = (v*v4) >> prec
621
+ k = 5
622
+ while v:
623
+ s0 += v // k
624
+ k += 2
625
+ s1 += v // k
626
+ v = (v*v4) >> prec
627
+ k += 2
628
+ s1 = (s1*v2) >> prec
629
+ s = (s0+s1) << (1+r)
630
+ if sign:
631
+ return -s
632
+ return s
633
+
634
+ def log_taylor_cached(x, prec):
635
+ """
636
+ Fixed-point computation of log(x), assuming x in (0.5, 2)
637
+ and prec <= LOG_TAYLOR_PREC.
638
+ """
639
+ n = x >> (prec-LOG_TAYLOR_SHIFT)
640
+ cached_prec = cache_prec_steps[prec]
641
+ dprec = cached_prec - prec
642
+ if (n, cached_prec) in log_taylor_cache:
643
+ a, log_a = log_taylor_cache[n, cached_prec]
644
+ else:
645
+ a = n << (cached_prec - LOG_TAYLOR_SHIFT)
646
+ log_a = log_taylor(a, cached_prec, 8)
647
+ log_taylor_cache[n, cached_prec] = (a, log_a)
648
+ a >>= dprec
649
+ log_a >>= dprec
650
+ u = ((x - a) << prec) // a
651
+ v = (u << prec) // ((MPZ_TWO << prec) + u)
652
+ v2 = (v*v) >> prec
653
+ v4 = (v2*v2) >> prec
654
+ s0 = v
655
+ s1 = v//3
656
+ v = (v*v4) >> prec
657
+ k = 5
658
+ while v:
659
+ s0 += v//k
660
+ k += 2
661
+ s1 += v//k
662
+ v = (v*v4) >> prec
663
+ k += 2
664
+ s1 = (s1*v2) >> prec
665
+ s = (s0+s1) << 1
666
+ return log_a + s
667
+
668
+ def mpf_log(x, prec, rnd=round_fast):
669
+ """
670
+ Compute the natural logarithm of the mpf value x. If x is negative,
671
+ ComplexResult is raised.
672
+ """
673
+ sign, man, exp, bc = x
674
+ #------------------------------------------------------------------
675
+ # Handle special values
676
+ if not man:
677
+ if x == fzero: return fninf
678
+ if x == finf: return finf
679
+ if x == fnan: return fnan
680
+ if sign:
681
+ raise ComplexResult("logarithm of a negative number")
682
+ wp = prec + 20
683
+ #------------------------------------------------------------------
684
+ # Handle log(2^n) = log(n)*2.
685
+ # Here we catch the only possible exact value, log(1) = 0
686
+ if man == 1:
687
+ if not exp:
688
+ return fzero
689
+ return from_man_exp(exp*ln2_fixed(wp), -wp, prec, rnd)
690
+ mag = exp+bc
691
+ abs_mag = abs(mag)
692
+ #------------------------------------------------------------------
693
+ # Handle x = 1+eps, where log(x) ~ x. We need to check for
694
+ # cancellation when moving to fixed-point math and compensate
695
+ # by increasing the precision. Note that abs_mag in (0, 1) <=>
696
+ # 0.5 < x < 2 and x != 1
697
+ if abs_mag <= 1:
698
+ # Calculate t = x-1 to measure distance from 1 in bits
699
+ tsign = 1-abs_mag
700
+ if tsign:
701
+ tman = (MPZ_ONE<<bc) - man
702
+ else:
703
+ tman = man - (MPZ_ONE<<(bc-1))
704
+ tbc = bitcount(tman)
705
+ cancellation = bc - tbc
706
+ if cancellation > wp:
707
+ t = normalize(tsign, tman, abs_mag-bc, tbc, tbc, 'n')
708
+ return mpf_perturb(t, tsign, prec, rnd)
709
+ else:
710
+ wp += cancellation
711
+ # TODO: if close enough to 1, we could use Taylor series
712
+ # even in the AGM precision range, since the Taylor series
713
+ # converges rapidly
714
+ #------------------------------------------------------------------
715
+ # Another special case:
716
+ # n*log(2) is a good enough approximation
717
+ if abs_mag > 10000:
718
+ if bitcount(abs_mag) > wp:
719
+ return from_man_exp(exp*ln2_fixed(wp), -wp, prec, rnd)
720
+ #------------------------------------------------------------------
721
+ # General case.
722
+ # Perform argument reduction using log(x) = log(x*2^n) - n*log(2):
723
+ # If we are in the Taylor precision range, choose magnitude 0 or 1.
724
+ # If we are in the AGM precision range, choose magnitude -m for
725
+ # some large m; benchmarking on one machine showed m = prec/20 to be
726
+ # optimal between 1000 and 100,000 digits.
727
+ if wp <= LOG_TAYLOR_PREC:
728
+ m = log_taylor_cached(lshift(man, wp-bc), wp)
729
+ if mag:
730
+ m += mag*ln2_fixed(wp)
731
+ else:
732
+ optimal_mag = -wp//LOG_AGM_MAG_PREC_RATIO
733
+ n = optimal_mag - mag
734
+ x = mpf_shift(x, n)
735
+ wp += (-optimal_mag)
736
+ m = -log_agm(to_fixed(x, wp), wp)
737
+ m -= n*ln2_fixed(wp)
738
+ return from_man_exp(m, -wp, prec, rnd)
739
+
740
+ def mpf_log_hypot(a, b, prec, rnd):
741
+ """
742
+ Computes log(sqrt(a^2+b^2)) accurately.
743
+ """
744
+ # If either a or b is inf/nan/0, assume it to be a
745
+ if not b[1]:
746
+ a, b = b, a
747
+ # a is inf/nan/0
748
+ if not a[1]:
749
+ # both are inf/nan/0
750
+ if not b[1]:
751
+ if a == b == fzero:
752
+ return fninf
753
+ if fnan in (a, b):
754
+ return fnan
755
+ # at least one term is (+/- inf)^2
756
+ return finf
757
+ # only a is inf/nan/0
758
+ if a == fzero:
759
+ # log(sqrt(0+b^2)) = log(|b|)
760
+ return mpf_log(mpf_abs(b), prec, rnd)
761
+ if a == fnan:
762
+ return fnan
763
+ return finf
764
+ # Exact
765
+ a2 = mpf_mul(a,a)
766
+ b2 = mpf_mul(b,b)
767
+ extra = 20
768
+ # Not exact
769
+ h2 = mpf_add(a2, b2, prec+extra)
770
+ cancelled = mpf_add(h2, fnone, 10)
771
+ mag_cancelled = cancelled[2]+cancelled[3]
772
+ # Just redo the sum exactly if necessary (could be smarter
773
+ # and avoid memory allocation when a or b is precisely 1
774
+ # and the other is tiny...)
775
+ if cancelled == fzero or mag_cancelled < -extra//2:
776
+ h2 = mpf_add(a2, b2, prec+extra-min(a2[2],b2[2]))
777
+ return mpf_shift(mpf_log(h2, prec, rnd), -1)
778
+
779
+
780
+ #----------------------------------------------------------------------
781
+ # Inverse tangent
782
+ #
783
+
784
+ def atan_newton(x, prec):
785
+ if prec >= 100:
786
+ r = math.atan(int((x>>(prec-53)))/2.0**53)
787
+ else:
788
+ r = math.atan(int(x)/2.0**prec)
789
+ prevp = 50
790
+ r = MPZ(int(r * 2.0**53) >> (53-prevp))
791
+ extra_p = 50
792
+ for wp in giant_steps(prevp, prec):
793
+ wp += extra_p
794
+ r = r << (wp-prevp)
795
+ cos, sin = cos_sin_fixed(r, wp)
796
+ tan = (sin << wp) // cos
797
+ a = ((tan-rshift(x, prec-wp)) << wp) // ((MPZ_ONE<<wp) + ((tan**2)>>wp))
798
+ r = r - a
799
+ prevp = wp
800
+ return rshift(r, prevp-prec)
801
+
802
+ def atan_taylor_get_cached(n, prec):
803
+ # Taylor series with caching wins up to huge precisions
804
+ # To avoid unnecessary precomputation at low precision, we
805
+ # do it in steps
806
+ # Round to next power of 2
807
+ prec2 = (1<<(bitcount(prec-1))) + 20
808
+ dprec = prec2 - prec
809
+ if (n, prec2) in atan_taylor_cache:
810
+ a, atan_a = atan_taylor_cache[n, prec2]
811
+ else:
812
+ a = n << (prec2 - ATAN_TAYLOR_SHIFT)
813
+ atan_a = atan_newton(a, prec2)
814
+ atan_taylor_cache[n, prec2] = (a, atan_a)
815
+ return (a >> dprec), (atan_a >> dprec)
816
+
817
+ def atan_taylor(x, prec):
818
+ n = (x >> (prec-ATAN_TAYLOR_SHIFT))
819
+ a, atan_a = atan_taylor_get_cached(n, prec)
820
+ d = x - a
821
+ s0 = v = (d << prec) // ((a**2 >> prec) + (a*d >> prec) + (MPZ_ONE << prec))
822
+ v2 = (v**2 >> prec)
823
+ v4 = (v2 * v2) >> prec
824
+ s1 = v//3
825
+ v = (v * v4) >> prec
826
+ k = 5
827
+ while v:
828
+ s0 += v // k
829
+ k += 2
830
+ s1 += v // k
831
+ v = (v * v4) >> prec
832
+ k += 2
833
+ s1 = (s1 * v2) >> prec
834
+ s = s0 - s1
835
+ return atan_a + s
836
+
837
+ def atan_inf(sign, prec, rnd):
838
+ if not sign:
839
+ return mpf_shift(mpf_pi(prec, rnd), -1)
840
+ return mpf_neg(mpf_shift(mpf_pi(prec, negative_rnd[rnd]), -1))
841
+
842
+ def mpf_atan(x, prec, rnd=round_fast):
843
+ sign, man, exp, bc = x
844
+ if not man:
845
+ if x == fzero: return fzero
846
+ if x == finf: return atan_inf(0, prec, rnd)
847
+ if x == fninf: return atan_inf(1, prec, rnd)
848
+ return fnan
849
+ mag = exp + bc
850
+ # Essentially infinity
851
+ if mag > prec+20:
852
+ return atan_inf(sign, prec, rnd)
853
+ # Essentially ~ x
854
+ if -mag > prec+20:
855
+ return mpf_perturb(x, 1-sign, prec, rnd)
856
+ wp = prec + 30 + abs(mag)
857
+ # For large x, use atan(x) = pi/2 - atan(1/x)
858
+ if mag >= 2:
859
+ x = mpf_rdiv_int(1, x, wp)
860
+ reciprocal = True
861
+ else:
862
+ reciprocal = False
863
+ t = to_fixed(x, wp)
864
+ if sign:
865
+ t = -t
866
+ if wp < ATAN_TAYLOR_PREC:
867
+ a = atan_taylor(t, wp)
868
+ else:
869
+ a = atan_newton(t, wp)
870
+ if reciprocal:
871
+ a = ((pi_fixed(wp)>>1)+1) - a
872
+ if sign:
873
+ a = -a
874
+ return from_man_exp(a, -wp, prec, rnd)
875
+
876
+ # TODO: cleanup the special cases
877
+ def mpf_atan2(y, x, prec, rnd=round_fast):
878
+ xsign, xman, xexp, xbc = x
879
+ ysign, yman, yexp, ybc = y
880
+ if not yman:
881
+ if y == fzero and x != fnan:
882
+ if mpf_sign(x) >= 0:
883
+ return fzero
884
+ return mpf_pi(prec, rnd)
885
+ if y in (finf, fninf):
886
+ if x in (finf, fninf):
887
+ return fnan
888
+ # pi/2
889
+ if y == finf:
890
+ return mpf_shift(mpf_pi(prec, rnd), -1)
891
+ # -pi/2
892
+ return mpf_neg(mpf_shift(mpf_pi(prec, negative_rnd[rnd]), -1))
893
+ return fnan
894
+ if ysign:
895
+ return mpf_neg(mpf_atan2(mpf_neg(y), x, prec, negative_rnd[rnd]))
896
+ if not xman:
897
+ if x == fnan:
898
+ return fnan
899
+ if x == finf:
900
+ return fzero
901
+ if x == fninf:
902
+ return mpf_pi(prec, rnd)
903
+ if y == fzero:
904
+ return fzero
905
+ return mpf_shift(mpf_pi(prec, rnd), -1)
906
+ tquo = mpf_atan(mpf_div(y, x, prec+4), prec+4)
907
+ if xsign:
908
+ return mpf_add(mpf_pi(prec+4), tquo, prec, rnd)
909
+ else:
910
+ return mpf_pos(tquo, prec, rnd)
911
+
912
+ def mpf_asin(x, prec, rnd=round_fast):
913
+ sign, man, exp, bc = x
914
+ if bc+exp > 0 and x not in (fone, fnone):
915
+ raise ComplexResult("asin(x) is real only for -1 <= x <= 1")
916
+ # asin(x) = 2*atan(x/(1+sqrt(1-x**2)))
917
+ wp = prec + 15
918
+ a = mpf_mul(x, x)
919
+ b = mpf_add(fone, mpf_sqrt(mpf_sub(fone, a, wp), wp), wp)
920
+ c = mpf_div(x, b, wp)
921
+ return mpf_shift(mpf_atan(c, prec, rnd), 1)
922
+
923
+ def mpf_acos(x, prec, rnd=round_fast):
924
+ # acos(x) = 2*atan(sqrt(1-x**2)/(1+x))
925
+ sign, man, exp, bc = x
926
+ if bc + exp > 0:
927
+ if x not in (fone, fnone):
928
+ raise ComplexResult("acos(x) is real only for -1 <= x <= 1")
929
+ if x == fnone:
930
+ return mpf_pi(prec, rnd)
931
+ wp = prec + 15
932
+ a = mpf_mul(x, x)
933
+ b = mpf_sqrt(mpf_sub(fone, a, wp), wp)
934
+ c = mpf_div(b, mpf_add(fone, x, wp), wp)
935
+ return mpf_shift(mpf_atan(c, prec, rnd), 1)
936
+
937
+ def mpf_asinh(x, prec, rnd=round_fast):
938
+ wp = prec + 20
939
+ sign, man, exp, bc = x
940
+ mag = exp+bc
941
+ if mag < -8:
942
+ if mag < -wp:
943
+ return mpf_perturb(x, 1-sign, prec, rnd)
944
+ wp += (-mag)
945
+ # asinh(x) = log(x+sqrt(x**2+1))
946
+ # use reflection symmetry to avoid cancellation
947
+ q = mpf_sqrt(mpf_add(mpf_mul(x, x), fone, wp), wp)
948
+ q = mpf_add(mpf_abs(x), q, wp)
949
+ if sign:
950
+ return mpf_neg(mpf_log(q, prec, negative_rnd[rnd]))
951
+ else:
952
+ return mpf_log(q, prec, rnd)
953
+
954
+ def mpf_acosh(x, prec, rnd=round_fast):
955
+ # acosh(x) = log(x+sqrt(x**2-1))
956
+ wp = prec + 15
957
+ if mpf_cmp(x, fone) == -1:
958
+ raise ComplexResult("acosh(x) is real only for x >= 1")
959
+ q = mpf_sqrt(mpf_add(mpf_mul(x,x), fnone, wp), wp)
960
+ return mpf_log(mpf_add(x, q, wp), prec, rnd)
961
+
962
+ def mpf_atanh(x, prec, rnd=round_fast):
963
+ # atanh(x) = log((1+x)/(1-x))/2
964
+ sign, man, exp, bc = x
965
+ if (not man) and exp:
966
+ if x in (fzero, fnan):
967
+ return x
968
+ raise ComplexResult("atanh(x) is real only for -1 <= x <= 1")
969
+ mag = bc + exp
970
+ if mag > 0:
971
+ if mag == 1 and man == 1:
972
+ return [finf, fninf][sign]
973
+ raise ComplexResult("atanh(x) is real only for -1 <= x <= 1")
974
+ wp = prec + 15
975
+ if mag < -8:
976
+ if mag < -wp:
977
+ return mpf_perturb(x, sign, prec, rnd)
978
+ wp += (-mag)
979
+ a = mpf_add(x, fone, wp)
980
+ b = mpf_sub(fone, x, wp)
981
+ return mpf_shift(mpf_log(mpf_div(a, b, wp), prec, rnd), -1)
982
+
983
+ def mpf_fibonacci(x, prec, rnd=round_fast):
984
+ sign, man, exp, bc = x
985
+ if not man:
986
+ if x == fninf:
987
+ return fnan
988
+ return x
989
+ # F(2^n) ~= 2^(2^n)
990
+ size = abs(exp+bc)
991
+ if exp >= 0:
992
+ # Exact
993
+ if size < 10 or size <= bitcount(prec):
994
+ return from_int(ifib(to_int(x)), prec, rnd)
995
+ # Use the modified Binet formula
996
+ wp = prec + size + 20
997
+ a = mpf_phi(wp)
998
+ b = mpf_add(mpf_shift(a, 1), fnone, wp)
999
+ u = mpf_pow(a, x, wp)
1000
+ v = mpf_cos_pi(x, wp)
1001
+ v = mpf_div(v, u, wp)
1002
+ u = mpf_sub(u, v, wp)
1003
+ u = mpf_div(u, b, prec, rnd)
1004
+ return u
1005
+
1006
+
1007
+ #-------------------------------------------------------------------------------
1008
+ # Exponential-type functions
1009
+ #-------------------------------------------------------------------------------
1010
+
1011
+ def exponential_series(x, prec, type=0):
1012
+ """
1013
+ Taylor series for cosh/sinh or cos/sin.
1014
+
1015
+ type = 0 -- returns exp(x) (slightly faster than cosh+sinh)
1016
+ type = 1 -- returns (cosh(x), sinh(x))
1017
+ type = 2 -- returns (cos(x), sin(x))
1018
+ """
1019
+ if x < 0:
1020
+ x = -x
1021
+ sign = 1
1022
+ else:
1023
+ sign = 0
1024
+ r = int(0.5*prec**0.5)
1025
+ xmag = bitcount(x) - prec
1026
+ r = max(0, xmag + r)
1027
+ extra = 10 + 2*max(r,-xmag)
1028
+ wp = prec + extra
1029
+ x <<= (extra - r)
1030
+ one = MPZ_ONE << wp
1031
+ alt = (type == 2)
1032
+ if prec < EXP_SERIES_U_CUTOFF:
1033
+ x2 = a = (x*x) >> wp
1034
+ x4 = (x2*x2) >> wp
1035
+ s0 = s1 = MPZ_ZERO
1036
+ k = 2
1037
+ while a:
1038
+ a //= (k-1)*k; s0 += a; k += 2
1039
+ a //= (k-1)*k; s1 += a; k += 2
1040
+ a = (a*x4) >> wp
1041
+ s1 = (x2*s1) >> wp
1042
+ if alt:
1043
+ c = s1 - s0 + one
1044
+ else:
1045
+ c = s1 + s0 + one
1046
+ else:
1047
+ u = int(0.3*prec**0.35)
1048
+ x2 = a = (x*x) >> wp
1049
+ xpowers = [one, x2]
1050
+ for i in xrange(1, u):
1051
+ xpowers.append((xpowers[-1]*x2)>>wp)
1052
+ sums = [MPZ_ZERO] * u
1053
+ k = 2
1054
+ while a:
1055
+ for i in xrange(u):
1056
+ a //= (k-1)*k
1057
+ if alt and k & 2: sums[i] -= a
1058
+ else: sums[i] += a
1059
+ k += 2
1060
+ a = (a*xpowers[-1]) >> wp
1061
+ for i in xrange(1, u):
1062
+ sums[i] = (sums[i]*xpowers[i]) >> wp
1063
+ c = sum(sums) + one
1064
+ if type == 0:
1065
+ s = isqrt_fast(c*c - (one<<wp))
1066
+ if sign:
1067
+ v = c - s
1068
+ else:
1069
+ v = c + s
1070
+ for i in xrange(r):
1071
+ v = (v*v) >> wp
1072
+ return v >> extra
1073
+ else:
1074
+ # Repeatedly apply the double-angle formula
1075
+ # cosh(2*x) = 2*cosh(x)^2 - 1
1076
+ # cos(2*x) = 2*cos(x)^2 - 1
1077
+ pshift = wp-1
1078
+ for i in xrange(r):
1079
+ c = ((c*c) >> pshift) - one
1080
+ # With the abs, this is the same for sinh and sin
1081
+ s = isqrt_fast(abs((one<<wp) - c*c))
1082
+ if sign:
1083
+ s = -s
1084
+ return (c>>extra), (s>>extra)
1085
+
1086
+ def exp_basecase(x, prec):
1087
+ """
1088
+ Compute exp(x) as a fixed-point number. Works for any x,
1089
+ but for speed should have |x| < 1. For an arbitrary number,
1090
+ use exp(x) = exp(x-m*log(2)) * 2^m where m = floor(x/log(2)).
1091
+ """
1092
+ if prec > EXP_COSH_CUTOFF:
1093
+ return exponential_series(x, prec, 0)
1094
+ r = int(prec**0.5)
1095
+ prec += r
1096
+ s0 = s1 = (MPZ_ONE << prec)
1097
+ k = 2
1098
+ a = x2 = (x*x) >> prec
1099
+ while a:
1100
+ a //= k; s0 += a; k += 1
1101
+ a //= k; s1 += a; k += 1
1102
+ a = (a*x2) >> prec
1103
+ s1 = (s1*x) >> prec
1104
+ s = s0 + s1
1105
+ u = r
1106
+ while r:
1107
+ s = (s*s) >> prec
1108
+ r -= 1
1109
+ return s >> u
1110
+
1111
+ def exp_expneg_basecase(x, prec):
1112
+ """
1113
+ Computation of exp(x), exp(-x)
1114
+ """
1115
+ if prec > EXP_COSH_CUTOFF:
1116
+ cosh, sinh = exponential_series(x, prec, 1)
1117
+ return cosh+sinh, cosh-sinh
1118
+ a = exp_basecase(x, prec)
1119
+ b = (MPZ_ONE << (prec+prec)) // a
1120
+ return a, b
1121
+
1122
+ def cos_sin_basecase(x, prec):
1123
+ """
1124
+ Compute cos(x), sin(x) as fixed-point numbers, assuming x
1125
+ in [0, pi/2). For an arbitrary number, use x' = x - m*(pi/2)
1126
+ where m = floor(x/(pi/2)) along with quarter-period symmetries.
1127
+ """
1128
+ if prec > COS_SIN_CACHE_PREC:
1129
+ return exponential_series(x, prec, 2)
1130
+ precs = prec - COS_SIN_CACHE_STEP
1131
+ t = x >> precs
1132
+ n = int(t)
1133
+ if n not in cos_sin_cache:
1134
+ w = t<<(10+COS_SIN_CACHE_PREC-COS_SIN_CACHE_STEP)
1135
+ cos_t, sin_t = exponential_series(w, 10+COS_SIN_CACHE_PREC, 2)
1136
+ cos_sin_cache[n] = (cos_t>>10), (sin_t>>10)
1137
+ cos_t, sin_t = cos_sin_cache[n]
1138
+ offset = COS_SIN_CACHE_PREC - prec
1139
+ cos_t >>= offset
1140
+ sin_t >>= offset
1141
+ x -= t << precs
1142
+ cos = MPZ_ONE << prec
1143
+ sin = x
1144
+ k = 2
1145
+ a = -((x*x) >> prec)
1146
+ while a:
1147
+ a //= k; cos += a; k += 1; a = (a*x) >> prec
1148
+ a //= k; sin += a; k += 1; a = -((a*x) >> prec)
1149
+ return ((cos*cos_t-sin*sin_t) >> prec), ((sin*cos_t+cos*sin_t) >> prec)
1150
+
1151
+ def mpf_exp(x, prec, rnd=round_fast):
1152
+ sign, man, exp, bc = x
1153
+ if man:
1154
+ mag = bc + exp
1155
+ wp = prec + 14
1156
+ if sign:
1157
+ man = -man
1158
+ # TODO: the best cutoff depends on both x and the precision.
1159
+ if prec > 600 and exp >= 0:
1160
+ # Need about log2(exp(n)) ~= 1.45*mag extra precision
1161
+ e = mpf_e(wp+int(1.45*mag))
1162
+ return mpf_pow_int(e, man<<exp, prec, rnd)
1163
+ if mag < -wp:
1164
+ return mpf_perturb(fone, sign, prec, rnd)
1165
+ # |x| >= 2
1166
+ if mag > 1:
1167
+ # For large arguments: exp(2^mag*(1+eps)) =
1168
+ # exp(2^mag)*exp(2^mag*eps) = exp(2^mag)*(1 + 2^mag*eps + ...)
1169
+ # so about mag extra bits is required.
1170
+ wpmod = wp + mag
1171
+ offset = exp + wpmod
1172
+ if offset >= 0:
1173
+ t = man << offset
1174
+ else:
1175
+ t = man >> (-offset)
1176
+ lg2 = ln2_fixed(wpmod)
1177
+ n, t = divmod(t, lg2)
1178
+ n = int(n)
1179
+ t >>= mag
1180
+ else:
1181
+ offset = exp + wp
1182
+ if offset >= 0:
1183
+ t = man << offset
1184
+ else:
1185
+ t = man >> (-offset)
1186
+ n = 0
1187
+ man = exp_basecase(t, wp)
1188
+ return from_man_exp(man, n-wp, prec, rnd)
1189
+ if not exp:
1190
+ return fone
1191
+ if x == fninf:
1192
+ return fzero
1193
+ return x
1194
+
1195
+
1196
+ def mpf_cosh_sinh(x, prec, rnd=round_fast, tanh=0):
1197
+ """Simultaneously compute (cosh(x), sinh(x)) for real x"""
1198
+ sign, man, exp, bc = x
1199
+ if (not man) and exp:
1200
+ if tanh:
1201
+ if x == finf: return fone
1202
+ if x == fninf: return fnone
1203
+ return fnan
1204
+ if x == finf: return (finf, finf)
1205
+ if x == fninf: return (finf, fninf)
1206
+ return fnan, fnan
1207
+ mag = exp+bc
1208
+ wp = prec+14
1209
+ if mag < -4:
1210
+ # Extremely close to 0, sinh(x) ~= x and cosh(x) ~= 1
1211
+ if mag < -wp:
1212
+ if tanh:
1213
+ return mpf_perturb(x, 1-sign, prec, rnd)
1214
+ cosh = mpf_perturb(fone, 0, prec, rnd)
1215
+ sinh = mpf_perturb(x, sign, prec, rnd)
1216
+ return cosh, sinh
1217
+ # Fix for cancellation when computing sinh
1218
+ wp += (-mag)
1219
+ # Does exp(-2*x) vanish?
1220
+ if mag > 10:
1221
+ if 3*(1<<(mag-1)) > wp:
1222
+ # XXX: rounding
1223
+ if tanh:
1224
+ return mpf_perturb([fone,fnone][sign], 1-sign, prec, rnd)
1225
+ c = s = mpf_shift(mpf_exp(mpf_abs(x), prec, rnd), -1)
1226
+ if sign:
1227
+ s = mpf_neg(s)
1228
+ return c, s
1229
+ # |x| > 1
1230
+ if mag > 1:
1231
+ wpmod = wp + mag
1232
+ offset = exp + wpmod
1233
+ if offset >= 0:
1234
+ t = man << offset
1235
+ else:
1236
+ t = man >> (-offset)
1237
+ lg2 = ln2_fixed(wpmod)
1238
+ n, t = divmod(t, lg2)
1239
+ n = int(n)
1240
+ t >>= mag
1241
+ else:
1242
+ offset = exp + wp
1243
+ if offset >= 0:
1244
+ t = man << offset
1245
+ else:
1246
+ t = man >> (-offset)
1247
+ n = 0
1248
+ a, b = exp_expneg_basecase(t, wp)
1249
+ # TODO: optimize division precision
1250
+ cosh = a + (b>>(2*n))
1251
+ sinh = a - (b>>(2*n))
1252
+ if sign:
1253
+ sinh = -sinh
1254
+ if tanh:
1255
+ man = (sinh << wp) // cosh
1256
+ return from_man_exp(man, -wp, prec, rnd)
1257
+ else:
1258
+ cosh = from_man_exp(cosh, n-wp-1, prec, rnd)
1259
+ sinh = from_man_exp(sinh, n-wp-1, prec, rnd)
1260
+ return cosh, sinh
1261
+
1262
+
1263
+ def mod_pi2(man, exp, mag, wp):
1264
+ # Reduce to standard interval
1265
+ if mag > 0:
1266
+ i = 0
1267
+ while 1:
1268
+ cancellation_prec = 20 << i
1269
+ wpmod = wp + mag + cancellation_prec
1270
+ pi2 = pi_fixed(wpmod-1)
1271
+ pi4 = pi2 >> 1
1272
+ offset = wpmod + exp
1273
+ if offset >= 0:
1274
+ t = man << offset
1275
+ else:
1276
+ t = man >> (-offset)
1277
+ n, y = divmod(t, pi2)
1278
+ if y > pi4:
1279
+ small = pi2 - y
1280
+ else:
1281
+ small = y
1282
+ if small >> (wp+mag-10):
1283
+ n = int(n)
1284
+ t = y >> mag
1285
+ wp = wpmod - mag
1286
+ break
1287
+ i += 1
1288
+ else:
1289
+ wp += (-mag)
1290
+ offset = exp + wp
1291
+ if offset >= 0:
1292
+ t = man << offset
1293
+ else:
1294
+ t = man >> (-offset)
1295
+ n = 0
1296
+ return t, n, wp
1297
+
1298
+
1299
+ def mpf_cos_sin(x, prec, rnd=round_fast, which=0, pi=False):
1300
+ """
1301
+ which:
1302
+ 0 -- return cos(x), sin(x)
1303
+ 1 -- return cos(x)
1304
+ 2 -- return sin(x)
1305
+ 3 -- return tan(x)
1306
+
1307
+ if pi=True, compute for pi*x
1308
+ """
1309
+ sign, man, exp, bc = x
1310
+ if not man:
1311
+ if exp:
1312
+ c, s = fnan, fnan
1313
+ else:
1314
+ c, s = fone, fzero
1315
+ if which == 0: return c, s
1316
+ if which == 1: return c
1317
+ if which == 2: return s
1318
+ if which == 3: return s
1319
+
1320
+ mag = bc + exp
1321
+ wp = prec + 10
1322
+
1323
+ # Extremely small?
1324
+ if mag < 0:
1325
+ if mag < -wp:
1326
+ if pi:
1327
+ x = mpf_mul(x, mpf_pi(wp))
1328
+ c = mpf_perturb(fone, 1, prec, rnd)
1329
+ s = mpf_perturb(x, 1-sign, prec, rnd)
1330
+ if which == 0: return c, s
1331
+ if which == 1: return c
1332
+ if which == 2: return s
1333
+ if which == 3: return mpf_perturb(x, sign, prec, rnd)
1334
+ if pi:
1335
+ if exp >= -1:
1336
+ if exp == -1:
1337
+ c = fzero
1338
+ s = (fone, fnone)[bool(man & 2) ^ sign]
1339
+ elif exp == 0:
1340
+ c, s = (fnone, fzero)
1341
+ else:
1342
+ c, s = (fone, fzero)
1343
+ if which == 0: return c, s
1344
+ if which == 1: return c
1345
+ if which == 2: return s
1346
+ if which == 3: return mpf_div(s, c, prec, rnd)
1347
+ # Subtract nearest half-integer (= mod by pi/2)
1348
+ n = ((man >> (-exp-2)) + 1) >> 1
1349
+ man = man - (n << (-exp-1))
1350
+ mag2 = bitcount(man) + exp
1351
+ wp = prec + 10 - mag2
1352
+ offset = exp + wp
1353
+ if offset >= 0:
1354
+ t = man << offset
1355
+ else:
1356
+ t = man >> (-offset)
1357
+ t = (t*pi_fixed(wp)) >> wp
1358
+ else:
1359
+ t, n, wp = mod_pi2(man, exp, mag, wp)
1360
+ c, s = cos_sin_basecase(t, wp)
1361
+ m = n & 3
1362
+ if m == 1: c, s = -s, c
1363
+ elif m == 2: c, s = -c, -s
1364
+ elif m == 3: c, s = s, -c
1365
+ if sign:
1366
+ s = -s
1367
+ if which == 0:
1368
+ c = from_man_exp(c, -wp, prec, rnd)
1369
+ s = from_man_exp(s, -wp, prec, rnd)
1370
+ return c, s
1371
+ if which == 1:
1372
+ return from_man_exp(c, -wp, prec, rnd)
1373
+ if which == 2:
1374
+ return from_man_exp(s, -wp, prec, rnd)
1375
+ if which == 3:
1376
+ return from_rational(s, c, prec, rnd)
1377
+
1378
+ def mpf_cos(x, prec, rnd=round_fast): return mpf_cos_sin(x, prec, rnd, 1)
1379
+ def mpf_sin(x, prec, rnd=round_fast): return mpf_cos_sin(x, prec, rnd, 2)
1380
+ def mpf_tan(x, prec, rnd=round_fast): return mpf_cos_sin(x, prec, rnd, 3)
1381
+ def mpf_cos_sin_pi(x, prec, rnd=round_fast): return mpf_cos_sin(x, prec, rnd, 0, 1)
1382
+ def mpf_cos_pi(x, prec, rnd=round_fast): return mpf_cos_sin(x, prec, rnd, 1, 1)
1383
+ def mpf_sin_pi(x, prec, rnd=round_fast): return mpf_cos_sin(x, prec, rnd, 2, 1)
1384
+ def mpf_cosh(x, prec, rnd=round_fast): return mpf_cosh_sinh(x, prec, rnd)[0]
1385
+ def mpf_sinh(x, prec, rnd=round_fast): return mpf_cosh_sinh(x, prec, rnd)[1]
1386
+ def mpf_tanh(x, prec, rnd=round_fast): return mpf_cosh_sinh(x, prec, rnd, tanh=1)
1387
+
1388
+
1389
+ # Low-overhead fixed-point versions
1390
+
1391
+ def cos_sin_fixed(x, prec, pi2=None):
1392
+ if pi2 is None:
1393
+ pi2 = pi_fixed(prec-1)
1394
+ n, t = divmod(x, pi2)
1395
+ n = int(n)
1396
+ c, s = cos_sin_basecase(t, prec)
1397
+ m = n & 3
1398
+ if m == 0: return c, s
1399
+ if m == 1: return -s, c
1400
+ if m == 2: return -c, -s
1401
+ if m == 3: return s, -c
1402
+
1403
+ def exp_fixed(x, prec, ln2=None):
1404
+ if ln2 is None:
1405
+ ln2 = ln2_fixed(prec)
1406
+ n, t = divmod(x, ln2)
1407
+ n = int(n)
1408
+ v = exp_basecase(t, prec)
1409
+ if n >= 0:
1410
+ return v << n
1411
+ else:
1412
+ return v >> (-n)
1413
+
1414
+
1415
+ if BACKEND == 'sage':
1416
+ try:
1417
+ import sage.libs.mpmath.ext_libmp as _lbmp
1418
+ mpf_sqrt = _lbmp.mpf_sqrt
1419
+ mpf_exp = _lbmp.mpf_exp
1420
+ mpf_log = _lbmp.mpf_log
1421
+ mpf_cos = _lbmp.mpf_cos
1422
+ mpf_sin = _lbmp.mpf_sin
1423
+ mpf_pow = _lbmp.mpf_pow
1424
+ exp_fixed = _lbmp.exp_fixed
1425
+ cos_sin_fixed = _lbmp.cos_sin_fixed
1426
+ log_int_fixed = _lbmp.log_int_fixed
1427
+ except (ImportError, AttributeError):
1428
+ print("Warning: Sage imports in libelefun failed")