Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/libs/mpmath/utils.pyx
4045 views
1
# Utilities for Sage-mpmath interaction
2
# Also patches some mpmath functions for speed
3
4
include "../../ext/stdsage.pxi"
5
6
from sage.rings.integer cimport Integer
7
from sage.rings.real_mpfr cimport RealNumber
8
from sage.rings.complex_number cimport ComplexNumber
9
from sage.structure.element cimport Element
10
11
import sage.all
12
13
from sage.libs.mpfr cimport *
14
from sage.libs.gmp.all cimport *
15
16
from sage.rings.complex_field import ComplexField
17
from sage.rings.real_mpfr import RealField
18
19
cpdef int bitcount(n):
20
"""
21
Bitcount of a Sage Integer or Python int/long.
22
23
EXAMPLES::
24
25
sage: from mpmath.libmp import bitcount
26
sage: bitcount(0)
27
0
28
sage: bitcount(1)
29
1
30
sage: bitcount(100)
31
7
32
sage: bitcount(-100)
33
7
34
sage: bitcount(2r)
35
2
36
sage: bitcount(2L)
37
2
38
39
"""
40
cdef Integer m
41
if PY_TYPE_CHECK(n, Integer):
42
m = <Integer>n
43
else:
44
m = Integer(n)
45
if mpz_sgn(m.value) == 0:
46
return 0
47
return mpz_sizeinbase(m.value, 2)
48
49
cpdef isqrt(n):
50
"""
51
Square root (rounded to floor) of a Sage Integer or Python int/long.
52
The result is a Sage Integer.
53
54
EXAMPLES::
55
56
sage: from mpmath.libmp import isqrt
57
sage: isqrt(0)
58
0
59
sage: isqrt(100)
60
10
61
sage: isqrt(10)
62
3
63
sage: isqrt(10r)
64
3
65
sage: isqrt(10L)
66
3
67
68
"""
69
cdef Integer m, y
70
if PY_TYPE_CHECK(n, Integer):
71
m = <Integer>n
72
else:
73
m = Integer(n)
74
if mpz_sgn(m.value) < 0:
75
raise ValueError, "square root of negative integer not defined."
76
y = PY_NEW(Integer)
77
mpz_sqrt(y.value, m.value)
78
return y
79
80
cpdef from_man_exp(man, exp, long prec = 0, str rnd = 'd'):
81
"""
82
Create normalized mpf value tuple from mantissa and exponent.
83
With prec > 0, rounds the result in the desired direction
84
if necessary.
85
86
EXAMPLES::
87
88
sage: from mpmath.libmp import from_man_exp
89
sage: from_man_exp(-6, -1)
90
(1, 3, 0, 2)
91
sage: from_man_exp(-6, -1, 1, 'd')
92
(1, 1, 1, 1)
93
sage: from_man_exp(-6, -1, 1, 'u')
94
(1, 1, 2, 1)
95
"""
96
cdef Integer res
97
cdef long bc
98
res = Integer(man)
99
bc = mpz_sizeinbase(res.value, 2)
100
if not prec:
101
prec = bc
102
if mpz_sgn(res.value) < 0:
103
mpz_neg(res.value, res.value)
104
return normalize(1, res, exp, bc, prec, rnd)
105
else:
106
return normalize(0, res, exp, bc, prec, rnd)
107
108
cpdef normalize(long sign, Integer man, exp, long bc, long prec, str rnd):
109
"""
110
Create normalized mpf value tuple from full list of components.
111
112
EXAMPLES::
113
114
sage: from mpmath.libmp import normalize
115
sage: normalize(0, 4, 5, 3, 53, 'n')
116
(0, 1, 7, 1)
117
"""
118
cdef long shift
119
cdef Integer res
120
cdef unsigned long trail
121
if mpz_sgn(man.value) == 0:
122
from mpmath.libmp import fzero
123
return fzero
124
if bc <= prec and mpz_odd_p(man.value):
125
return (sign, man, exp, bc)
126
shift = bc - prec
127
res = PY_NEW(Integer)
128
if shift > 0:
129
if rnd == 'n':
130
if mpz_tstbit(man.value, shift-1) and (mpz_tstbit(man.value, shift)\
131
or (mpz_scan1(man.value, 0) < (shift-1))):
132
mpz_cdiv_q_2exp(res.value, man.value, shift)
133
else:
134
mpz_fdiv_q_2exp(res.value, man.value, shift)
135
elif rnd == 'd':
136
mpz_fdiv_q_2exp(res.value, man.value, shift)
137
elif rnd == 'f':
138
if sign: mpz_cdiv_q_2exp(res.value, man.value, shift)
139
else: mpz_fdiv_q_2exp(res.value, man.value, shift)
140
elif rnd == 'c':
141
if sign: mpz_fdiv_q_2exp(res.value, man.value, shift)
142
else: mpz_cdiv_q_2exp(res.value, man.value, shift)
143
elif rnd == 'u':
144
mpz_cdiv_q_2exp(res.value, man.value, shift)
145
exp += shift
146
else:
147
mpz_set(res.value, man.value)
148
# Strip trailing bits
149
trail = mpz_scan1(res.value, 0)
150
if 0 < trail < bc:
151
mpz_tdiv_q_2exp(res.value, res.value, trail)
152
exp += trail
153
bc = mpz_sizeinbase(res.value, 2)
154
return (sign, res, int(exp), bc)
155
156
cdef mpfr_from_mpfval(mpfr_t res, tuple x):
157
"""
158
Set value of an MPFR number (in place) to that of a given mpmath mpf
159
data tuple.
160
"""
161
cdef int sign
162
cdef Integer man
163
cdef long exp
164
cdef long bc
165
sign, man, exp, bc = x
166
if man.__nonzero__():
167
mpfr_set_z(res, man.value, GMP_RNDZ)
168
if sign:
169
mpfr_neg(res, res, GMP_RNDZ)
170
mpfr_mul_2si(res, res, exp, GMP_RNDZ)
171
return
172
from mpmath.libmp import finf, fninf
173
if exp == 0:
174
mpfr_set_ui(res, 0, GMP_RNDZ)
175
elif x == finf:
176
mpfr_set_inf(res, 1)
177
elif x == fninf:
178
mpfr_set_inf(res, -1)
179
else:
180
mpfr_set_nan(res)
181
182
cdef mpfr_to_mpfval(mpfr_t value):
183
"""
184
Given an MPFR value, return an mpmath mpf data tuple representing
185
the same number.
186
"""
187
if mpfr_nan_p(value):
188
from mpmath.libmp import fnan
189
return fnan
190
if mpfr_inf_p(value):
191
from mpmath.libmp import finf, fninf
192
if mpfr_sgn(value) > 0:
193
return finf
194
else:
195
return fninf
196
if mpfr_sgn(value) == 0:
197
from mpmath.libmp import fzero
198
return fzero
199
sign = 0
200
cdef Integer man = PY_NEW(Integer)
201
exp = mpfr_get_z_exp(man.value, value)
202
if mpz_sgn(man.value) < 0:
203
mpz_neg(man.value, man.value)
204
sign = 1
205
cdef unsigned long trailing
206
trailing = mpz_scan1(man.value, 0)
207
if trailing:
208
mpz_tdiv_q_2exp(man.value, man.value, trailing)
209
exp += trailing
210
bc = mpz_sizeinbase(man.value, 2)
211
return (sign, man, int(exp), bc)
212
213
def mpmath_to_sage(x, prec):
214
"""
215
Convert any mpmath number (mpf or mpc) to a Sage RealNumber or
216
ComplexNumber of the given precision.
217
218
EXAMPLES::
219
220
sage: import sage.libs.mpmath.all as a
221
sage: a.mpmath_to_sage(a.mpf('2.5'), 53)
222
2.50000000000000
223
sage: a.mpmath_to_sage(a.mpc('2.5','-3.5'), 53)
224
2.50000000000000 - 3.50000000000000*I
225
sage: a.mpmath_to_sage(a.mpf('inf'), 53)
226
+infinity
227
sage: a.mpmath_to_sage(a.mpf('-inf'), 53)
228
-infinity
229
sage: a.mpmath_to_sage(a.mpf('nan'), 53)
230
NaN
231
sage: a.mpmath_to_sage(a.mpf('0'), 53)
232
0.000000000000000
233
234
A real example::
235
236
sage: RealField(100)(pi)
237
3.1415926535897932384626433833
238
sage: t = RealField(100)(pi)._mpmath_(); t
239
mpf('3.1415926535897932')
240
sage: a.mpmath_to_sage(t, 100)
241
3.1415926535897932384626433833
242
243
We can ask for more precision, but the result is undefined::
244
245
sage: a.mpmath_to_sage(t, 140) # random
246
3.1415926535897932384626433832793333156440
247
sage: ComplexField(140)(pi)
248
3.1415926535897932384626433832795028841972
249
250
A complex example::
251
252
sage: ComplexField(100)([0, pi])
253
3.1415926535897932384626433833*I
254
sage: t = ComplexField(100)([0, pi])._mpmath_(); t
255
mpc(real='0.0', imag='3.1415926535897932')
256
sage: sage.libs.mpmath.all.mpmath_to_sage(t, 100)
257
3.1415926535897932384626433833*I
258
259
Again, we can ask for more precision, but the result is undefined::
260
261
sage: sage.libs.mpmath.all.mpmath_to_sage(t, 140) # random
262
3.1415926535897932384626433832793333156440*I
263
sage: ComplexField(140)([0, pi])
264
3.1415926535897932384626433832795028841972*I
265
"""
266
cdef RealNumber y
267
cdef ComplexNumber z
268
if hasattr(x, "_mpf_"):
269
y = RealField(prec)()
270
mpfr_from_mpfval(y.value, x._mpf_)
271
return y
272
elif hasattr(x, "_mpc_"):
273
z = ComplexField(prec)(0)
274
re, im = x._mpc_
275
mpfr_from_mpfval(z.__re, re)
276
mpfr_from_mpfval(z.__im, im)
277
return z
278
else:
279
raise TypeError("cannot convert %r to Sage", x)
280
281
def sage_to_mpmath(x, prec):
282
"""
283
Convert any Sage number that can be coerced into a RealNumber
284
or ComplexNumber of the given precision into an mpmath mpf or mpc.
285
Integers are currently converted to int.
286
287
Lists, tuples and dicts passed as input are converted
288
recursively.
289
290
EXAMPLES::
291
292
sage: import sage.libs.mpmath.all as a
293
sage: a.mp.dps = 15
294
sage: print a.sage_to_mpmath(2/3, 53)
295
0.666666666666667
296
sage: print a.sage_to_mpmath(2./3, 53)
297
0.666666666666667
298
sage: print a.sage_to_mpmath(3+4*I, 53)
299
(3.0 + 4.0j)
300
sage: print a.sage_to_mpmath(1+pi, 53)
301
4.14159265358979
302
sage: a.sage_to_mpmath(infinity, 53)
303
mpf('+inf')
304
sage: a.sage_to_mpmath(-infinity, 53)
305
mpf('-inf')
306
sage: a.sage_to_mpmath(NaN, 53)
307
mpf('nan')
308
sage: a.sage_to_mpmath(0, 53)
309
0
310
sage: a.sage_to_mpmath([0.5, 1.5], 53)
311
[mpf('0.5'), mpf('1.5')]
312
sage: a.sage_to_mpmath((0.5, 1.5), 53)
313
(mpf('0.5'), mpf('1.5'))
314
sage: a.sage_to_mpmath({'n':0.5}, 53)
315
{'n': mpf('0.5')}
316
317
"""
318
cdef RealNumber y
319
if isinstance(x, Element):
320
if PY_TYPE_CHECK(x, Integer):
321
return int(<Integer>x)
322
try:
323
if PY_TYPE_CHECK(x, RealNumber):
324
return x._mpmath_()
325
else:
326
x = RealField(prec)(x)
327
return x._mpmath_()
328
except TypeError:
329
if PY_TYPE_CHECK(x, ComplexNumber):
330
return x._mpmath_()
331
else:
332
x = ComplexField(prec)(x)
333
return x._mpmath_()
334
if PY_TYPE_CHECK(x, tuple) or PY_TYPE_CHECK(x, list):
335
return type(x)([sage_to_mpmath(v, prec) for v in x])
336
if PY_TYPE_CHECK(x, dict):
337
return dict([(k, sage_to_mpmath(v, prec)) for (k, v) in x.items()])
338
return x
339
340
def call(func, *args, **kwargs):
341
"""
342
Call an mpmath function with Sage objects as inputs and
343
convert the result back to a Sage real or complex number.
344
345
By default, a RealNumber or ComplexNumber with the current
346
working precision of mpmath (mpmath.mp.prec) will be returned.
347
348
If prec=n is passed among the keyword arguments, the temporary
349
working precision will be set to n and the result will also
350
have this precision.
351
352
If parent=P is passed, P.prec() will be used as working
353
precision and the result will be coerced to P (or the
354
corresponding complex field if necessary).
355
356
Arguments should be Sage objects that can be coerced into RealField
357
or ComplexField elements. Arguments may also be tuples, lists or
358
dicts (which are converted recursively), or any type that mpmath
359
understands natively (e.g. Python floats, strings for options).
360
361
EXAMPLES::
362
363
sage: import sage.libs.mpmath.all as a
364
sage: a.mp.prec = 53
365
sage: a.call(a.erf, 3+4*I)
366
-120.186991395079 - 27.7503372936239*I
367
sage: a.call(a.polylog, 2, 1/3+4/5*I)
368
0.153548951541433 + 0.875114412499637*I
369
sage: a.call(a.barnesg, 3+4*I)
370
-0.000676375932234244 - 0.0000442236140124728*I
371
sage: a.call(a.barnesg, -4)
372
0.000000000000000
373
sage: a.call(a.hyper, [2,3], [4,5], 1/3)
374
1.10703578162508
375
sage: a.call(a.hyper, [2,3], [4,(2,3)], 1/3)
376
1.95762943509305
377
sage: a.call(a.quad, a.erf, [0,1])
378
0.486064958112256
379
sage: a.call(a.gammainc, 3+4*I, 2/3, 1-pi*I, prec=100)
380
-274.18871130777160922270612331 + 101.59521032382593402947725236*I
381
sage: x = (3+4*I).n(100)
382
sage: y = (2/3).n(100)
383
sage: z = (1-pi*I).n(100)
384
sage: a.call(a.gammainc, x, y, z, prec=100)
385
-274.18871130777160922270612331 + 101.59521032382593402947725236*I
386
sage: a.call(a.erf, infinity)
387
1.00000000000000
388
sage: a.call(a.erf, -infinity)
389
-1.00000000000000
390
sage: a.call(a.gamma, infinity)
391
+infinity
392
sage: a.call(a.polylog, 2, 1/2, parent=RR)
393
0.582240526465012
394
sage: a.call(a.polylog, 2, 2, parent=RR)
395
2.46740110027234 - 2.17758609030360*I
396
sage: a.call(a.polylog, 2, 1/2, parent=RealField(100))
397
0.58224052646501250590265632016
398
sage: a.call(a.polylog, 2, 2, parent=RealField(100))
399
2.4674011002723396547086227500 - 2.1775860903036021305006888982*I
400
sage: a.call(a.polylog, 2, 1/2, parent=CC)
401
0.582240526465012
402
sage: type(_)
403
<type 'sage.rings.complex_number.ComplexNumber'>
404
sage: a.call(a.polylog, 2, 1/2, parent=RDF)
405
0.582240526465
406
sage: type(_)
407
<type 'sage.rings.real_double.RealDoubleElement'>
408
409
Check that Trac 11885 is fixed::
410
411
sage: a.call(a.ei, 1.0r, parent=float)
412
1.8951178163559366
413
414
"""
415
from mpmath import mp
416
orig = mp.prec
417
prec = kwargs.pop('prec', orig)
418
parent = kwargs.pop('parent', None)
419
if parent is not None:
420
try:
421
prec = parent.prec()
422
except AttributeError:
423
pass
424
prec2 = prec + 20
425
args = sage_to_mpmath(args, prec2)
426
kwargs = sage_to_mpmath(kwargs, prec2)
427
try:
428
mp.prec = prec
429
y = func(*args, **kwargs)
430
finally:
431
mp.prec = orig
432
y = mpmath_to_sage(y, prec)
433
if parent is None:
434
return y
435
try:
436
return parent(y)
437
except TypeError:
438
return parent.complex_field()(y)
439
440
441