import struct
import multiprocessing
import gmpy2
from opendp._data import erfc
gmpy2.get_context().round = gmpy2.RoundUp
def floatToBits(f):
s = struct.pack(">f", f)
return struct.unpack(">l", s)[0]
def bitsToFloat(b):
s = struct.pack(">l", b)
return struct.unpack(">f", s)[0]
def worker(offset, step):
max_err = 0
print(f"running {offset}")
for bits in range(floatToBits(0.0), floatToBits(float("inf")), step):
bits += offset
if offset == 0 and bits > 0 and (bits // step) % 10_000 == 0:
prop_done = bits / floatToBits(float("inf"))
print(
f"{prop_done:.2%} done, with max discovered f32 ulp error of: {max_err}. Currently at: {bitsToFloat(bits)}"
)
f32 = bitsToFloat(bits)
f32_ulp_err = abs(floatToBits(erfc(f32)) - floatToBits(gmpy2.erfc(f32)))
max_err = max(max_err, f32_ulp_err)
print(max_err)
if __name__ == "__main__":
n_cpus = multiprocessing.cpu_count() - 2
processes = []
for cpu in range(n_cpus):
p = multiprocessing.Process(target=worker, args=(cpu, n_cpus))
p.start()
processes.append(p)
[p.join() for p in processes]