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