Collect value statistics for formats
This notebook computes various statistics for a variety of float formats,
by exhaustively enumerating the values. Naturally, most of these statistics can be computed directly, and indeed many are already supplied on the FormatInfo
class as methods, for example max
, smallest_subnormal
, etc. However this method serves as a useful cross-check against the direct formulae.
Statistics collected
name: Format
B: Bits in the format
P: Precision in bits
E: Exponent field width in bits
T: Trailing significand field width in bits
lt1: Number of values x such that
0 < x < 1
gt1: Number of values x such that
1 < x < Inf
rt16: True if all values are exactly representable in IEEE binary16
maxFinite: Largest finite value
minFinite: Smallest finite value
maxNormal: Largest finite normal value, NaN if all finite values are subnormal
minNormal: Smallest positive normal value, NaN if all finite values are subnormal
minSubnormal: Smallest positive subnormal value, NaN if no finite values are - subnormal
maxSubnormal: Largest subnormal value, NaN if no finite values are subnormal
from gfloat import *
from gfloat.formats import *
import pandas
import numpy as np
from IPython.display import HTML
def collect_stats(fi: FormatInfo):
# Generate all values
values = [decode_float(fi, i) for i in range(2**fi.bits)]
df = pandas.DataFrame(values)
# Extract format information parameters
E = fi.expBits
S = fi.tSignificandBits
# Compute statistics: lt1,gt1
fval = df["fval"]
total_01 = fval.between(0, 1, inclusive="neither").sum()
total_1Inf = fval.between(1, np.inf, inclusive="neither").sum()
# Compute statistics: maxFinite,minFinite
finite_vals = fval[np.isfinite(fval)]
maxFinite = finite_vals.loc[finite_vals.idxmax()]
minFinite = finite_vals.loc[finite_vals.idxmin()]
# Compute statistics: maxNormal,minNormal
normal_vals = fval[(df["fclass"] == FloatClass.NORMAL) & (fval > 0)]
maxNormal = normal_vals.loc[normal_vals.idxmax()] if normal_vals.any() else np.nan
minNormal = normal_vals.loc[normal_vals.idxmin()] if normal_vals.any() else np.nan
# Compute statistics: minSubnormal
pos_subnormal = fval[(df["fclass"] == FloatClass.SUBNORMAL) & (fval > 0)]
maxSubnormal = (
pos_subnormal.loc[pos_subnormal.idxmax()] if pos_subnormal.any() else np.nan
)
minSubnormal = (
pos_subnormal.loc[pos_subnormal.idxmin()] if pos_subnormal.any() else np.nan
)
# Compute roundtrips: rt16, rt32
with np.errstate(over="ignore"):
rt16 = (np.float64(np.float16(fval)) == np.float64(fval)) | ~np.isfinite(fval)
rt32 = (np.float64(np.float32(fval)) == np.float64(fval)) | ~np.isfinite(fval)
rt16 = rt16.all()
rt32 = rt32.all()
assert rt32 # If not, we should include rt32 in the table
# Assemble tuple
return dict(
name=fi.name,
B=fi.bits,
P=fi.precision,
E=E,
T=S,
lt1=total_01,
gt1=total_1Inf,
rt16=rt16,
maxFinite=maxFinite,
minFinite=minFinite,
maxNormal=maxNormal,
minNormal=minNormal,
minSubnormal=minSubnormal,
maxSubnormal=maxSubnormal,
)
formats_to_check = (
tiny_formats
+ fp8_formats
+ [format_info_bfloat16, format_info_ocp_int8, format_info_ocp_e8m0]
)
stats = [collect_stats(fi) for fi in formats_to_check]
df = pandas.DataFrame(stats)
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 4
1 from gfloat import *
2 from gfloat.formats import *
----> 4 import pandas
5 import numpy as np
6 from IPython.display import HTML
ModuleNotFoundError: No module named 'pandas'
Emit HTML table
# Special rendering for float values - if they don't render nicely in 10.5g,
# use float_pow2str
def render_float(v):
s = f"{v:8.5g}"
if not "e" in s and float(s) == v:
return s
else:
return float_pow2str(v)
for field in (
"maxFinite",
"minFinite",
"maxNormal",
"minNormal",
"minSubnormal",
"maxSubnormal",
):
df[field] = df[field].map(render_float)
HTML(df.style.hide().to_html())
name | B | P | E | T | lt1 | gt1 | rt16 | maxFinite | minFinite | maxNormal | minNormal | minSubnormal | maxSubnormal |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ocp_e2m1 | 4 | 2 | 2 | 1 | 1 | 5 | True | 6 | -6 | 6 | 1 | 0.5 | 0.5 |
ocp_e2m3 | 6 | 4 | 2 | 3 | 7 | 23 | True | 7.5 | -7.5 | 7.5 | 1 | 0.125 | 0.875 |
ocp_e3m2 | 6 | 3 | 3 | 2 | 11 | 19 | True | 28 | -28 | 28 | 0.25 | 0.0625 | 0.1875 |
ocp_e4m3 | 8 | 4 | 4 | 3 | 55 | 70 | True | 448 | -448 | 448 | 0.015625 | 1*2^-9 | 7/4*2^-7 |
ocp_e5m2 | 8 | 3 | 5 | 2 | 59 | 63 | True | 57344 | -57344 | 57344 | 1*2^-14 | 1*2^-16 | 3/2*2^-15 |
p3109_p1 | 8 | 1 | 7 | 0 | 62 | 63 | False | 1*2^63 | -1*2^63 | 1*2^63 | 1*2^-62 | nan | nan |
p3109_p2 | 8 | 2 | 6 | 1 | 63 | 62 | False | 1*2^31 | -1*2^31 | 1*2^31 | 1*2^-31 | 1*2^-32 | 1*2^-32 |
p3109_p3 | 8 | 3 | 5 | 2 | 63 | 62 | True | 49152 | -49152 | 49152 | 1*2^-15 | 1*2^-17 | 3/2*2^-16 |
p3109_p4 | 8 | 4 | 4 | 3 | 63 | 62 | True | 224 | -224 | 224 | 0.0078125 | 1*2^-10 | 7/4*2^-8 |
p3109_p5 | 8 | 5 | 3 | 4 | 63 | 62 | True | 15 | -15 | 15 | 0.125 | 0.0078125 | 15/8*2^-4 |
p3109_p6 | 8 | 6 | 2 | 5 | 63 | 62 | True | 3.875 | -3.875 | 3.875 | 0.5 | 0.015625 | 31/16*2^-2 |
bfloat16 | 16 | 8 | 8 | 7 | 16255 | 16383 | False | 255/128*2^127 | -255/128*2^127 | 255/128*2^127 | 1*2^-126 | 1*2^-133 | 127/64*2^-127 |
ocp_int8 | 8 | 8 | 0 | 7 | 63 | 63 | True | 127/64*2^0 | -2 | nan | nan | 0.015625 | 127/64*2^0 |
ocp_e8m0 | 8 | 1 | 8 | 0 | 127 | 127 | False | 1*2^127 | 1*2^-127 | 1*2^127 | 1*2^-127 | nan | nan |