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