|
1 | 1 | """ Utilties for casting floats to integers
|
2 | 2 | """
|
3 | 3 |
|
| 4 | +from platform import processor |
| 5 | + |
4 | 6 | import numpy as np
|
5 | 7 |
|
6 | 8 |
|
@@ -165,6 +167,71 @@ class FloatingError(Exception):
|
165 | 167 | pass
|
166 | 168 |
|
167 | 169 |
|
| 170 | +def type_info(np_type): |
| 171 | + """ Return dict with min, max, nexp, nmant, width for numpy type `np_type` |
| 172 | +
|
| 173 | + Type can be integer in which case nexp and nmant are None. |
| 174 | +
|
| 175 | + Parameters |
| 176 | + ---------- |
| 177 | + np_type : numpy type specifier |
| 178 | + Any specifier for a numpy dtype |
| 179 | +
|
| 180 | + Returns |
| 181 | + ------- |
| 182 | + info : dict |
| 183 | + with fields ``min`` (minimum value), ``max`` (maximum value), ``nexp`` |
| 184 | + (exponent width), ``nmant`` (significand precision not including |
| 185 | + implicit first digit) ``width`` (width in bytes). ``nexp``, ``nmant`` |
| 186 | + are None for integer types. |
| 187 | +
|
| 188 | + Raises |
| 189 | + ------ |
| 190 | + FloatingError : for floating point types we don't recognize |
| 191 | +
|
| 192 | + Notes |
| 193 | + ----- |
| 194 | + You might be thinking that ``np.finfo`` does this job, and it does, except |
| 195 | + for PPC long doubles (http://projects.scipy.org/numpy/ticket/2077). This |
| 196 | + routine protects against errors in ``np.finfo`` by only accepting values |
| 197 | + that we know are likely to be correct. |
| 198 | + """ |
| 199 | + dt = np.dtype(np_type) |
| 200 | + width = dt.itemsize |
| 201 | + try: # integer type |
| 202 | + info = np.iinfo(dt) |
| 203 | + except ValueError: |
| 204 | + pass |
| 205 | + else: |
| 206 | + return dict(min=info.min, max=info.max, nmant=None, nexp=None, |
| 207 | + width=width) |
| 208 | + info = np.finfo(dt) |
| 209 | + vals = info.nmant, info.nexp, width |
| 210 | + if vals == (10, 5, 2): # binary16 |
| 211 | + assert dt.type is _float16 |
| 212 | + elif vals == (23, 8, 4): # binary32 |
| 213 | + assert dt.type is np.float32 |
| 214 | + elif vals == (23, 8, 8): # binary32, complex |
| 215 | + assert dt.type is np.complex64 |
| 216 | + elif vals == (52, 11, 8): # binary64 |
| 217 | + assert dt.type in (np.float64, np.longdouble) |
| 218 | + elif vals == (52, 11, 16): # binary64, complex |
| 219 | + assert dt.type is np.complex128 |
| 220 | + elif vals == (112, 15, 16): # binary128 |
| 221 | + assert dt.type is np.longdouble |
| 222 | + elif vals in ((63, 15, 12), (63, 15, 16)): # Intel extended 80 |
| 223 | + assert dt.type is np.longdouble |
| 224 | + elif vals == (1, 1, 16) and processor() == 'powerpc': # broken PPC |
| 225 | + assert dt.type is np.longdouble |
| 226 | + dbl_info = np.finfo(np.float64) |
| 227 | + return dict(min=dbl_info.min, max=dbl_info.max, nmant=106, nexp=11, |
| 228 | + width=width) |
| 229 | + else: # don't recognize the type |
| 230 | + raise FloatingError('We had not expected this type') |
| 231 | + return dict(min=info.min, max=info.max, nmant=info.nmant, nexp=info.nexp, |
| 232 | + width=width) |
| 233 | + |
| 234 | + |
168 | 235 | def flt2nmant(flt_type):
|
169 | 236 | """ Number of significand bits in float type `flt_type`
|
170 | 237 |
|
|
0 commit comments