_machar.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. """
  2. Machine arithmetic - determine the parameters of the
  3. floating-point arithmetic system
  4. Author: Pearu Peterson, September 2003
  5. """
  6. __all__ = ['MachAr']
  7. from numpy.core.fromnumeric import any
  8. from numpy.core._ufunc_config import errstate
  9. from numpy.core.overrides import set_module
  10. # Need to speed this up...especially for longfloat
  11. # Deprecated 2021-10-20, NumPy 1.22
  12. @set_module('numpy')
  13. class MachAr:
  14. """
  15. Diagnosing machine parameters.
  16. Attributes
  17. ----------
  18. ibeta : int
  19. Radix in which numbers are represented.
  20. it : int
  21. Number of base-`ibeta` digits in the floating point mantissa M.
  22. machep : int
  23. Exponent of the smallest (most negative) power of `ibeta` that,
  24. added to 1.0, gives something different from 1.0
  25. eps : float
  26. Floating-point number ``beta**machep`` (floating point precision)
  27. negep : int
  28. Exponent of the smallest power of `ibeta` that, subtracted
  29. from 1.0, gives something different from 1.0.
  30. epsneg : float
  31. Floating-point number ``beta**negep``.
  32. iexp : int
  33. Number of bits in the exponent (including its sign and bias).
  34. minexp : int
  35. Smallest (most negative) power of `ibeta` consistent with there
  36. being no leading zeros in the mantissa.
  37. xmin : float
  38. Floating-point number ``beta**minexp`` (the smallest [in
  39. magnitude] positive floating point number with full precision).
  40. maxexp : int
  41. Smallest (positive) power of `ibeta` that causes overflow.
  42. xmax : float
  43. ``(1-epsneg) * beta**maxexp`` (the largest [in magnitude]
  44. usable floating value).
  45. irnd : int
  46. In ``range(6)``, information on what kind of rounding is done
  47. in addition, and on how underflow is handled.
  48. ngrd : int
  49. Number of 'guard digits' used when truncating the product
  50. of two mantissas to fit the representation.
  51. epsilon : float
  52. Same as `eps`.
  53. tiny : float
  54. An alias for `smallest_normal`, kept for backwards compatibility.
  55. huge : float
  56. Same as `xmax`.
  57. precision : float
  58. ``- int(-log10(eps))``
  59. resolution : float
  60. ``- 10**(-precision)``
  61. smallest_normal : float
  62. The smallest positive floating point number with 1 as leading bit in
  63. the mantissa following IEEE-754. Same as `xmin`.
  64. smallest_subnormal : float
  65. The smallest positive floating point number with 0 as leading bit in
  66. the mantissa following IEEE-754.
  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. See Also
  85. --------
  86. finfo : Machine limits for floating point types.
  87. iinfo : Machine limits for integer types.
  88. References
  89. ----------
  90. .. [1] Press, Teukolsky, Vetterling and Flannery,
  91. "Numerical Recipes in C++," 2nd ed,
  92. Cambridge University Press, 2002, p. 31.
  93. """
  94. def __init__(self, float_conv=float,int_conv=int,
  95. float_to_float=float,
  96. float_to_str=lambda v:'%24.16e' % v,
  97. title='Python floating point number'):
  98. """
  99. float_conv - convert integer to float (array)
  100. int_conv - convert float (array) to integer
  101. float_to_float - convert float array to float
  102. float_to_str - convert array float to str
  103. title - description of used floating point numbers
  104. """
  105. # We ignore all errors here because we are purposely triggering
  106. # underflow to detect the properties of the runninng arch.
  107. with errstate(under='ignore'):
  108. self._do_init(float_conv, int_conv, float_to_float, float_to_str, title)
  109. def _do_init(self, float_conv, int_conv, float_to_float, float_to_str, title):
  110. max_iterN = 10000
  111. msg = "Did not converge after %d tries with %s"
  112. one = float_conv(1)
  113. two = one + one
  114. zero = one - one
  115. # Do we really need to do this? Aren't they 2 and 2.0?
  116. # Determine ibeta and beta
  117. a = one
  118. for _ in range(max_iterN):
  119. a = a + a
  120. temp = a + one
  121. temp1 = temp - a
  122. if any(temp1 - one != zero):
  123. break
  124. else:
  125. raise RuntimeError(msg % (_, one.dtype))
  126. b = one
  127. for _ in range(max_iterN):
  128. b = b + b
  129. temp = a + b
  130. itemp = int_conv(temp-a)
  131. if any(itemp != 0):
  132. break
  133. else:
  134. raise RuntimeError(msg % (_, one.dtype))
  135. ibeta = itemp
  136. beta = float_conv(ibeta)
  137. # Determine it and irnd
  138. it = -1
  139. b = one
  140. for _ in range(max_iterN):
  141. it = it + 1
  142. b = b * beta
  143. temp = b + one
  144. temp1 = temp - b
  145. if any(temp1 - one != zero):
  146. break
  147. else:
  148. raise RuntimeError(msg % (_, one.dtype))
  149. betah = beta / two
  150. a = one
  151. for _ in range(max_iterN):
  152. a = a + a
  153. temp = a + one
  154. temp1 = temp - a
  155. if any(temp1 - one != zero):
  156. break
  157. else:
  158. raise RuntimeError(msg % (_, one.dtype))
  159. temp = a + betah
  160. irnd = 0
  161. if any(temp-a != zero):
  162. irnd = 1
  163. tempa = a + beta
  164. temp = tempa + betah
  165. if irnd == 0 and any(temp-tempa != zero):
  166. irnd = 2
  167. # Determine negep and epsneg
  168. negep = it + 3
  169. betain = one / beta
  170. a = one
  171. for i in range(negep):
  172. a = a * betain
  173. b = a
  174. for _ in range(max_iterN):
  175. temp = one - a
  176. if any(temp-one != zero):
  177. break
  178. a = a * beta
  179. negep = negep - 1
  180. # Prevent infinite loop on PPC with gcc 4.0:
  181. if negep < 0:
  182. raise RuntimeError("could not determine machine tolerance "
  183. "for 'negep', locals() -> %s" % (locals()))
  184. else:
  185. raise RuntimeError(msg % (_, one.dtype))
  186. negep = -negep
  187. epsneg = a
  188. # Determine machep and eps
  189. machep = - it - 3
  190. a = b
  191. for _ in range(max_iterN):
  192. temp = one + a
  193. if any(temp-one != zero):
  194. break
  195. a = a * beta
  196. machep = machep + 1
  197. else:
  198. raise RuntimeError(msg % (_, one.dtype))
  199. eps = a
  200. # Determine ngrd
  201. ngrd = 0
  202. temp = one + eps
  203. if irnd == 0 and any(temp*one - one != zero):
  204. ngrd = 1
  205. # Determine iexp
  206. i = 0
  207. k = 1
  208. z = betain
  209. t = one + eps
  210. nxres = 0
  211. for _ in range(max_iterN):
  212. y = z
  213. z = y*y
  214. a = z*one # Check here for underflow
  215. temp = z*t
  216. if any(a+a == zero) or any(abs(z) >= y):
  217. break
  218. temp1 = temp * betain
  219. if any(temp1*beta == z):
  220. break
  221. i = i + 1
  222. k = k + k
  223. else:
  224. raise RuntimeError(msg % (_, one.dtype))
  225. if ibeta != 10:
  226. iexp = i + 1
  227. mx = k + k
  228. else:
  229. iexp = 2
  230. iz = ibeta
  231. while k >= iz:
  232. iz = iz * ibeta
  233. iexp = iexp + 1
  234. mx = iz + iz - 1
  235. # Determine minexp and xmin
  236. for _ in range(max_iterN):
  237. xmin = y
  238. y = y * betain
  239. a = y * one
  240. temp = y * t
  241. if any((a + a) != zero) and any(abs(y) < xmin):
  242. k = k + 1
  243. temp1 = temp * betain
  244. if any(temp1*beta == y) and any(temp != y):
  245. nxres = 3
  246. xmin = y
  247. break
  248. else:
  249. break
  250. else:
  251. raise RuntimeError(msg % (_, one.dtype))
  252. minexp = -k
  253. # Determine maxexp, xmax
  254. if mx <= k + k - 3 and ibeta != 10:
  255. mx = mx + mx
  256. iexp = iexp + 1
  257. maxexp = mx + minexp
  258. irnd = irnd + nxres
  259. if irnd >= 2:
  260. maxexp = maxexp - 2
  261. i = maxexp + minexp
  262. if ibeta == 2 and not i:
  263. maxexp = maxexp - 1
  264. if i > 20:
  265. maxexp = maxexp - 1
  266. if any(a != y):
  267. maxexp = maxexp - 2
  268. xmax = one - epsneg
  269. if any(xmax*one != xmax):
  270. xmax = one - beta*epsneg
  271. xmax = xmax / (xmin*beta*beta*beta)
  272. i = maxexp + minexp + 3
  273. for j in range(i):
  274. if ibeta == 2:
  275. xmax = xmax + xmax
  276. else:
  277. xmax = xmax * beta
  278. smallest_subnormal = abs(xmin / beta ** (it))
  279. self.ibeta = ibeta
  280. self.it = it
  281. self.negep = negep
  282. self.epsneg = float_to_float(epsneg)
  283. self._str_epsneg = float_to_str(epsneg)
  284. self.machep = machep
  285. self.eps = float_to_float(eps)
  286. self._str_eps = float_to_str(eps)
  287. self.ngrd = ngrd
  288. self.iexp = iexp
  289. self.minexp = minexp
  290. self.xmin = float_to_float(xmin)
  291. self._str_xmin = float_to_str(xmin)
  292. self.maxexp = maxexp
  293. self.xmax = float_to_float(xmax)
  294. self._str_xmax = float_to_str(xmax)
  295. self.irnd = irnd
  296. self.title = title
  297. # Commonly used parameters
  298. self.epsilon = self.eps
  299. self.tiny = self.xmin
  300. self.huge = self.xmax
  301. self.smallest_normal = self.xmin
  302. self._str_smallest_normal = float_to_str(self.xmin)
  303. self.smallest_subnormal = float_to_float(smallest_subnormal)
  304. self._str_smallest_subnormal = float_to_str(smallest_subnormal)
  305. import math
  306. self.precision = int(-math.log10(float_to_float(self.eps)))
  307. ten = two + two + two + two + two
  308. resolution = ten ** (-self.precision)
  309. self.resolution = float_to_float(resolution)
  310. self._str_resolution = float_to_str(resolution)
  311. def __str__(self):
  312. fmt = (
  313. 'Machine parameters for %(title)s\n'
  314. '---------------------------------------------------------------------\n'
  315. 'ibeta=%(ibeta)s it=%(it)s iexp=%(iexp)s ngrd=%(ngrd)s irnd=%(irnd)s\n'
  316. 'machep=%(machep)s eps=%(_str_eps)s (beta**machep == epsilon)\n'
  317. 'negep =%(negep)s epsneg=%(_str_epsneg)s (beta**epsneg)\n'
  318. 'minexp=%(minexp)s xmin=%(_str_xmin)s (beta**minexp == tiny)\n'
  319. 'maxexp=%(maxexp)s xmax=%(_str_xmax)s ((1-epsneg)*beta**maxexp == huge)\n'
  320. 'smallest_normal=%(smallest_normal)s '
  321. 'smallest_subnormal=%(smallest_subnormal)s\n'
  322. '---------------------------------------------------------------------\n'
  323. )
  324. return fmt % self.__dict__
  325. if __name__ == '__main__':
  326. print(MachAr())