Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""Machine limits for Float32 and Float64 and (long double) if available... 

2 

3""" 

4__all__ = ['finfo', 'iinfo'] 

5 

6import warnings 

7 

8from .machar import MachAr 

9from .overrides import set_module 

10from . import numeric 

11from . import numerictypes as ntypes 

12from .numeric import array, inf 

13from .umath import log10, exp2 

14from . import umath 

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 

32class MachArLike: 

33 """ Object to simulate MachAr instance """ 

34 

35 def __init__(self, 

36 ftype, 

37 *, eps, epsneg, huge, tiny, ibeta, **kwargs): 

38 params = _MACHAR_PARAMS[ftype] 

39 float_conv = lambda v: array([v], ftype) 

40 float_to_float = lambda v : _fr1(float_conv(v)) 

41 float_to_str = lambda v: (params['fmt'] % array(_fr0(v)[0], ftype)) 

42 

43 self.title = params['title'] 

44 # Parameter types same as for discovered MachAr object. 

45 self.epsilon = self.eps = float_to_float(eps) 

46 self.epsneg = float_to_float(epsneg) 

47 self.xmax = self.huge = float_to_float(huge) 

48 self.xmin = self.tiny = float_to_float(tiny) 

49 self.ibeta = params['itype'](ibeta) 

50 self.__dict__.update(kwargs) 

51 self.precision = int(-log10(self.eps)) 

52 self.resolution = float_to_float(float_conv(10) ** (-self.precision)) 

53 self._str_eps = float_to_str(self.eps) 

54 self._str_epsneg = float_to_str(self.epsneg) 

55 self._str_xmin = float_to_str(self.xmin) 

56 self._str_xmax = float_to_str(self.xmax) 

57 self._str_resolution = float_to_str(self.resolution) 

58 

59_convert_to_float = { 

60 ntypes.csingle: ntypes.single, 

61 ntypes.complex_: ntypes.float_, 

62 ntypes.clongfloat: ntypes.longfloat 

63 } 

64 

65# Parameters for creating MachAr / MachAr-like objects 

66_title_fmt = 'numpy {} precision floating point number' 

67_MACHAR_PARAMS = { 

68 ntypes.double: dict( 

69 itype = ntypes.int64, 

70 fmt = '%24.16e', 

71 title = _title_fmt.format('double')), 

72 ntypes.single: dict( 

73 itype = ntypes.int32, 

74 fmt = '%15.7e', 

75 title = _title_fmt.format('single')), 

76 ntypes.longdouble: dict( 

77 itype = ntypes.longlong, 

78 fmt = '%s', 

79 title = _title_fmt.format('long double')), 

80 ntypes.half: dict( 

81 itype = ntypes.int16, 

82 fmt = '%12.5e', 

83 title = _title_fmt.format('half'))} 

84 

85# Key to identify the floating point type. Key is result of 

86# ftype('-0.1').newbyteorder('<').tobytes() 

87# See: 

88# https://perl5.git.perl.org/perl.git/blob/3118d7d684b56cbeb702af874f4326683c45f045:/Configure 

89_KNOWN_TYPES = {} 

90def _register_type(machar, bytepat): 

91 _KNOWN_TYPES[bytepat] = machar 

92_float_ma = {} 

93 

94def _register_known_types(): 

95 # Known parameters for float16 

96 # See docstring of MachAr class for description of parameters. 

97 f16 = ntypes.float16 

98 float16_ma = MachArLike(f16, 

99 machep=-10, 

100 negep=-11, 

101 minexp=-14, 

102 maxexp=16, 

103 it=10, 

104 iexp=5, 

105 ibeta=2, 

106 irnd=5, 

107 ngrd=0, 

108 eps=exp2(f16(-10)), 

109 epsneg=exp2(f16(-11)), 

110 huge=f16(65504), 

111 tiny=f16(2 ** -14)) 

112 _register_type(float16_ma, b'f\xae') 

113 _float_ma[16] = float16_ma 

114 

115 # Known parameters for float32 

116 f32 = ntypes.float32 

117 float32_ma = MachArLike(f32, 

118 machep=-23, 

119 negep=-24, 

120 minexp=-126, 

121 maxexp=128, 

122 it=23, 

123 iexp=8, 

124 ibeta=2, 

125 irnd=5, 

126 ngrd=0, 

127 eps=exp2(f32(-23)), 

128 epsneg=exp2(f32(-24)), 

129 huge=f32((1 - 2 ** -24) * 2**128), 

130 tiny=exp2(f32(-126))) 

131 _register_type(float32_ma, b'\xcd\xcc\xcc\xbd') 

132 _float_ma[32] = float32_ma 

133 

134 # Known parameters for float64 

135 f64 = ntypes.float64 

136 epsneg_f64 = 2.0 ** -53.0 

137 tiny_f64 = 2.0 ** -1022.0 

138 float64_ma = MachArLike(f64, 

139 machep=-52, 

140 negep=-53, 

141 minexp=-1022, 

142 maxexp=1024, 

143 it=52, 

144 iexp=11, 

145 ibeta=2, 

146 irnd=5, 

147 ngrd=0, 

148 eps=2.0 ** -52.0, 

149 epsneg=epsneg_f64, 

150 huge=(1.0 - epsneg_f64) / tiny_f64 * f64(4), 

151 tiny=tiny_f64) 

152 _register_type(float64_ma, b'\x9a\x99\x99\x99\x99\x99\xb9\xbf') 

153 _float_ma[64] = float64_ma 

154 

155 # Known parameters for IEEE 754 128-bit binary float 

156 ld = ntypes.longdouble 

157 epsneg_f128 = exp2(ld(-113)) 

158 tiny_f128 = exp2(ld(-16382)) 

159 # Ignore runtime error when this is not f128 

160 with numeric.errstate(all='ignore'): 

161 huge_f128 = (ld(1) - epsneg_f128) / tiny_f128 * ld(4) 

162 float128_ma = MachArLike(ld, 

163 machep=-112, 

164 negep=-113, 

165 minexp=-16382, 

166 maxexp=16384, 

167 it=112, 

168 iexp=15, 

169 ibeta=2, 

170 irnd=5, 

171 ngrd=0, 

172 eps=exp2(ld(-112)), 

173 epsneg=epsneg_f128, 

174 huge=huge_f128, 

175 tiny=tiny_f128) 

176 # IEEE 754 128-bit binary float 

177 _register_type(float128_ma, 

178 b'\x9a\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xfb\xbf') 

179 _register_type(float128_ma, 

180 b'\x9a\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xfb\xbf') 

181 _float_ma[128] = float128_ma 

182 

183 # Known parameters for float80 (Intel 80-bit extended precision) 

184 epsneg_f80 = exp2(ld(-64)) 

185 tiny_f80 = exp2(ld(-16382)) 

186 # Ignore runtime error when this is not f80 

187 with numeric.errstate(all='ignore'): 

188 huge_f80 = (ld(1) - epsneg_f80) / tiny_f80 * ld(4) 

189 float80_ma = MachArLike(ld, 

190 machep=-63, 

191 negep=-64, 

192 minexp=-16382, 

193 maxexp=16384, 

194 it=63, 

195 iexp=15, 

196 ibeta=2, 

197 irnd=5, 

198 ngrd=0, 

199 eps=exp2(ld(-63)), 

200 epsneg=epsneg_f80, 

201 huge=huge_f80, 

202 tiny=tiny_f80) 

203 # float80, first 10 bytes containing actual storage 

204 _register_type(float80_ma, b'\xcd\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xfb\xbf') 

205 _float_ma[80] = float80_ma 

206 

207 # Guessed / known parameters for double double; see: 

208 # https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format#Double-double_arithmetic 

209 # These numbers have the same exponent range as float64, but extended number of 

210 # digits in the significand. 

211 huge_dd = (umath.nextafter(ld(inf), ld(0)) 

212 if hasattr(umath, 'nextafter') # Missing on some platforms? 

213 else float64_ma.huge) 

214 float_dd_ma = MachArLike(ld, 

215 machep=-105, 

216 negep=-106, 

217 minexp=-1022, 

218 maxexp=1024, 

219 it=105, 

220 iexp=11, 

221 ibeta=2, 

222 irnd=5, 

223 ngrd=0, 

224 eps=exp2(ld(-105)), 

225 epsneg= exp2(ld(-106)), 

226 huge=huge_dd, 

227 tiny=exp2(ld(-1022))) 

228 # double double; low, high order (e.g. PPC 64) 

229 _register_type(float_dd_ma, 

230 b'\x9a\x99\x99\x99\x99\x99Y<\x9a\x99\x99\x99\x99\x99\xb9\xbf') 

231 # double double; high, low order (e.g. PPC 64 le) 

232 _register_type(float_dd_ma, 

233 b'\x9a\x99\x99\x99\x99\x99\xb9\xbf\x9a\x99\x99\x99\x99\x99Y<') 

234 _float_ma['dd'] = float_dd_ma 

235 

236 

237def _get_machar(ftype): 

238 """ Get MachAr instance or MachAr-like instance 

