Coverage for /usr/lib/python3/dist-packages/mpmath/ctx_fp.py: 55%

198 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1from .ctx_base import StandardBaseContext 

2 

3import math 

4import cmath 

5from . import math2 

6 

7from . import function_docs 

8 

9from .libmp import mpf_bernoulli, to_float, int_types 

10from . import libmp 

11 

12class FPContext(StandardBaseContext): 

13 """ 

14 Context for fast low-precision arithmetic (53-bit precision, giving at most 

15 about 15-digit accuracy), using Python's builtin float and complex. 

16 """ 

17 

18 def __init__(ctx): 

19 StandardBaseContext.__init__(ctx) 

20 

21 # Override SpecialFunctions implementation 

22 ctx.loggamma = math2.loggamma 

23 ctx._bernoulli_cache = {} 

24 ctx.pretty = False 

25 

26 ctx._init_aliases() 

27 

28 _mpq = lambda cls, x: float(x[0])/x[1] 

29 

30 NoConvergence = libmp.NoConvergence 

31 

32 def _get_prec(ctx): return 53 

33 def _set_prec(ctx, p): return 

34 def _get_dps(ctx): return 15 

35 def _set_dps(ctx, p): return 

36 

37 _fixed_precision = True 

38 

39 prec = property(_get_prec, _set_prec) 

40 dps = property(_get_dps, _set_dps) 

41 

42 zero = 0.0 

43 one = 1.0 

44 eps = math2.EPS 

45 inf = math2.INF 

46 ninf = math2.NINF 

47 nan = math2.NAN 

48 j = 1j 

49 

50 # Called by SpecialFunctions.__init__() 

51 @classmethod 

52 def _wrap_specfun(cls, name, f, wrap): 

53 if wrap: 

54 def f_wrapped(ctx, *args, **kwargs): 

55 convert = ctx.convert 

56 args = [convert(a) for a in args] 

57 return f(ctx, *args, **kwargs) 

58 else: 

59 f_wrapped = f 

60 f_wrapped.__doc__ = function_docs.__dict__.get(name, f.__doc__) 

61 setattr(cls, name, f_wrapped) 

62 

63 def bernoulli(ctx, n): 

64 cache = ctx._bernoulli_cache 

65 if n in cache: 

66 return cache[n] 

67 cache[n] = to_float(mpf_bernoulli(n, 53, 'n'), strict=True) 

68 return cache[n] 

69 

70 pi = math2.pi 

71 e = math2.e 

72 euler = math2.euler 

73 sqrt2 = 1.4142135623730950488 

74 sqrt5 = 2.2360679774997896964 

75 phi = 1.6180339887498948482 

76 ln2 = 0.69314718055994530942 

77 ln10 = 2.302585092994045684 

78 euler = 0.57721566490153286061 

79 catalan = 0.91596559417721901505 

80 khinchin = 2.6854520010653064453 

81 apery = 1.2020569031595942854 

82 glaisher = 1.2824271291006226369 

83 

84 absmin = absmax = abs 

85 

86 def is_special(ctx, x): 

87 return x - x != 0.0 

88 

89 def isnan(ctx, x): 

90 return x != x 

91 

92 def isinf(ctx, x): 

93 return abs(x) == math2.INF 

94 

95 def isnormal(ctx, x): 

96 if x: 

97 return x - x == 0.0 

98 return False 

99 

100 def isnpint(ctx, x): 

101 if type(x) is complex: 

102 if x.imag: 

103 return False 

104 x = x.real 

105 return x <= 0.0 and round(x) == x 

106 

107 mpf = float 

108 mpc = complex 

109 

110 def convert(ctx, x): 

111 try: 

112 return float(x) 

113 except: 

114 return complex(x) 

115 

116 power = staticmethod(math2.pow) 

117 sqrt = staticmethod(math2.sqrt) 

118 exp = staticmethod(math2.exp) 

119 ln = log = staticmethod(math2.log) 

120 cos = staticmethod(math2.cos) 

121 sin = staticmethod(math2.sin) 

122 tan = staticmethod(math2.tan) 

123 cos_sin = staticmethod(math2.cos_sin) 

124 acos = staticmethod(math2.acos) 

125 asin = staticmethod(math2.asin) 

126 atan = staticmethod(math2.atan) 

127 cosh = staticmethod(math2.cosh) 

128 sinh = staticmethod(math2.sinh) 

