"""Ideal resistor/RC calculations; no hardware or SPICE claims."""
from itertools import product
from math import exp, isclose, pi


def parallel(a, b):
    if a <= 0 or b <= 0:
        raise ValueError("resistances must be positive")
    return a * b / (a + b)


def divider(vin, r1, r2, load=None):
    lower = parallel(r2, load) if load is not None else r2
    return vin * lower / (r1 + lower)


def main():
    vin, r1, r2, load = 5.0, 10_000.0, 20_000.0, 100_000.0
    unloaded = divider(vin, r1, r2)
    loaded = divider(vin, r1, r2, load)
    thevenin = unloaded * load / (parallel(r1, r2) + load)
    assert isclose(loaded, 3.125)
    assert isclose(loaded, thevenin)
    tau = 10_000 * 100e-9
    fraction = 1 - exp(-1)
    assert 0.632 < fraction < 0.633
    assert (1 - exp(-5)) > 0.99
    corners = [divider(vin, r1 * a, r2 * b)
               for a, b in product((0.99, 1.01), repeat=2)]
    assert min(corners) < unloaded < max(corners)
    assert isclose(divider(vin, r1 * 10, r2 * 10), unloaded)
    assert divider(vin, r1 * 10, r2 * 10, load) < loaded
    print(f"unloaded={unloaded:.6f} V loaded={loaded:.6f} V")
    print(f"tau={tau * 1000:.3f} ms fc={1 / (2 * pi * tau):.3f} Hz")
    print(f"1% corners=[{min(corners):.6f}, {max(corners):.6f}] V")
    print("PASS")


if __name__ == "__main__":
    main()