239 

240 Get parameters for floating point type, by first trying signatures of 

241 various known floating point types, then, if none match, attempting to 

242 identify parameters by analysis. 

243 

244 Parameters 

245 ---------- 

246 ftype : class 

247 Numpy floating point type class (e.g. ``np.float64``) 

248 

249 Returns 

250 ------- 

251 ma_like : instance of :class:`MachAr` or :class:`MachArLike` 

252 Object giving floating point parameters for `ftype`. 

253 

254 Warns 

255 ----- 

256 UserWarning 

257 If the binary signature of the float type is not in the dictionary of 

258 known float types. 

259 """ 

260 params = _MACHAR_PARAMS.get(ftype) 

261 if params is None: 

262 raise ValueError(repr(ftype)) 

263 # Detect known / suspected types 

264 key = ftype('-0.1').newbyteorder('<').tobytes() 

265 ma_like = _KNOWN_TYPES.get(key) 

266 # Could be 80 bit == 10 byte extended precision, where last bytes can be 

267 # random garbage. Try comparing first 10 bytes to pattern. 

268 if ma_like is None and ftype == ntypes.longdouble: 

269 ma_like = _KNOWN_TYPES.get(key[:10]) 

270 if ma_like is not None: 

271 return ma_like 

272 # Fall back to parameter discovery 

273 warnings.warn( 

274 'Signature {} for {} does not match any known type: ' 

275 'falling back to type probe function'.format(key, ftype), 

276 UserWarning, stacklevel=2) 

277 return _discovered_machar(ftype) 

278 

279 

280def _discovered_machar(ftype): 

281 """ Create MachAr instance with found information on float types 

