Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2Machine arithmetics - determine the parameters of the 

3floating-point arithmetic system 

4 

5Author: Pearu Peterson, September 2003 

6 

7""" 

8__all__ = ['MachAr'] 

9 

10from numpy.core.fromnumeric import any 

11from numpy.core._ufunc_config import errstate 

12from numpy.core.overrides import set_module 

13 

14# Need to speed this up...especially for longfloat 

15 

16@set_module('numpy') 

17class MachAr: 

18 """ 

19 Diagnosing machine parameters. 

20 

21 Attributes 

22 ---------- 

23 ibeta : int 

24 Radix in which numbers are represented. 

25 it : int 

26 Number of base-`ibeta` digits in the floating point mantissa M. 

27 machep : int 

28 Exponent of the smallest (most negative) power of `ibeta` that, 

29 added to 1.0, gives something different from 1.0 

30 eps : float 

31 Floating-point number ``beta**machep`` (floating point precision) 

32 negep : int 

33 Exponent of the smallest power of `ibeta` that, subtracted 

34 from 1.0, gives something different from 1.0. 

35 epsneg : float 

36 Floating-point number ``beta**negep``. 

37 iexp : int 

38 Number of bits in the exponent (including its sign and bias). 

39 minexp : int 

40 Smallest (most negative) power of `ibeta` consistent with there 

41 being no leading zeros in the mantissa. 

42 xmin : float 

43 Floating point number ``beta**minexp`` (the smallest [in 

44 magnitude] usable floating value). 

45 maxexp : int 

46 Smallest (positive) power of `ibeta` that causes overflow. 

47 xmax : float 

48 ``(1-epsneg) * beta**maxexp`` (the largest [in magnitude] 

49 usable floating value). 

50 irnd : int 

51 In ``range(6)``, information on what kind of rounding is done 

52 in addition, and on how underflow is handled. 

53 ngrd : int 

54 Number of 'guard digits' used when truncating the product 

55 of two mantissas to fit the representation. 

56 epsilon : float 

57 Same as `eps`. 

58 tiny : float 

59 Same as `xmin`. 

60 huge : float 

61 Same as `xmax`. 

62 precision : float 

63 ``- int(-log10(eps))`` 

64 resolution : float 

65 ``- 10**(-precision)`` 

66 

67 Parameters 

68 ---------- 

69 float_conv : function, optional 

70 Function that converts an integer or integer array to a float 

71 or float array. Default is `float`. 

72 int_conv : function, optional 

73 Function that converts a float or float array to an integer or 

74 integer array. Default is `int`. 

75 float_to_float : function, optional 

76 Function that converts a float array to float. Default is `float`. 

77 Note that this does not seem to do anything useful in the current 

78 implementation. 

79 float_to_str : function, optional 

80 Function that converts a single float to a string. Default is 

81 ``lambda v:'%24.16e' %v``. 

82 title : str, optional 

83 Title that is printed in the string representation of `MachAr`. 

84 

85 See Also 

86 -------- 

87 finfo : Machine limits for floating point types. 

88 iinfo : Machine limits for integer types. 

89 

90 References 

91 ---------- 

92 .. [1] Press, Teukolsky, Vetterling and Flannery, 

93 "Numerical Recipes in C++," 2nd ed, 

94 Cambridge University Press, 2002, p. 31. 

95 

96 """ 

97 

98 def __init__(self, float_conv=float,int_conv=int, 

99 float_to_float=float, 

100 float_to_str=lambda v:'%24.16e' % v, 

101 title='Python floating point number'): 

102 """ 

103 

104 float_conv - convert integer to float (array) 

105 int_conv - convert float (array) to integer 

106 float_to_float - convert float array to float 

107 float_to_str - convert array float to str 

108 title - description of used floating point numbers 

109 

