summaryrefslogtreecommitdiff
path: root/numpy/lib/getlimits.py
blob: 41030af2d053f0b877824e3390104e33e76036f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
""" Machine limits for Float32 and Float64 and (long double) if available...
"""

__all__ = ['finfo']

from machar import MachAr
import numeric
from numeric import array

def _frz(a):
    """fix rank-0 --> rank-1"""
    if a.ndim == 0: a.shape = (1,)
    return a

_convert_to_float = {
    numeric.csingle: numeric.single,
    numeric.complex_: numeric.float_,
    numeric.clongfloat: numeric.longfloat
    }

class finfo(object):

    _finfo_cache = {}

    def __new__(cls, dtype):
        obj = cls._finfo_cache.get(dtype,None)
        if obj is not None:
            return obj
        dtypes = [dtype]
        newdtype = numeric.obj2dtype(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 numeric.float_:
            machar = MachAr(lambda v:array([v],'d'),
                            lambda v:_frz(v.astype('i'))[0],
                            lambda v:array(_frz(v)[0],'d'),
                            lambda v:'%24.16e' % array(_frz(v)[0],'d'),
                            'scipy float precision floating point '\
                            'number')
        elif dtype is numeric.single:
            machar =  MachAr(lambda v:array([v],'f'),
                             lambda v:_frz(v.astype('i'))[0],
                             lambda v:array(_frz(v)[0],'f'),  #
                             lambda v:'%15.7e' % array(_frz(v)[0],'f'),
                             "scipy single precision floating "\
                             "point number")
        elif dtype is numeric.longfloat:
            machar = MachAr(lambda v:array([v],'g'),
                            lambda v:_frz(v.astype('i'))[0],
                            lambda v:array(_frz(v)[0],'g'),  #
                            lambda v:str(array(_frz(v)[0],'g')),
                            "scipy longfloat precision floating "\
                            "point number")
        else:
            raise ValueError,`dtype`

        for word in ['tiny', 'precision', 'resolution','iexp',
                     'maxexp','minexp','epsneg','negep',
                     'machep']:
            setattr(self,word,getattr(machar, word))
        self.max = machar.huge
        self.min = -self.max
        self.eps = machar.epsilon
        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__

if __name__ == '__main__':
    f = finfo(numeric.single)
    print 'single epsilon:',f.eps
    print 'single tiny:',f.tiny
    f = finfo(numeric.float)
    print 'float epsilon:',f.eps
    print 'float tiny:',f.tiny
    f = finfo(numeric.longfloat)
    print 'longfloat epsilon:',f.eps
    print 'longfloat tiny:',f.tiny