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