110 """ 

111 # We ignore all errors here because we are purposely triggering 

112 # underflow to detect the properties of the runninng arch. 

113 with errstate(under='ignore'): 

114 self._do_init(float_conv, int_conv, float_to_float, float_to_str, title) 

115 

116 def _do_init(self, float_conv, int_conv, float_to_float, float_to_str, title): 

117 max_iterN = 10000 

118 msg = "Did not converge after %d tries with %s" 

119 one = float_conv(1) 

120 two = one + one 

121 zero = one - one 

122 

123 # Do we really need to do this? Aren't they 2 and 2.0? 

124 # Determine ibeta and beta 

125 a = one 

126 for _ in range(max_iterN): 

127 a = a + a 

128 temp = a + one 

129 temp1 = temp - a 

130 if any(temp1 - one != zero): 

131 break 

132 else: 

133 raise RuntimeError(msg % (_, one.dtype)) 

134 b = one 

135 for _ in range(max_iterN): 

136 b = b + b 

137 temp = a + b 

138 itemp = int_conv(temp-a) 

139 if any(itemp != 0): 

140 break 

141 else: 

142 raise RuntimeError(msg % (_, one.dtype)) 

143 ibeta = itemp 

144 beta = float_conv(ibeta) 

145 

146 # Determine it and irnd 

147 it = -1 

148 b = one 

149 for _ in range(max_iterN): 

150 it = it + 1 

151 b = b * beta 

152 temp = b + one 

153 temp1 = temp - b 

154 if any(temp1 - one != zero): 

155 break 

156 else: 

157 raise RuntimeError(msg % (_, one.dtype)) 

158 

159 betah = beta / two 

160 a = one 

161 for _ in range(max_iterN): 

162 a = a + a 

163 temp = a + one 

164 temp1 = temp - a 

165 if any(temp1 - one != zero): 

166 break 

167 else: 

168 raise RuntimeError(msg % (_, one.dtype)) 

169 temp = a + betah 

170 irnd = 0 

171 if any(temp-a != zero): 

172 irnd = 1 

173 tempa = a + beta 

174 temp = tempa + betah 

175 if irnd == 0 and any(temp-tempa != zero): 

176 irnd = 2 

177 

178 # Determine negep and epsneg 

179 negep = it + 3 

180 betain = one / beta 

181 a = one 

182 for i in range(negep): 

183 a = a * betain 

184 b = a 

185 for _ in range(max_iterN): 

186 temp = one - a 

187 if any(temp-one != zero): 

188 break 

189 a = a * beta 

190 negep = negep - 1 

191 # Prevent infinite loop on PPC with gcc 4.0: 

192 if negep < 0: 

193 raise RuntimeError("could not determine machine tolerance " 

194 "for 'negep', locals() -> %s" % (locals())) 

195 else: 

196 raise RuntimeError(msg % (_, one.dtype)) 

197 negep = -negep 

198 epsneg = a 

199 

200 # Determine machep and eps 

201 machep = - it - 3 

202 a = b 

203 

204 for _ in range(max_iterN): 

205 temp = one + a 

206 if any(temp-one != zero): 

207 break 

208 a = a * beta 

209 machep = machep + 1 

210 else: 

211 raise RuntimeError(msg % (_, one.dtype)) 

212 eps = a 

213 

214 # Determine ngrd 

215 ngrd = 0 

216 temp = one + eps 

217 if irnd == 0 and any(temp*one - one != zero): 

218 ngrd = 1 

219 

220 # Determine iexp 

221 i = 0 

222 k = 1 

223 z = betain 

224 t = one + eps 

225 nxres = 0 

226 for _ in range(max_iterN): 

227 y = z 

228 z = y*y 

229 a = z*one # Check here for underflow 

230 temp = z*t 

231 if any(a+a == zero) or any(abs(z) >= y): 

232 break 

233 temp1 = temp * betain 

234 if any(temp1*beta == z): 

235 break 

236 i = i + 1 

237 k = k + k 

238 else: 

239 raise RuntimeError(msg % (_, one.dtype)) 

240 if ibeta != 10: 

241 iexp = i + 1 

242 mx = k + k 

243 else: 

244 iexp = 2 

245 iz = ibeta 

246 while k >= iz: 

247 iz = iz * ibeta 

248 iexp = iexp + 1 

249 mx = iz + iz - 1 

250 

251 # Determine minexp and xmin 

252 for _ in range(max_iterN): 

253 xmin = y 

254 y = y * betain 

255 a = y * one 

256 temp = y * t 

257 if any((a + a) != zero) and any(abs(y) < xmin): 

258 k = k + 1 

259 temp1 = temp * betain 

260 if any(temp1*beta == y) and any(temp != y): 

261 nxres = 3 

262 xmin = y 

263 break 

264 else: 

265 break 

266 else: 

267 raise RuntimeError(msg % (_, one.dtype)) 

268 minexp = -k 

269 

270 # Determine maxexp, xmax 

271 if mx <= k + k - 3 and ibeta != 10: 

272 mx = mx + mx 

273 iexp = iexp + 1 

274 maxexp = mx + minexp 

275 irnd = irnd + nxres 

276 if irnd >= 2: 

277 maxexp = maxexp - 2 

278 i = maxexp + minexp 

279 if ibeta == 2 and not i: 

280 maxexp = maxexp - 1 

281 if i > 20: 

282 maxexp = maxexp - 1 

283 if any(a != y): 

284 maxexp = maxexp - 2 

285 xmax = one - epsneg 

286 if any(xmax*one != xmax): 

287 xmax = one - beta*epsneg 

288 xmax = xmax / (xmin*beta*beta*beta) 

289 i = maxexp + minexp + 3 

290 for j in range(i): 

291 if ibeta == 2: 

292 xmax = xmax + xmax 

293 else: 

294 xmax = xmax * beta 

295 

296 self.ibeta = ibeta 

297 self.it = it 

298 self.negep = negep 

299 self.epsneg = float_to_float(epsneg) 

300 self._str_epsneg = float_to_str(epsneg) 

301 self.machep = machep 

302 self.eps = float_to_float(eps) 

303 self._str_eps = float_to_str(eps) 

304 self.ngrd = ngrd 

305 self.iexp = iexp 

306 self.minexp = minexp 

307 self.xmin = float_to_float(xmin) 

308 self._str_xmin = float_to_str(xmin) 

309 self.maxexp = maxexp 

310 self.xmax = float_to_float(xmax) 

311 self._str_xmax = float_to_str(xmax) 

312 self.irnd = irnd 

313 

314 self.title = title 

315 # Commonly used parameters 

316 self.epsilon = self.eps 

317 self.tiny = self.xmin 

318 self.huge = self.xmax 

319 

320 import math 

321 self.precision = int(-math.log10(float_to_float(self.eps))) 

322 ten = two + two + two + two + two 

323 resolution = ten ** (-self.precision) 

324 self.resolution = float_to_float(resolution) 

325 self._str_resolution = float_to_str(resolution) 

326 

327 def __str__(self): 

328 fmt = ( 

329 'Machine parameters for %(title)s\n' 

330 '---------------------------------------------------------------------\n' 

331 'ibeta=%(ibeta)s it=%(it)s iexp=%(iexp)s ngrd=%(ngrd)s irnd=%(irnd)s\n' 

332 'machep=%(machep)s eps=%(_str_eps)s (beta**machep == epsilon)\n' 

333 'negep =%(negep)s epsneg=%(_str_epsneg)s (beta**epsneg)\n' 

334 'minexp=%(minexp)s xmin=%(_str_xmin)s (beta**minexp == tiny)\n' 

335 'maxexp=%(maxexp)s xmax=%(_str_xmax)s ((1-epsneg)*beta**maxexp == huge)\n' 

336 '---------------------------------------------------------------------\n' 

337 ) 

338 return fmt % self.__dict__ 

339 

340 

341if __name__ == '__main__': 

342 print(MachAr())