282 """ 

283 params = _MACHAR_PARAMS[ftype] 

284 return MachAr(lambda v: array([v], ftype), 

285 lambda v:_fr0(v.astype(params['itype']))[0], 

286 lambda v:array(_fr0(v)[0], ftype), 

287 lambda v: params['fmt'] % array(_fr0(v)[0], ftype), 

288 params['title']) 

289 

290 

291@set_module('numpy') 

292class finfo: 

293 """ 

294 finfo(dtype) 

295 

296 Machine limits for floating point types. 

297 

298 Attributes 

299 ---------- 

300 bits : int 

301 The number of bits occupied by the type. 

302 eps : float 

303 The difference between 1.0 and the next smallest representable float 

304 larger than 1.0. For example, for 64-bit binary floats in the IEEE-754 

305 standard, ``eps = 2**-52``, approximately 2.22e-16. 

306 epsneg : float 

307 The difference between 1.0 and the next smallest representable float 

308 less than 1.0. For example, for 64-bit binary floats in the IEEE-754 

309 standard, ``epsneg = 2**-53``, approximately 1.11e-16. 

310 iexp : int 

311 The number of bits in the exponent portion of the floating point 

312 representation. 

313 machar : MachAr 

314 The object which calculated these parameters and holds more 

315 detailed information. 

316 machep : int 

317 The exponent that yields `eps`. 

318 max : floating point number of the appropriate type 

319 The largest representable number. 

