Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/numpy/core/getlimits.py: 58%
228 statements
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:27 +0000
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:27 +0000
1"""Machine limits for Float32 and Float64 and (long double) if available...
3"""
4__all__ = ['finfo', 'iinfo']
6import warnings
8from .._utils import set_module
9from ._machar import MachAr
10from . import numeric
11from . import numerictypes as ntypes
12from .numeric import array, inf, NaN
13from .umath import log10, exp2, nextafter, isnan
16def _fr0(a):
17 """fix rank-0 --> rank-1"""
18 if a.ndim == 0:
19 a = a.copy()
20 a.shape = (1,)
21 return a
24def _fr1(a):
25 """fix rank > 0 --> rank-0"""
26 if a.size == 1:
27 a = a.copy()
28 a.shape = ()
29 return a
32class MachArLike:
33 """ Object to simulate MachAr instance """
34 def __init__(self, ftype, *, eps, epsneg, huge, tiny,
35 ibeta, smallest_subnormal=None, **kwargs):
36 self.params = _MACHAR_PARAMS[ftype]
37 self.ftype = ftype
38 self.title = self.params['title']
39 # Parameter types same as for discovered MachAr object.
40 if not smallest_subnormal:
41 self._smallest_subnormal = nextafter(
42 self.ftype(0), self.ftype(1), dtype=self.ftype)
43 else:
44 self._smallest_subnormal = smallest_subnormal
45 self.epsilon = self.eps = self._float_to_float(eps)
46 self.epsneg = self._float_to_float(epsneg)
47 self.xmax = self.huge = self._float_to_float(huge)
48 self.xmin = self._float_to_float(tiny)
49 self.smallest_normal = self.tiny = self._float_to_float(tiny)
50 self.ibeta = self.params['itype'](ibeta)
51 self.__dict__.update(kwargs)
52 self.precision = int(-log10(self.eps))
53 self.resolution = self._float_to_float(
54 self._float_conv(10) ** (-self.precision))
55 self._str_eps = self._float_to_str(self.eps)
56 self._str_epsneg = self._float_to_str(self.epsneg)
57 self._str_xmin = self._float_to_str(self.xmin)
58 self._str_xmax = self._float_to_str(self.xmax)
59 self._str_resolution = self._float_to_str(self.resolution)
60 self._str_smallest_normal = self._float_to_str(self.xmin)
62 @property
63 def smallest_subnormal(self):
64 """Return the value for the smallest subnormal.
66 Returns
67 -------
68 smallest_subnormal : float
69 value for the smallest subnormal.
71 Warns
72 -----
73 UserWarning
74 If the calculated value for the smallest subnormal is zero.
75 """
76 # Check that the calculated value is not zero, in case it raises a
77 # warning.
78 value = self._smallest_subnormal
79 if self.ftype(0) == value:
80 warnings.warn(
81 'The value of the smallest subnormal for {} type '
82 'is zero.'.format(self.ftype), UserWarning, stacklevel=2)
84 return self._float_to_float(value)
86 @property
87 def _str_smallest_subnormal(self):
88 """Return the string representation of the smallest subnormal."""
89 return self._float_to_str(self.smallest_subnormal)
91 def _float_to_float(self, value):
92 """Converts float to float.
94 Parameters
95 ----------
96 value : float
97 value to be converted.
98 """
99 return _fr1(self._float_conv(value))
101 def _float_conv(self, value):
102 """Converts float to conv.
104 Parameters
105 ----------
106 value : float
107 value to be converted.
108 """
109 return array([value], self.ftype)
111 def _float_to_str(self, value):
112 """Converts float to str.
114 Parameters
115 ----------
116 value : float
117 value to be converted.
118 """
119 return self.params['fmt'] % array(_fr0(value)[0], self.ftype)
122_convert_to_float = {
123 ntypes.csingle: ntypes.single,
124 ntypes.complex_: ntypes.float_,
125 ntypes.clongfloat: ntypes.longfloat
126 }
128# Parameters for creating MachAr / MachAr-like objects
129_title_fmt = 'numpy {} precision floating point number'
130_MACHAR_PARAMS = {
131 ntypes.double: dict(
132 itype = ntypes.int64,
133 fmt = '%24.16e',
134 title = _title_fmt.format('double')),
135 ntypes.single: dict(
136 itype = ntypes.int32,
137 fmt = '%15.7e',
138 title = _title_fmt.format('single')),
139 ntypes.longdouble: dict(
140 itype = ntypes.longlong,
141 fmt = '%s',
142 title = _title_fmt.format('long double')),
143 ntypes.half: dict(
144 itype = ntypes.int16,
145 fmt = '%12.5e',
146 title = _title_fmt.format('half'))}
148# Key to identify the floating point type. Key is result of
149# ftype('-0.1').newbyteorder('<').tobytes()
150# See:
151# https://perl5.git.perl.org/perl.git/blob/3118d7d684b56cbeb702af874f4326683c45f045:/Configure
152_KNOWN_TYPES = {}
153def _register_type(machar, bytepat):
154 _KNOWN_TYPES[bytepat] = machar
155_float_ma = {}
158def _register_known_types():
159 # Known parameters for float16
160 # See docstring of MachAr class for description of parameters.
161 f16 = ntypes.float16
162 float16_ma = MachArLike(f16,
163 machep=-10,
164 negep=-11,
165 minexp=-14,
166 maxexp=16,
167 it=10,
168 iexp=5,
169 ibeta=2,
170 irnd=5,
171 ngrd=0,
172 eps=exp2(f16(-10)),
173 epsneg=exp2(f16(-11)),
174 huge=f16(65504),
175 tiny=f16(2 ** -14))
176 _register_type(float16_ma, b'f\xae')
177 _float_ma[16] = float16_ma
179 # Known parameters for float32
180 f32 = ntypes.float32
181 float32_ma = MachArLike(f32,
182 machep=-23,
183 negep=-24,
184 minexp=-126,
185 maxexp=128,
186 it=23,
187 iexp=8,
188 ibeta=2,
189 irnd=5,
190 ngrd=0,
191 eps=exp2(f32(-23)),
192 epsneg=exp2(f32(-24)),
193 huge=f32((1 - 2 ** -24) * 2**128),
194 tiny=exp2(f32(-126)))
195 _register_type(float32_ma, b'\xcd\xcc\xcc\xbd')
196 _float_ma[32] = float32_ma
198 # Known parameters for float64
199 f64 = ntypes.float64
200 epsneg_f64 = 2.0 ** -53.0
201 tiny_f64 = 2.0 ** -1022.0
202 float64_ma = MachArLike(f64,
203 machep=-52,
204 negep=-53,
205 minexp=-1022,
206 maxexp=1024,
207 it=52,
208 iexp=11,
209 ibeta=2,
210 irnd=5,
211 ngrd=0,
212 eps=2.0 ** -52.0,
213 epsneg=epsneg_f64,
214 huge=(1.0 - epsneg_f64) / tiny_f64 * f64(4),
215 tiny=tiny_f64)
216 _register_type(float64_ma, b'\x9a\x99\x99\x99\x99\x99\xb9\xbf')
217 _float_ma[64] = float64_ma
219 # Known parameters for IEEE 754 128-bit binary float
220 ld = ntypes.longdouble
221 epsneg_f128 = exp2(ld(-113))
222 tiny_f128 = exp2(ld(-16382))
223 # Ignore runtime error when this is not f128
224 with numeric.errstate(all='ignore'):
225 huge_f128 = (ld(1) - epsneg_f128) / tiny_f128 * ld(4)
226 float128_ma = MachArLike(ld,
227 machep=-112,
228 negep=-113,
229 minexp=-16382,
230 maxexp=16384,
231 it=112,
232 iexp=15,
233 ibeta=2,
234 irnd=5,
235 ngrd=0,
236 eps=exp2(ld(-112)),
237 epsneg=epsneg_f128,
238 huge=huge_f128,
239 tiny=tiny_f128)
240 # IEEE 754 128-bit binary float
241 _register_type(float128_ma,
242 b'\x9a\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xfb\xbf')
243 _register_type(float128_ma,
244 b'\x9a\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xfb\xbf')
245 _float_ma[128] = float128_ma
247 # Known parameters for float80 (Intel 80-bit extended precision)
248 epsneg_f80 = exp2(ld(-64))
249 tiny_f80 = exp2(ld(-16382))
250 # Ignore runtime error when this is not f80
251 with numeric.errstate(all='ignore'):
252 huge_f80 = (ld(1) - epsneg_f80) / tiny_f80 * ld(4)
253 float80_ma = MachArLike(ld,
254 machep=-63,
255 negep=-64,
256 minexp=-16382,
257 maxexp=16384,
258 it=63,
259 iexp=15,
260 ibeta=2,
261 irnd=5,
262 ngrd=0,
263 eps=exp2(ld(-63)),
264 epsneg=epsneg_f80,
265 huge=huge_f80,
266 tiny=tiny_f80)
267 # float80, first 10 bytes containing actual storage
268 _register_type(float80_ma, b'\xcd\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xfb\xbf')
269 _float_ma[80] = float80_ma
271 # Guessed / known parameters for double double; see:
272 # https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format#Double-double_arithmetic
273 # These numbers have the same exponent range as float64, but extended number of
274 # digits in the significand.
275 huge_dd = nextafter(ld(inf), ld(0), dtype=ld)
276 # As the smallest_normal in double double is so hard to calculate we set
277 # it to NaN.
278 smallest_normal_dd = NaN
279 # Leave the same value for the smallest subnormal as double
280 smallest_subnormal_dd = ld(nextafter(0., 1.))
281 float_dd_ma = MachArLike(ld,
282 machep=-105,
283 negep=-106,
284 minexp=-1022,
285 maxexp=1024,
286 it=105,
287 iexp=11,
288 ibeta=2,
289 irnd=5,
290 ngrd=0,
291 eps=exp2(ld(-105)),
292 epsneg=exp2(ld(-106)),
293 huge=huge_dd,
294 tiny=smallest_normal_dd,
295 smallest_subnormal=smallest_subnormal_dd)
296 # double double; low, high order (e.g. PPC 64)
297 _register_type(float_dd_ma,
298 b'\x9a\x99\x99\x99\x99\x99Y<\x9a\x99\x99\x99\x99\x99\xb9\xbf')
299 # double double; high, low order (e.g. PPC 64 le)
300 _register_type(float_dd_ma,
301 b'\x9a\x99\x99\x99\x99\x99\xb9\xbf\x9a\x99\x99\x99\x99\x99Y<')
302 _float_ma['dd'] = float_dd_ma
305def _get_machar(ftype):
306 """ Get MachAr instance or MachAr-like instance
308 Get parameters for floating point type, by first trying signatures of
309 various known floating point types, then, if none match, attempting to
310 identify parameters by analysis.
312 Parameters
313 ----------
314 ftype : class
315 Numpy floating point type class (e.g. ``np.float64``)
317 Returns
318 -------
319 ma_like : instance of :class:`MachAr` or :class:`MachArLike`
320 Object giving floating point parameters for `ftype`.
322 Warns
323 -----
324 UserWarning
325 If the binary signature of the float type is not in the dictionary of
326 known float types.
327 """
328 params = _MACHAR_PARAMS.get(ftype)
329 if params is None:
330 raise ValueError(repr(ftype))
331 # Detect known / suspected types
332 key = ftype('-0.1').newbyteorder('<').tobytes()
333 ma_like = None
334 if ftype == ntypes.longdouble:
335 # Could be 80 bit == 10 byte extended precision, where last bytes can
336 # be random garbage.
337 # Comparing first 10 bytes to pattern first to avoid branching on the
338 # random garbage.
339 ma_like = _KNOWN_TYPES.get(key[:10])
340 if ma_like is None:
341 ma_like = _KNOWN_TYPES.get(key)
342 if ma_like is not None:
343 return ma_like
344 # Fall back to parameter discovery
345 warnings.warn(
346 f'Signature {key} for {ftype} does not match any known type: '
347 'falling back to type probe function.\n'
348 'This warnings indicates broken support for the dtype!',
349 UserWarning, stacklevel=2)
350 return _discovered_machar(ftype)
353def _discovered_machar(ftype):
354 """ Create MachAr instance with found information on float types
356 TODO: MachAr should be retired completely ideally. We currently only
357 ever use it system with broken longdouble (valgrind, WSL).
358 """
359 params = _MACHAR_PARAMS[ftype]
360 return MachAr(lambda v: array([v], ftype),
361 lambda v:_fr0(v.astype(params['itype']))[0],
362 lambda v:array(_fr0(v)[0], ftype),
363 lambda v: params['fmt'] % array(_fr0(v)[0], ftype),
364 params['title'])
367@set_module('numpy')
368class finfo:
369 """
370 finfo(dtype)
372 Machine limits for floating point types.
374 Attributes
375 ----------
376 bits : int
377 The number of bits occupied by the type.
378 dtype : dtype
379 Returns the dtype for which `finfo` returns information. For complex
380 input, the returned dtype is the associated ``float*`` dtype for its
381 real and complex components.
382 eps : float
383 The difference between 1.0 and the next smallest representable float
384 larger than 1.0. For example, for 64-bit binary floats in the IEEE-754
385 standard, ``eps = 2**-52``, approximately 2.22e-16.
386 epsneg : float
387 The difference between 1.0 and the next smallest representable float
388 less than 1.0. For example, for 64-bit binary floats in the IEEE-754
389 standard, ``epsneg = 2**-53``, approximately 1.11e-16.
390 iexp : int
391 The number of bits in the exponent portion of the floating point
392 representation.
393 machep : int
394 The exponent that yields `eps`.
395 max : floating point number of the appropriate type
396 The largest representable number.
397 maxexp : int
398 The smallest positive power of the base (2) that causes overflow.
399 min : floating point number of the appropriate type
400 The smallest representable number, typically ``-max``.
401 minexp : int
402 The most negative power of the base (2) consistent with there
403 being no leading 0's in the mantissa.
404 negep : int
405 The exponent that yields `epsneg`.
406 nexp : int
407 The number of bits in the exponent including its sign and bias.
408 nmant : int
409 The number of bits in the mantissa.
410 precision : int
411 The approximate number of decimal digits to which this kind of
412 float is precise.
413 resolution : floating point number of the appropriate type
414 The approximate decimal resolution of this type, i.e.,
415 ``10**-precision``.
416 tiny : float
417 An alias for `smallest_normal`, kept for backwards compatibility.
418 smallest_normal : float
419 The smallest positive floating point number with 1 as leading bit in
420 the mantissa following IEEE-754 (see Notes).
421 smallest_subnormal : float
422 The smallest positive floating point number with 0 as leading bit in
423 the mantissa following IEEE-754.
425 Parameters
426 ----------
427 dtype : float, dtype, or instance
428 Kind of floating point or complex floating point
429 data-type about which to get information.
431 See Also
432 --------
433 iinfo : The equivalent for integer data types.
434 spacing : The distance between a value and the nearest adjacent number
435 nextafter : The next floating point value after x1 towards x2
437 Notes
438 -----
439 For developers of NumPy: do not instantiate this at the module level.
440 The initial calculation of these parameters is expensive and negatively
441 impacts import times. These objects are cached, so calling ``finfo()``
442 repeatedly inside your functions is not a problem.
444 Note that ``smallest_normal`` is not actually the smallest positive
445 representable value in a NumPy floating point type. As in the IEEE-754
446 standard [1]_, NumPy floating point types make use of subnormal numbers to
447 fill the gap between 0 and ``smallest_normal``. However, subnormal numbers
448 may have significantly reduced precision [2]_.
450 This function can also be used for complex data types as well. If used,
451 the output will be the same as the corresponding real float type
452 (e.g. numpy.finfo(numpy.csingle) is the same as numpy.finfo(numpy.single)).
453 However, the output is true for the real and imaginary components.
455 References
456 ----------
457 .. [1] IEEE Standard for Floating-Point Arithmetic, IEEE Std 754-2008,
458 pp.1-70, 2008, http://www.doi.org/10.1109/IEEESTD.2008.4610935
459 .. [2] Wikipedia, "Denormal Numbers",
460 https://en.wikipedia.org/wiki/Denormal_number
462 Examples
463 --------
464 >>> np.finfo(np.float64).dtype
465 dtype('float64')
466 >>> np.finfo(np.complex64).dtype
467 dtype('float32')
469 """
471 _finfo_cache = {}
473 def __new__(cls, dtype):
474 try:
475 dtype = numeric.dtype(dtype)
476 except TypeError:
477 # In case a float instance was given
478 dtype = numeric.dtype(type(dtype))
480 obj = cls._finfo_cache.get(dtype, None)
481 if obj is not None:
482 return obj
483 dtypes = [dtype]
484 newdtype = numeric.obj2sctype(dtype)
485 if newdtype is not dtype:
486 dtypes.append(newdtype)
487 dtype = newdtype
488 if not issubclass(dtype, numeric.inexact):
489 raise ValueError("data type %r not inexact" % (dtype))
490 obj = cls._finfo_cache.get(dtype, None)
491 if obj is not None:
492 return obj
493 if not issubclass(dtype, numeric.floating):
494 newdtype = _convert_to_float[dtype]
495 if newdtype is not dtype:
496 dtypes.append(newdtype)
497 dtype = newdtype
498 obj = cls._finfo_cache.get(dtype, None)
499 if obj is not None:
500 return obj
501 obj = object.__new__(cls)._init(dtype)
502 for dt in dtypes:
503 cls._finfo_cache[dt] = obj
504 return obj
506 def _init(self, dtype):
507 self.dtype = numeric.dtype(dtype)
508 machar = _get_machar(dtype)
510 for word in ['precision', 'iexp',
511 'maxexp', 'minexp', 'negep',
512 'machep']:
513 setattr(self, word, getattr(machar, word))
514 for word in ['resolution', 'epsneg', 'smallest_subnormal']:
515 setattr(self, word, getattr(machar, word).flat[0])
516 self.bits = self.dtype.itemsize * 8
517 self.max = machar.huge.flat[0]
518 self.min = -self.max
519 self.eps = machar.eps.flat[0]
520 self.nexp = machar.iexp
521 self.nmant = machar.it
522 self._machar = machar
523 self._str_tiny = machar._str_xmin.strip()
524 self._str_max = machar._str_xmax.strip()
525 self._str_epsneg = machar._str_epsneg.strip()
526 self._str_eps = machar._str_eps.strip()
527 self._str_resolution = machar._str_resolution.strip()
528 self._str_smallest_normal = machar._str_smallest_normal.strip()
529 self._str_smallest_subnormal = machar._str_smallest_subnormal.strip()
530 return self
532 def __str__(self):
533 fmt = (
534 'Machine parameters for %(dtype)s\n'
535 '---------------------------------------------------------------\n'
536 'precision = %(precision)3s resolution = %(_str_resolution)s\n'
537 'machep = %(machep)6s eps = %(_str_eps)s\n'
538 'negep = %(negep)6s epsneg = %(_str_epsneg)s\n'
539 'minexp = %(minexp)6s tiny = %(_str_tiny)s\n'
540 'maxexp = %(maxexp)6s max = %(_str_max)s\n'
541 'nexp = %(nexp)6s min = -max\n'
542 'smallest_normal = %(_str_smallest_normal)s '
543 'smallest_subnormal = %(_str_smallest_subnormal)s\n'
544 '---------------------------------------------------------------\n'
545 )
546 return fmt % self.__dict__
548 def __repr__(self):
549 c = self.__class__.__name__
550 d = self.__dict__.copy()
551 d['klass'] = c
552 return (("%(klass)s(resolution=%(resolution)s, min=-%(_str_max)s,"
553 " max=%(_str_max)s, dtype=%(dtype)s)") % d)
555 @property
556 def smallest_normal(self):
557 """Return the value for the smallest normal.
559 Returns
560 -------
561 smallest_normal : float
562 Value for the smallest normal.
564 Warns
565 -----
566 UserWarning
567 If the calculated value for the smallest normal is requested for
568 double-double.
569 """
570 # This check is necessary because the value for smallest_normal is
571 # platform dependent for longdouble types.
572 if isnan(self._machar.smallest_normal.flat[0]):
573 warnings.warn(
574 'The value of smallest normal is undefined for double double',
575 UserWarning, stacklevel=2)
576 return self._machar.smallest_normal.flat[0]
578 @property
579 def tiny(self):
580 """Return the value for tiny, alias of smallest_normal.
582 Returns
583 -------
584 tiny : float
585 Value for the smallest normal, alias of smallest_normal.
587 Warns
588 -----
589 UserWarning
590 If the calculated value for the smallest normal is requested for
591 double-double.
592 """
593 return self.smallest_normal
596@set_module('numpy')
597class iinfo:
598 """
599 iinfo(type)
601 Machine limits for integer types.
603 Attributes
604 ----------
605 bits : int
606 The number of bits occupied by the type.
607 dtype : dtype
608 Returns the dtype for which `iinfo` returns information.
609 min : int
610 The smallest integer expressible by the type.
611 max : int
612 The largest integer expressible by the type.
614 Parameters
615 ----------
616 int_type : integer type, dtype, or instance
617 The kind of integer data type to get information about.
619 See Also
620 --------
621 finfo : The equivalent for floating point data types.
623 Examples
624 --------
625 With types:
627 >>> ii16 = np.iinfo(np.int16)
628 >>> ii16.min
629 -32768
630 >>> ii16.max
631 32767
632 >>> ii32 = np.iinfo(np.int32)
633 >>> ii32.min
634 -2147483648
635 >>> ii32.max
636 2147483647
638 With instances:
640 >>> ii32 = np.iinfo(np.int32(10))
641 >>> ii32.min
642 -2147483648
643 >>> ii32.max
644 2147483647
646 """
648 _min_vals = {}
649 _max_vals = {}
651 def __init__(self, int_type):
652 try:
653 self.dtype = numeric.dtype(int_type)
654 except TypeError:
655 self.dtype = numeric.dtype(type(int_type))
656 self.kind = self.dtype.kind
657 self.bits = self.dtype.itemsize * 8
658 self.key = "%s%d" % (self.kind, self.bits)
659 if self.kind not in 'iu':
660 raise ValueError("Invalid integer data type %r." % (self.kind,))
662 @property
663 def min(self):
664 """Minimum value of given dtype."""
665 if self.kind == 'u':
666 return 0
667 else:
668 try:
669 val = iinfo._min_vals[self.key]
670 except KeyError:
671 val = int(-(1 << (self.bits-1)))
672 iinfo._min_vals[self.key] = val
673 return val
675 @property
676 def max(self):
677 """Maximum value of given dtype."""
678 try:
679 val = iinfo._max_vals[self.key]
680 except KeyError:
681 if self.kind == 'u':
682 val = int((1 << self.bits) - 1)
683 else:
684 val = int((1 << (self.bits-1)) - 1)
685 iinfo._max_vals[self.key] = val
686 return val
688 def __str__(self):
689 """String representation."""
690 fmt = (
691 'Machine parameters for %(dtype)s\n'
692 '---------------------------------------------------------------\n'
693 'min = %(min)s\n'
694 'max = %(max)s\n'
695 '---------------------------------------------------------------\n'
696 )
697 return fmt % {'dtype': self.dtype, 'min': self.min, 'max': self.max}
699 def __repr__(self):
700 return "%s(min=%s, max=%s, dtype=%s)" % (self.__class__.__name__,
701 self.min, self.max, self.dtype)