129 tanh = staticmethod(math2.tanh) 

130 gamma = staticmethod(math2.gamma) 

131 rgamma = staticmethod(math2.rgamma) 

132 fac = factorial = staticmethod(math2.factorial) 

133 floor = staticmethod(math2.floor) 

134 ceil = staticmethod(math2.ceil) 

135 cospi = staticmethod(math2.cospi) 

136 sinpi = staticmethod(math2.sinpi) 

137 cbrt = staticmethod(math2.cbrt) 

138 _nthroot = staticmethod(math2.nthroot) 

139 _ei = staticmethod(math2.ei) 

140 _e1 = staticmethod(math2.e1) 

141 _zeta = _zeta_int = staticmethod(math2.zeta) 

142 

143 # XXX: math2 

144 def arg(ctx, z): 

145 z = complex(z) 

146 return math.atan2(z.imag, z.real) 

147 

148 def expj(ctx, x): 

149 return ctx.exp(ctx.j*x) 

150 

151 def expjpi(ctx, x): 

152 return ctx.exp(ctx.j*ctx.pi*x) 

153 

154 ldexp = math.ldexp 

155 frexp = math.frexp 

156 

157 def mag(ctx, z): 

158 if z: 

159 return ctx.frexp(abs(z))[1] 

160 return ctx.ninf 

161 

162 def isint(ctx, z): 

163 if hasattr(z, "imag"): # float/int don't have .real/.imag in py2.5 

164 if z.imag: 

165 return False 

166 z = z.real 

167 try: 

168 return z == int(z) 

169 except: 

170 return False 

171 

172 def nint_distance(ctx, z): 

173 if hasattr(z, "imag"): # float/int don't have .real/.imag in py2.5 

174 n = round(z.real) 

175 else: 

176 n = round(z) 

177 if n == z: 

178 return n, ctx.ninf 

179 return n, ctx.mag(abs(z-n)) 

180 

181 def _convert_param(ctx, z): 

182 if type(z) is tuple: 

183 p, q = z 

184 return ctx.mpf(p) / q, 'R' 

185 if hasattr(z, "imag"): # float/int don't have .real/.imag in py2.5 

186 intz = int(z.real) 

187 else: 

188 intz = int(z) 

189 if z == intz: 

190 return intz, 'Z' 

191 return z, 'R' 

192 

193 def _is_real_type(ctx, z): 

194 return isinstance(z, float) or isinstance(z, int_types) 

195 

196 def _is_complex_type(ctx, z): 

197 return isinstance(z, complex) 

198 

199 def hypsum(ctx, p, q, types, coeffs, z, maxterms=6000, **kwargs): 

200 coeffs = list(coeffs) 

201 num = range(p) 

202 den = range(p,p+q) 

203 tol = ctx.eps 

204 s = t = 1.0 

205 k = 0 

206 while 1: 

207 for i in num: t *= (coeffs[i]+k) 

208 for i in den: t /= (coeffs[i]+k) 

209 k += 1; t /= k; t *= z; s += t 

210 if abs(t) < tol: 

211 return s 

212 if k > maxterms: 

213 raise ctx.NoConvergence 

214 

215 def atan2(ctx, x, y): 

216 return math.atan2(x, y) 

217 

218 def psi(ctx, m, z): 

219 m = int(m) 

220 if m == 0: 

221 return ctx.digamma(z) 

222 return (-1)**(m+1) * ctx.fac(m) * ctx.zeta(m+1, z) 

223 

224 digamma = staticmethod(math2.digamma) 

225 

226 def harmonic(ctx, x): 

227 x = ctx.convert(x) 

228 if x == 0 or x == 1: 

229 return x 

230 return ctx.digamma(x+1) + ctx.euler 

231 

232 nstr = str 

233 

234 def to_fixed(ctx, x, prec): 

235 return int(math.ldexp(x, prec)) 

236 

237 def rand(ctx): 

238 import random 

239 return random.random() 

240 

241 _erf = staticmethod(math2.erf) 

242 _erfc = staticmethod(math2.erfc) 

243 

244 def sum_accurately(ctx, terms, check_step=1): 

245 s = ctx.zero 

246 k = 0 

247 for term in terms(): 

248 s += term 

249 if (not k % check_step) and term: 

250 if abs(term) <= 1e-18*abs(s): 

251 break 

252 k += 1 

253 return s