Source code for gfloat.decode

# Copyright (c) 2024 Graphcore Ltd. All rights reserved.

import numpy as np

from .types import FloatClass, FloatValue, FormatInfo


[docs] def decode_float(fi: FormatInfo, i: int) -> FloatValue: r""" Given :py:class:`FormatInfo` and integer code point, decode to a :py:class:`FloatValue` Args: fi (FormatInfo): Floating point format descriptor. i (int): Integer code point, in the range :math:`0 \le i < 2^{k}`, where :math:`k` = ``fi.k`` Returns: Decoded float value Raises: ValueError: If :paramref:`i` is outside the range of valid code points in :paramref:`fi`. """ k = fi.k p = fi.precision t = p - 1 # Trailing significand field width num_signbits = 1 if fi.is_signed else 0 w = k - t - num_signbits # Exponent field width if i < 0 or i >= 2**k: raise ValueError(f"Code point {i} not in range [0, 2**{k})") if fi.is_signed: signmask = 1 << (k - 1) signbit = 1 if i & signmask else 0 sign = -1 if signbit else 1 else: signmask = None signbit = 0 sign = 1 exp = (i >> t) & ((1 << w) - 1) significand = i & ((1 << t) - 1) if fi.is_twos_complement and signbit: significand = (1 << t) - significand expBias = fi.expBias iszero = exp == 0 and significand == 0 and fi.has_zero issubnormal = fi.has_subnormals and (exp == 0) and (significand != 0) isnormal = not iszero and not issubnormal if iszero or issubnormal: expval = 1 - expBias fsignificand = significand * 2**-t else: expval = exp - expBias fsignificand = 1.0 + significand * 2**-t # val: the raw value excluding specials val = sign * fsignificand * 2.0**expval # Now overwrite the raw value with specials: Infs, NaN, -0, NaN_0 signed_infinity = -np.inf if signbit else np.inf fval = val # All-bits-special exponent (ABSE) if w > 0 and exp == 2**w - 1: min_i_with_nan = 2 ** (p - 1) - fi.num_high_nans if significand >= min_i_with_nan: fval = np.nan if fi.has_infs and significand == min_i_with_nan - 1: fval = signed_infinity # Negative zero or NaN if iszero and i == signmask and not fi.is_twos_complement: if fi.has_nz: fval = -0.0 else: fval = np.nan # Compute FloatClass fclass = None if fval == 0: fclass = FloatClass.ZERO elif np.isnan(fval): fclass = FloatClass.NAN elif np.isfinite(fval): if isnormal: fclass = FloatClass.NORMAL else: fclass = FloatClass.SUBNORMAL else: fclass = FloatClass.INFINITE return FloatValue(i, fval, exp, expval, significand, fsignificand, signbit, fclass)