@@ -6,6 +6,8 @@ from flint.flintlib.types.flint cimport (
66)
77from flint.utils.conversion cimport prec_to_dps, dps_to_prec
88
9+ from functools import wraps
10+
911cdef class FlintContext:
1012 def __init__ (self ):
1113 self .default()
@@ -57,6 +59,88 @@ cdef class FlintContext:
5759 assert num >= 1 and num <= 64
5860 flint_set_num_threads(num)
5961
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+
60144 def __repr__ (self ):
61145 return " pretty = %-8s # pretty-print repr() output\n " \
62146 " unicode = %-8s # use unicode characters in output\n " \
@@ -69,4 +153,51 @@ cdef class FlintContext:
69153 def cleanup (self ):
70154 flint_cleanup()
71155
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+
72203cdef FlintContext thectx = FlintContext()
0 commit comments