320 maxexp : int 

321 The smallest positive power of the base (2) that causes overflow. 

322 min : floating point number of the appropriate type 

323 The smallest representable number, typically ``-max``. 

324 minexp : int 

325 The most negative power of the base (2) consistent with there 

326 being no leading 0's in the mantissa. 

327 negep : int 

328 The exponent that yields `epsneg`. 

329 nexp : int 

330 The number of bits in the exponent including its sign and bias. 

331 nmant : int 

332 The number of bits in the mantissa. 

333 precision : int 

334 The approximate number of decimal digits to which this kind of 

335 float is precise. 

336 resolution : floating point number of the appropriate type 

337 The approximate decimal resolution of this type, i.e., 

338 ``10**-precision``. 

339 tiny : float 

340 The smallest positive usable number. Type of `tiny` is an 

341 appropriate floating point type. 

342 

343 Parameters 

344 ---------- 

345 dtype : float, dtype, or instance 

346 Kind of floating point data-type about which to get information. 

347 

348 See Also 

349 -------- 

350 MachAr : The implementation of the tests that produce this information. 

351 iinfo : The equivalent for integer data types. 

352 spacing : The distance between a value and the nearest adjacent number 

353 nextafter : The next floating point value after x1 towards x2 

354 

355 Notes 

356 ----- 

357 For developers of NumPy: do not instantiate this at the module level. 

358 The initial calculation of these parameters is expensive and negatively 

359 impacts import times. These objects are cached, so calling ``finfo()`` 

360 repeatedly inside your functions is not a problem. 

361 

362 """ 

363 

364 _finfo_cache = {} 

365 

366 def __new__(cls, dtype): 

367 try: 

368 dtype = numeric.dtype(dtype) 

369 except TypeError: 

370 # In case a float instance was given 

371 dtype = numeric.dtype(type(dtype)) 

372 

373 obj = cls._finfo_cache.get(dtype, None) 

374 if obj is not None: 

375 return obj 

376 dtypes = [dtype] 

377 newdtype = numeric.obj2sctype(dtype) 

378 if newdtype is not dtype: 

379 dtypes.append(newdtype) 

380 dtype = newdtype 

381 if not issubclass(dtype, numeric.inexact): 

382 raise ValueError("data type %r not inexact" % (dtype)) 

383 obj = cls._finfo_cache.get(dtype, None) 

384 if obj is not None: 

385 return obj 

386 if not issubclass(dtype, numeric.floating): 

387 newdtype = _convert_to_float[dtype] 

388 if newdtype is not dtype: 

389 dtypes.append(newdtype) 

390 dtype = newdtype 

391 obj = cls._finfo_cache.get(dtype, None) 

392 if obj is not None: 

393 return obj 

394 obj = object.__new__(cls)._init(dtype) 

395 for dt in dtypes: 

396 cls._finfo_cache[dt] = obj 

397 return obj 

398 

399 def _init(self, dtype): 

400 self.dtype = numeric.dtype(dtype) 

401 machar = _get_machar(dtype) 

402 

403 for word in ['precision', 'iexp', 

404 'maxexp', 'minexp', 'negep', 

405 'machep']: 

406 setattr(self, word, getattr(machar, word)) 

407 for word in ['tiny', 'resolution', 'epsneg']: 

408 setattr(self, word, getattr(machar, word).flat[0]) 

409 self.bits = self.dtype.itemsize * 8 

410 self.max = machar.huge.flat[0] 

411 self.min = -self.max 

412 self.eps = machar.eps.flat[0] 

413 self.nexp = machar.iexp 

414 self.nmant = machar.it 

415 self.machar = machar 

416 self._str_tiny = machar._str_xmin.strip() 

417 self._str_max = machar._str_xmax.strip() 

418 self._str_epsneg = machar._str_epsneg.strip() 

419 self._str_eps = machar._str_eps.strip() 

420 self._str_resolution = machar._str_resolution.strip() 

421 return self 

422 

423 def __str__(self): 

424 fmt = ( 

425 'Machine parameters for %(dtype)s\n' 

426 '---------------------------------------------------------------\n' 

427 'precision = %(precision)3s resolution = %(_str_resolution)s\n' 

428 'machep = %(machep)6s eps = %(_str_eps)s\n' 

429 'negep = %(negep)6s epsneg = %(_str_epsneg)s\n' 

430 'minexp = %(minexp)6s tiny = %(_str_tiny)s\n' 

431 'maxexp = %(maxexp)6s max = %(_str_max)s\n' 

432 'nexp = %(nexp)6s min = -max\n' 

433 '---------------------------------------------------------------\n' 

434 ) 

435 return fmt % self.__dict__ 

436 

437 def __repr__(self): 

438 c = self.__class__.__name__ 

439 d = self.__dict__.copy() 

440 d['klass'] = c 

441 return (("%(klass)s(resolution=%(resolution)s, min=-%(_str_max)s," 

442 " max=%(_str_max)s, dtype=%(dtype)s)") % d) 

443 

444 

445@set_module('numpy') 

446class iinfo: 

447 """ 

