@@ -6,6 +6,8 @@ from flint.flintlib.types.flint cimport (
6
6
)
7
7
from flint.utils.conversion cimport prec_to_dps, dps_to_prec
8
8
9
+ from functools import wraps
10
+
9
11
cdef class FlintContext:
10
12
def __init__ (self ):
11
13
self .default()
@@ -57,6 +59,88 @@ cdef class FlintContext:
57
59
assert num >= 1 and num <= 64
58
60
flint_set_num_threads(num)
59
61
62
+ def extraprec (self , n ):
63
+ """
64
+ Adds n bits of precision to the current flint context.
65
+
66
+ >>> from flint import arb, ctx
67
+ >>> with ctx.extraprec(5): x = arb(2).sqrt().str()
68
+ >>> x
69
+ '[1.414213562373095 +/- 5.53e-17]'
70
+
71
+ This function also works as a wrapper:
72
+
73
+ >>> from flint import arb, ctx
74
+ >>> @ctx.extraprec(10)
75
+ ... def f(x):
76
+ ... return x.sqrt().str()
77
+ >>> f(arb(2))
78
+ '[1.41421356237309505 +/- 1.46e-18]'
79
+ """
80
+ return self .workprec(n + self .prec)
81
+
82
+ def extradps (self , n ):
83
+ """
84
+ Adds n digits of precision to the current flint context.
85
+
86
+ >>> from flint import arb, ctx
87
+ >>> with ctx.extradps(5): x = arb(2).sqrt().str()
88
+ >>> x
89
+ '[1.4142135623730950488 +/- 2.76e-21]'
90
+
91
+ This function also works as a wrapper:
92
+
93
+ >>> from flint import arb, ctx
94
+ >>> @ctx.extradps(10)
95
+ ... def f(x):
96
+ ... return x.sqrt().str()
97
+ >>> f(arb(2))
98
+ '[1.414213562373095048801689 +/- 3.13e-25]'
99
+ """
100
+ return self .workdps(n + self .dps)
101
+
102
+ def workprec (self , n ):
103
+ """
104
+ Sets the working precision for the current flint context,
105
+ using a python context manager.
106
+
107
+ >>> from flint import arb, ctx
108
+ >>> with ctx.workprec(5): x = arb(2).sqrt().str()
109
+ >>> x
110
+ '[1e+0 +/- 0.438]'
111
+
112
+ This function also works as a wrapper:
113
+
114
+ >>> from flint import arb, ctx
115
+ >>> @ctx.workprec(24)
116
+ ... def f(x):
117
+ ... return x.sqrt().str()
118
+ >>> f(arb(2))
119
+ '[1.41421 +/- 3.66e-6]'
120
+ """
121
+ return PrecisionManager(self , eprec = n)
122
+
123
+ def workdps (self , n ):
124
+ """
125
+ Sets the working precision in digits for the current
126
+ flint context, using a python context manager.
127
+
128
+ >>> from flint import arb, ctx
129
+ >>> with ctx.workdps(5): x = arb(2).sqrt().str()
130
+ >>> x
131
+ '[1.4142 +/- 1.51e-5]'
132
+
133
+ This function also works as a wrapper:
134
+
135
+ >>> from flint import arb, ctx
136
+ >>> @ctx.workdps(10)
137
+ ... def f(x):
138
+ ... return x.sqrt().str()
139
+ >>> f(arb(2))
140
+ '[1.414213562 +/- 3.85e-10]'
141
+ """
142
+ return PrecisionManager(self , edps = n)
143
+
60
144
def __repr__ (self ):
61
145
return " pretty = %-8s # pretty-print repr() output\n " \
62
146
" unicode = %-8s # use unicode characters in output\n " \
@@ -69,4 +153,51 @@ cdef class FlintContext:
69
153
def cleanup (self ):
70
154
flint_cleanup()
71
155
156
+
157
+ cdef class PrecisionManager:
158
+ cdef FlintContext ctx
159
+ cdef int eprec
160
+ cdef int edps
161
+ cdef int _oldprec
162
+
163
+ def __init__ (self , ctx , eprec = - 1 , edps = - 1 ):
164
+ if eprec != - 1 and edps != - 1 :
165
+ raise ValueError (" two different precisions requested" )
166
+
167
+ self .ctx = ctx
168
+
169
+ self .eprec = eprec
170
+ self .edps = edps
171
+
172
+ def __call__ (self , func ):
173
+ @ wraps (func)
174
+ def wrapped (*args , **kwargs ):
175
+ _oldprec = self .ctx.prec
176
+
177
+ try :
178
+ if self .eprec != - 1 :
179
+ self .ctx.prec = self .eprec
180
+
181
+ if self .edps != - 1 :
182
+ self .ctx.dps = self .edps
183
+
184
+ return func(* args, ** kwargs)
185
+ finally :
186
+ self .ctx.prec = _oldprec
187
+
188
+ return wrapped
189
+
190
+ def __enter__ (self ):
191
+ self ._oldprec = self .ctx.prec
192
+
193
+ if self .eprec != - 1 :
194
+ self .ctx.prec = self .eprec
195
+
196
+ if self .edps != - 1 :
197
+ self .ctx.dps = self .edps
198
+
199
+ def __exit__ (self , type , value , traceback ):
200
+ self .ctx.prec = self ._oldprec
201
+
202
+
72
203
cdef FlintContext thectx = FlintContext()
0 commit comments