forked from graphcore-research/gfloat
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecode.py
More file actions
101 lines (81 loc) · 2.83 KB
/
decode.py
File metadata and controls
101 lines (81 loc) · 2.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# Copyright (c) 2024 Graphcore Ltd. All rights reserved.
import numpy as np
from .types import FloatClass, FloatValue, FormatInfo, Domain
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`.
"""
assert isinstance(i, int)
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
bias = fi.bias
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 - bias
fsignificand = significand * 2**-t
else:
expval = exp - bias
fsignificand = 1.0 + significand * 2**-t
# Handle specials: Infs, NaN, -0, NaN_0
# High NaNs
fval = None
max_positive_code = (1 << (k - fi.signBits)) - 1
code_without_sign = i & max_positive_code
if code_without_sign > max_positive_code - fi.num_high_nans:
# Return nan, ignore sign
fval = np.nan
# Infinities
if fi.domain == Domain.Extended:
if code_without_sign == max_positive_code - fi.num_high_nans:
fval = -np.inf if signbit else np.inf
# 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
# In range - compute value
if fval is None:
fval = sign * fsignificand * 2.0**expval
# 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)