casting
¶
Utilities for casting numpy values in various ways
Most routines work round some numpy oddities in floating point precision and casting. Others work round numpy casting to and from python ints
|
Find the smallest integer numpy type to contain sequence values |
|
Return python integer representation of number |
Floating point type with best precision |
|
|
Return nearest exact integer >= val in float type flt_type |
|
Convert floating point array arr to type int_type |
|
Return nearest exact integer <= val in float type flt_type |
|
floor of log2 of abs(x) |
True if we have a binary128 IEEE longdouble |
|
|
Absolute values of array taking care of max negative int values |
|
Convert integer val to floating point type flt_type |
Return True if longdouble appears to have the same precision as float64 |
|
True if longdouble precision increased since initial import |
|
Return floating point types sorted by precision |
|
True if we are running on a Power PC platform |
|
|
Min and max in float type that are >=min, <=max in integer type |
|
Return dict with min, max, nexp, nmant, width for numpy type np_type |
|
Return gap between val and nearest representable number of same type |
CastingError
¶
FloatingError
¶
able_int_type¶
- nibabel.casting.able_int_type(values)¶
Find the smallest integer numpy type to contain sequence values
Prefers uint to int if minimum is >= 0
- Parameters:
- valuessequence
sequence of integer values
- Returns:
- itypeNone or numpy type
numpy integer type or None if no integer type holds all values
Examples
>>> able_int_type([0, 1]) == np.uint8 True >>> able_int_type([-1, 1]) == np.int8 True
as_int¶
- nibabel.casting.as_int(x, check=True)¶
Return python integer representation of number
This is useful because the numpy int(val) mechanism is broken for large values in np.longdouble.
It is also useful to work around a numpy 1.4.1 bug in conversion of uints to python ints.
This routine will still raise an OverflowError for values that are outside the range of float64.
- Parameters:
- xobject
integer, unsigned integer or floating point value
- check{True, False}
If True, raise error for values that are not integers
- Returns:
- iint
Python integer
Examples
>>> as_int(2.0) 2 >>> as_int(-2.0) -2 >>> as_int(2.1) Traceback (most recent call last): ... FloatingError: Not an integer: 2.1 >>> as_int(2.1, check=False) 2
best_float¶
- nibabel.casting.best_float()¶
Floating point type with best precision
This is nearly always np.longdouble, except on Windows, where np.longdouble is Intel80 storage, but with float64 precision for calculations. In that case we return float64 on the basis it’s the fastest and smallest at the highest precision.
SPARC float128 also proved so slow that we prefer float64.
- Returns:
- best_typenumpy type
floating point type with highest precision
Notes
Needs to run without error for module import, because it is called in
ok_floats
below, and therefore in setting module globalOK_FLOATS
.
ceil_exact¶
- nibabel.casting.ceil_exact(val, flt_type)¶
Return nearest exact integer >= val in float type flt_type
- Parameters:
- valint
We have to pass val as an int rather than the floating point type because large integers cast as floating point may be rounded by the casting process.
- flt_typenumpy type
numpy float type.
- Returns:
- ceil_valobject
value of same floating point type as val, that is the nearest exact integer in this type such that floor_val >= val. Thus if val is exact in flt_type, ceil_val == val.
Examples
Obviously 2 is within the range of representable integers for float32
>>> ceil_exact(2, np.float32) 2.0
As is 2**24-1 (the number of significand digits is 23 + 1 implicit)
>>> ceil_exact(2**24-1, np.float32) == 2**24-1 True
But 2**24+1 gives a number that float32 can’t represent exactly
>>> ceil_exact(2**24+1, np.float32) == 2**24+2 True
As for the numpy ceil function, negatives ceil towards inf
>>> ceil_exact(-2**24-1, np.float32) == -2**24 True
float_to_int¶
- nibabel.casting.float_to_int(arr, int_type, nan2zero=True, infmax=False)¶
Convert floating point array arr to type int_type
Rounds numbers to nearest integer
Clips values to prevent overflows when casting
Converts NaN to 0 (for nan2zero == True)
Casting floats to integers is delicate because the result is undefined and platform specific for float values outside the range of int_type. Define
shared_min
to be the minimum value that can be exactly represented in both the float type of arr and int_type. Define shared_max to be the equivalent maximum value. To avoid undefined results we threshold arr atshared_min
andshared_max
.- Parameters:
- arrarray-like
Array of floating point type
- int_typeobject
Numpy integer type
- nan2zero{True, False, None}
Whether to convert NaN value to zero. Default is True. If False, and NaNs are present, raise CastingError. If None, do not check for NaN values and pass through directly to the
astype
casting mechanism. In this last case, the resulting value is undefined.- infmax{False, True}
If True, set np.inf values in arr to be int_type integer maximum value, -np.inf as int_type integer minimum. If False, set +/- infs to be
shared_min
,shared_max
as defined above. Therefore False gives faster conversion at the expense of infs that are further from infinity.
- Returns:
- iarrndarray
of type int_type
Notes
Numpy relies on the C library to cast from float to int using the standard
astype
method of the array.Quoting from section F4 of the C99 standard:
If the floating value is infinite or NaN or if the integral part of the floating value exceeds the range of the integer type, then the “invalid” floating-point exception is raised and the resulting value is unspecified.
Hence we threshold at
shared_min
andshared_max
to avoid casting to values that are undefined.See: https://en.wikipedia.org/wiki/C99 . There are links to the C99 standard from that page.
Examples
>>> float_to_int([np.nan, np.inf, -np.inf, 1.1, 6.6], np.int16) array([ 0, 32767, -32768, 1, 7], dtype=int16)
floor_exact¶
- nibabel.casting.floor_exact(val, flt_type)¶
Return nearest exact integer <= val in float type flt_type
- Parameters:
- valint
We have to pass val as an int rather than the floating point type because large integers cast as floating point may be rounded by the casting process.
- flt_typenumpy type
numpy float type.
- Returns:
- floor_valobject
value of same floating point type as val, that is the nearest exact integer in this type such that floor_val <= val. Thus if val is exact in flt_type, floor_val == val.
Examples
Obviously 2 is within the range of representable integers for float32
>>> floor_exact(2, np.float32) 2.0
As is 2**24-1 (the number of significand digits is 23 + 1 implicit)
>>> floor_exact(2**24-1, np.float32) == 2**24-1 True
But 2**24+1 gives a number that float32 can’t represent exactly
>>> floor_exact(2**24+1, np.float32) == 2**24 True
As for the numpy floor function, negatives floor towards -inf
>>> floor_exact(-2**24-1, np.float32) == -2**24-2 True
floor_log2¶
- nibabel.casting.floor_log2(x)¶
floor of log2 of abs(x)
Embarrassingly, from https://en.wikipedia.org/wiki/Binary_logarithm
- Parameters:
- xint
- Returns:
- LNone or int
floor of base 2 log of x. None if x == 0.
Examples
>>> floor_log2(2**9+1) 9 >>> floor_log2(-2**9+1) 8 >>> floor_log2(0.5) -1 >>> floor_log2(0) is None True
have_binary128¶
- nibabel.casting.have_binary128()¶
True if we have a binary128 IEEE longdouble
int_abs¶
- nibabel.casting.int_abs(arr)¶
Absolute values of array taking care of max negative int values
- Parameters:
- arrarray-like
- Returns:
- abs_arrarray
array the same shape as arr in which all negative numbers have been changed to positive numbers with the magnitude.
Examples
This kind of thing is confusing in base numpy:
>>> import numpy as np >>> np.abs(np.int8(-128)) -128
int_abs
fixes that:>>> int_abs(np.int8(-128)) 128 >>> int_abs(np.array([-128, 127], dtype=np.int8)) array([128, 127], dtype=uint8) >>> int_abs(np.array([-128, 127], dtype=np.float32)) array([128., 127.], dtype=float32)
int_to_float¶
- nibabel.casting.int_to_float(val, flt_type)¶
Convert integer val to floating point type flt_type
Why is this so complicated?
At least in numpy <= 1.6.1, numpy longdoubles do not correctly convert to ints, and ints do not correctly convert to longdoubles. Specifically, in both cases, the values seem to go through float64 conversion on the way, so to convert better, we need to split into float64s and sum up the result.
- Parameters:
- valint
Integer value
- flt_typeobject
numpy floating point type
- Returns:
- fnumpy scalar
of type flt_type
longdouble_lte_float64¶
- nibabel.casting.longdouble_lte_float64()¶
Return True if longdouble appears to have the same precision as float64
longdouble_precision_improved¶
- nibabel.casting.longdouble_precision_improved()¶
True if longdouble precision increased since initial import
This can happen on Windows compiled with MSVC. It may be because libraries compiled with mingw (longdouble is Intel80) get linked to numpy compiled with MSVC (longdouble is Float64)
ok_floats¶
- nibabel.casting.ok_floats()¶
Return floating point types sorted by precision
Remove longdouble if it has no higher precision than float64
on_powerpc¶
- nibabel.casting.on_powerpc()¶
True if we are running on a Power PC platform
Has to deal with older Macs and IBM POWER7 series among others
type_info¶
- nibabel.casting.type_info(np_type)¶
Return dict with min, max, nexp, nmant, width for numpy type np_type
Type can be integer in which case nexp and nmant are None.
- Parameters:
- np_typenumpy type specifier
Any specifier for a numpy dtype
- Returns:
- infodict
with fields
min
(minimum value),max
(maximum value),nexp
(exponent width),nmant
(significand precision not including implicit first digit),minexp
(minimum exponent),maxexp
(maximum exponent),width
(width in bytes). (nexp
,nmant
,minexp
,maxexp
) are None for integer types. Bothmin
andmax
are of type np_type.
- Raises:
- FloatingError
for floating point types we don’t recognize
Notes
You might be thinking that
np.finfo
does this job, and it does, except for PPC long doubles (https://github.com/numpy/numpy/issues/2669) and float96 on Windows compiled with Mingw. This routine protects against such errors innp.finfo
by only accepting values that we know are likely to be correct.
ulp¶
- nibabel.casting.ulp(val=1.0)¶
Return gap between val and nearest representable number of same type
This is the value of a unit in the last place (ULP), and is similar in meaning to the MATLAB eps function.
- Parameters:
- valscalar, optional
scalar value of any numpy type. Default is 1.0 (float64)
- Returns:
- ulp_valscalar
gap between val and nearest representable number of same type
Notes
The wikipedia article on machine epsilon points out that the term epsilon can be used in the sense of a unit in the last place (ULP), or as the maximum relative rounding error. The MATLAB
eps
function uses the ULP meaning, but this function isulp
rather thaneps
to avoid confusion between different meanings of eps.