summaryrefslogtreecommitdiff
path: root/numpy/lib/getlimits.py
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/lib/getlimits.py')
-rw-r--r--numpy/lib/getlimits.py268
1 files changed, 268 insertions, 0 deletions
diff --git a/numpy/lib/getlimits.py b/numpy/lib/getlimits.py
new file mode 100644
index 000000000..bc5fbbf5e
--- /dev/null
+++ b/numpy/lib/getlimits.py
@@ -0,0 +1,268 @@
+""" Machine limits for Float32 and Float64 and (long double) if available...
+"""
+
+__all__ = ['finfo','iinfo']
+
+from machar import MachAr
+import numpy.core.numeric as numeric
+import numpy.core.numerictypes as ntypes
+from numpy.core.numeric import array
+import numpy as np
+
+def _frz(a):
+ """fix rank-0 --> rank-1"""
+ if a.ndim == 0: a.shape = (1,)
+ return a
+
+_convert_to_float = {
+ ntypes.csingle: ntypes.single,
+ ntypes.complex_: ntypes.float_,
+ ntypes.clongfloat: ntypes.longfloat
+ }
+
+class finfo(object):
+ """
+ finfo(dtype)
+
+ Machine limits for floating point types.
+
+ Attributes
+ ----------
+ eps : floating point number of the appropriate type
+ The smallest representable number such that ``1.0 + eps != 1.0``.
+ epsneg : floating point number of the appropriate type
+ The smallest representable number such that ``1.0 - epsneg != 1.0``.
+ iexp : int
+ The number of bits in the exponent portion of the floating point
+ representation.
+ machar : MachAr
+ The object which calculated these parameters and holds more detailed
+ information.
+ machep : int
+ The exponent that yields ``eps``.
+ max : floating point number of the appropriate type
+ The largest representable number.
+ maxexp : int
+ The smallest positive power of the base (2) that causes overflow.
+ min : floating point number of the appropriate type
+ The smallest representable number, typically ``-max``.
+ minexp : int
+ The most negative power of the base (2) consistent with there being
+ no leading 0s in the mantissa.
+ negep : int
+ The exponent that yields ``epsneg``.
+ nexp : int
+ The number of bits in the exponent including its sign and bias.
+ nmant : int
+ The number of bits in the mantissa.
+ precision : int
+ The approximate number of decimal digits to which this kind of float
+ is precise.
+ resolution : floating point number of the appropriate type
+ The approximate decimal resolution of this type, i.e.
+ ``10**-precision``.
+ tiny : floating point number of the appropriate type
+ The smallest-magnitude usable number.
+
+ Parameters
+ ----------
+ dtype : floating point type, dtype, or instance
+ The kind of floating point data type to get information about.
+
+ See Also
+ --------
+ numpy.lib.machar.MachAr :
+ The implementation of the tests that produce this information.
+ iinfo :
+ The equivalent for integer data types.
+
+ Notes
+ -----
+ For developers of numpy: do not instantiate this at the module level. The
+ initial calculation of these parameters is expensive and negatively impacts
+ import times. These objects are cached, so calling ``finfo()`` repeatedly
+ inside your functions is not a problem.
+
+ """
+
+ _finfo_cache = {}
+
+ def __new__(cls, dtype):
+ obj = cls._finfo_cache.get(dtype,None)
+ if obj is not None:
+ return obj
+ dtypes = [dtype]
+ newdtype = numeric.obj2sctype(dtype)
+ if newdtype is not dtype:
+ dtypes.append(newdtype)
+ dtype = newdtype
+ if not issubclass(dtype, numeric.inexact):
+ raise ValueError, "data type %r not inexact" % (dtype)
+ obj = cls._finfo_cache.get(dtype,None)
+ if obj is not None:
+ return obj
+ if not issubclass(dtype, numeric.floating):
+ newdtype = _convert_to_float[dtype]
+ if newdtype is not dtype:
+ dtypes.append(newdtype)
+ dtype = newdtype
+ obj = cls._finfo_cache.get(dtype,None)
+ if obj is not None:
+ return obj
+ obj = object.__new__(cls)._init(dtype)
+ for dt in dtypes:
+ cls._finfo_cache[dt] = obj
+ return obj
+
+ def _init(self, dtype):
+ self.dtype = dtype
+ if dtype is ntypes.double:
+ itype = ntypes.int64
+ fmt = '%24.16e'
+ precname = 'double'
+ elif dtype is ntypes.single:
+ itype = ntypes.int32
+ fmt = '%15.7e'
+ precname = 'single'
+ elif dtype is ntypes.longdouble:
+ itype = ntypes.longlong
+ fmt = '%s'
+ precname = 'long double'
+ else:
+ raise ValueError, repr(dtype)
+
+ machar = MachAr(lambda v:array([v], dtype),
+ lambda v:_frz(v.astype(itype))[0],
+ lambda v:array(_frz(v)[0], dtype),
+ lambda v: fmt % array(_frz(v)[0], dtype),
+ 'numpy %s precision floating point number' % precname)
+
+ for word in ['precision', 'iexp',
+ 'maxexp','minexp','negep',
+ 'machep']:
+ setattr(self,word,getattr(machar, word))
+ for word in ['tiny','resolution','epsneg']:
+ setattr(self,word,getattr(machar, word).squeeze())
+ self.max = machar.huge.flat[0]
+ self.min = -self.max
+ self.eps = machar.eps.flat[0]
+ self.nexp = machar.iexp
+ self.nmant = machar.it
+ self.machar = machar
+ self._str_tiny = machar._str_xmin
+ self._str_max = machar._str_xmax
+ self._str_epsneg = machar._str_epsneg
+ self._str_eps = machar._str_eps
+ self._str_resolution = machar._str_resolution
+ return self
+
+ def __str__(self):
+ return '''\
+Machine parameters for %(dtype)s
+---------------------------------------------------------------------
+precision=%(precision)3s resolution=%(_str_resolution)s
+machep=%(machep)6s eps= %(_str_eps)s
+negep =%(negep)6s epsneg= %(_str_epsneg)s
+minexp=%(minexp)6s tiny= %(_str_tiny)s
+maxexp=%(maxexp)6s max= %(_str_max)s
+nexp =%(nexp)6s min= -max
+---------------------------------------------------------------------
+''' % self.__dict__
+
+
+class iinfo:
+ """
+ iinfo(type)
+
+ Machine limits for integer types.
+
+ Attributes
+ ----------
+ min : int
+ The smallest integer expressible by the type.
+ max : int
+ The largest integer expressible by the type.
+
+ Parameters
+ ----------
+ type : integer type, dtype, or instance
+ The kind of integer data type to get information about.
+
+ See Also
+ --------
+ finfo : The equivalent for floating point data types.
+
+ Examples
+ --------
+ With types:
+
+ >>> ii16 = np.iinfo(np.int16)
+ >>> ii16.min
+ -32768
+ >>> ii16.max
+ 32767
+ >>> ii32 = np.iinfo(np.int32)
+ >>> ii32.min
+ -2147483648
+ >>> ii32.max
+ 2147483647
+
+ With instances:
+
+ >>> ii32 = np.iinfo(np.int32(10))
+ >>> ii32.min
+ -2147483648
+ >>> ii32.max
+ 2147483647
+
+ """
+
+ _min_vals = {}
+ _max_vals = {}
+
+ def __init__(self, type):
+ self.dtype = np.dtype(type)
+ self.kind = self.dtype.kind
+ self.bits = self.dtype.itemsize * 8
+ self.key = "%s%d" % (self.kind, self.bits)
+ if not self.kind in 'iu':
+ raise ValueError("Invalid integer data type.")
+
+ def min(self):
+ """Minimum value of given dtype."""
+ if self.kind == 'u':
+ return 0
+ else:
+ try:
+ val = iinfo._min_vals[self.key]
+ except KeyError:
+ val = int(-(1L << (self.bits-1)))
+ iinfo._min_vals[self.key] = val
+ return val
+
+ min = property(min)
+
+ def max(self):
+ """Maximum value of given dtype."""
+ try:
+ val = iinfo._max_vals[self.key]
+ except KeyError:
+ if self.kind == 'u':
+ val = int((1L << self.bits) - 1)
+ else:
+ val = int((1L << (self.bits-1)) - 1)
+ iinfo._max_vals[self.key] = val
+ return val
+
+ max = property(max)
+
+if __name__ == '__main__':
+ f = finfo(ntypes.single)
+ print 'single epsilon:',f.eps
+ print 'single tiny:',f.tiny
+ f = finfo(ntypes.float)
+ print 'float epsilon:',f.eps
+ print 'float tiny:',f.tiny
+ f = finfo(ntypes.longfloat)
+ print 'longfloat epsilon:',f.eps
+ print 'longfloat tiny:',f.tiny