"""Lecture 2 demonstration: bits, bytes and floating-point numbers, on C9.csv.

    python3.13 bits_and_floats.py        (needs numpy, in the project venv)
"""
import math
import os
import struct

import numpy as np

# --- integers ---------------------------------------------------------------
print("141 in binary:", bin(141), "=", " + ".join(str(2**i) for i, b in enumerate(reversed(bin(141)[2:])) if b == "1"))
print("int('10001101', 2) =", int("10001101", 2))
print("np.int8 wraps: 141 ->", np.array([141]).astype(np.int8)[0], "| int8 range", np.iinfo(np.int8).min, "..", np.iinfo(np.int8).max)

# --- sizes --------------------------------------------------------------------
d = np.genfromtxt("C9.csv", delimiter=",", skip_header=1)
print("C9.csv on disk:", os.path.getsize("C9.csv"), "bytes")
print("as an array:", d.shape, d.dtype, d.nbytes, "bytes;", "as float32:", d.astype(np.float32).nbytes, "bytes")

# --- floating point ------------------------------------------------------------
x = d[0, 1]  # the first algae value, 1.92
bits = format(struct.unpack(">Q", struct.pack(">d", x))[0], "064b")
print(f"{x} as fp64: sign {bits[0]}, exponent {bits[1:12]} ({int(bits[1:12], 2)} - 1023 = {int(bits[1:12], 2) - 1023}), fraction {bits[12:]}")
bits32 = format(struct.unpack(">I", struct.pack(">f", x))[0], "032b")
print(f"{x} as fp32: sign {bits32[0]}, exponent {bits32[1:9]}, fraction {bits32[9:]}")
print("fp32 rounding error:", float(np.float32(x)) - x)
print("0.1 + 0.2 =", 0.1 + 0.2, "| == 0.3:", 0.1 + 0.2 == 0.3, "| isclose:", math.isclose(0.1 + 0.2, 0.3))
for t in (np.float32, np.float64):
    f = np.finfo(t)
    print(f"{t.__name__}: eps {f.eps:.3g}, min positive {f.tiny:.3g}, max {f.max:.3g}, ~{f.precision} digits")
print("sum of 1e7 x 0.1 in fp32:", np.sum(np.full(10**7, 0.1, dtype=np.float32)), "| in fp64:", np.sum(np.full(10**7, 0.1)))
print("mean algae: fp64", d[:, 1].mean(), "| fp32", d[:, 1].astype(np.float32).mean())
