# NiBabel

### Access a cacophony of neuro-imaging file formats

# `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

`CastingError` |
`FloatingError` |
`able_int_type`(values) | Find the smallest integer numpy type to contain sequence values
`as_int`(x[, check]) | Return python integer representation of number
`best_float`() | Floating point type with best precision
`ceil_exact`(val, flt_type) | Return nearest exact integer >= val in float type flt_type
`float_to_int`(arr, int_type[, nan2zero, infmax]) | Convert floating point array arr to type int_type
`floor_exact`(val, flt_type) | Return nearest exact integer <= val in float type flt_type
`floor_log2`(x) | floor of log2 of abs(x)
`have_binary128`() | True if we have a binary128 IEEE longdouble
`int_abs`(arr) | Absolute values of array taking care of max negative int values
`int_to_float`(val, flt_type) | Convert integer val to floating point type flt_type
`longdouble_lte_float64`() | Return True if longdouble appears to have the same precision as float64
`longdouble_precision_improved`() | True if longdouble precision increased since initial import
`ok_floats`() | Return floating point types sorted by precision
`on_powerpc`() | True if we are running on a Power PC platform
`shared_range`(flt_type, int_type) | Min and max in float type that are >=min, <=max in integer type
`type_info`(np_type) | Return dict with min, max, nexp, nmant, width for numpy type np_type
`ulp`([val]) | Return gap between val and nearest representable number of same type

## `CastingError`

class nibabel.casting.CastingError

  Bases: `Exception`

  __init__(*args, **kwargs)

## `FloatingError`

class nibabel.casting.FloatingError

  Bases: `Exception`

  __init__(*args, **kwargs)

## 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:
    values sequence

      sequence of integer values

  Returns:
    itype None 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

  as_int() is deprecated. Use int() instead.

  - deprecated from version: 5.2.0

  - Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 7.0.0

      >>> import pytest
      >>> import warnings
      >>> _suppress_warnings = pytest.deprecated_call()
      >>> _ = _suppress_warnings.__enter__()

  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.

  Parameters:
    x object

      integer, unsigned integer or floating point value

    check{True, False}

      If True, raise error for values that are not integers

  Returns:
    i int

      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

      >>> warnings.warn("Avoid error if no doctests to run...", DeprecationWarning)
      >>> _ = _suppress_warnings.__exit__(None, None, None)

## 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_type numpy 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 global `OK_FLOATS`.

## ceil_exact

nibabel.casting.ceil_exact(val, flt_type)

  Return nearest exact integer >= val in float type flt_type

  Parameters:
    val int

      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_type numpy type

      numpy float type.

  Returns:
    ceil_val object

      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 at `shared_min` and `shared_max`.

  Parameters:
    arr array-like

      Array of floating point type

    int_type object

      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:
    iarr ndarray

      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` and `shared_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:
    val int

      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_type numpy type

      numpy float type.

  Returns:
    floor_val object

      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:
    x int
  Returns:
    L None 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:
    arr array-like
  Returns:
    abs_arr array

      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

  int_to_float(…, dt) is deprecated. Use dt() instead.

  - deprecated from version: 5.2.0

  - Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 7.0.0

      >>> import pytest
      >>> import warnings
      >>> _suppress_warnings = pytest.deprecated_call()
      >>> _ = _suppress_warnings.__enter__()

  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:
    val int

      Integer value

    flt_type object

      numpy floating point type

  Returns:
    f numpy scalar

      of type flt_type

  Examples

      >>> int_to_float(1, np.float32)
      1.0

      >>> warnings.warn("Avoid error if no doctests to run...", DeprecationWarning)
      >>> _ = _suppress_warnings.__exit__(None, None, None)

## 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

## shared_range

nibabel.casting.shared_range(flt_type, int_type)

  Min and max in float type that are >=min, <=max in integer type

  This is not as easy as it sounds, because the float type may not be able to exactly represent the max or min integer values, so we have to find the next exactly representable floating point value to do the thresholding.

  Parameters:
    flt_type dtype specifier

      A dtype specifier referring to a numpy floating point type. For example, `f4`, `np.dtype('f4')`, `np.float32` are equivalent.

    int_type dtype specifier

      A dtype specifier referring to a numpy integer type. For example, `i4`, `np.dtype('i4')`, `np.int32` are equivalent

  Returns:
    mn object

      Number of type flt_type that is the minimum value in the range of int_type, such that `mn.astype(int_type)` >= min of int_type

    mx object

      Number of type flt_type that is the maximum value in the range of int_type, such that `mx.astype(int_type)` <= max of int_type

  Examples

      >>> shared_range(np.float32, np.int32) == (-2147483648.0, 2147483520.0)
      True
      >>> shared_range('f4', 'i4') == (-2147483648.0, 2147483520.0)
      True

## 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_type numpy type specifier

      Any specifier for a numpy dtype

  Returns:
    info dict

      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. Both `min` and `max` 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 in `np.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:
    val scalar, optional

      scalar value of any numpy type. Default is 1.0 (float64)

  Returns:
    ulp_val scalar

      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 is `ulp` rather than `eps` to avoid confusion between different meanings of eps.