448 iinfo(type) 

449 

450 Machine limits for integer types. 

451 

452 Attributes 

453 ---------- 

454 bits : int 

455 The number of bits occupied by the type. 

456 min : int 

457 The smallest integer expressible by the type. 

458 max : int 

459 The largest integer expressible by the type. 

460 

461 Parameters 

462 ---------- 

463 int_type : integer type, dtype, or instance 

464 The kind of integer data type to get information about. 

465 

466 See Also 

467 -------- 

468 finfo : The equivalent for floating point data types. 

469 

470 Examples 

471 -------- 

472 With types: 

473 

474 >>> ii16 = np.iinfo(np.int16) 

475 >>> ii16.min 

476 -32768 

477 >>> ii16.max 

478 32767 

479 >>> ii32 = np.iinfo(np.int32) 

480 >>> ii32.min 

481 -2147483648 

482 >>> ii32.max 

483 2147483647 

484 

485 With instances: 

486 

487 >>> ii32 = np.iinfo(np.int32(10)) 

488 >>> ii32.min 

489 -2147483648 

490 >>> ii32.max 

491 2147483647 

492 

493 """ 

494 

495 _min_vals = {} 

496 _max_vals = {} 

497 

498 def __init__(self, int_type): 

499 try: 

500 self.dtype = numeric.dtype(int_type) 

501 except TypeError: 

502 self.dtype = numeric.dtype(type(int_type)) 

503 self.kind = self.dtype.kind 

504 self.bits = self.dtype.itemsize * 8 

505 self.key = "%s%d" % (self.kind, self.bits) 

506 if self.kind not in 'iu': 

507 raise ValueError("Invalid integer data type %r." % (self.kind,)) 

508 

509 @property 

510 def min(self): 

511 """Minimum value of given dtype.""" 

512 if self.kind == 'u': 

513 return 0 

514 else: 

515 try: 

516 val = iinfo._min_vals[self.key] 

517 except KeyError: 

518 val = int(-(1 << (self.bits-1))) 

519 iinfo._min_vals[self.key] = val 

520 return val 

521 

522 @property 

523 def max(self): 

524 """Maximum value of given dtype.""" 

525 try: 

526 val = iinfo._max_vals[self.key] 

527 except KeyError: 

528 if self.kind == 'u': 

529 val = int((1 << self.bits) - 1) 

530 else: 

531 val = int((1 << (self.bits-1)) - 1) 

532 iinfo._max_vals[self.key] = val 

533 return val 

534 

535 def __str__(self): 

536 """String representation.""" 

537 fmt = ( 

538 'Machine parameters for %(dtype)s\n' 

539 '---------------------------------------------------------------\n' 

540 'min = %(min)s\n' 

541 'max = %(max)s\n' 

542 '---------------------------------------------------------------\n' 

543 ) 

544 return fmt % {'dtype': self.dtype, 'min': self.min, 'max': self.max} 

545 

546 def __repr__(self): 

547 return "%s(min=%s, max=%s, dtype=%s)" % (self.__class__.__name__, 

548 self.min, self.max, self.dtype) 

549