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 102 103 104 105 106
|
"""This script generates msgspec/atof_consts.h"""
import math
import os
import textwrap
def gen_hpd_tables():
log2log10 = math.log(2) / math.log(10)
shifts = ["0x0000"]
powers = []
for i in range(1, 61):
offset = len(powers)
assert offset <= 0x07FF
num_new_digits = int(log2log10 * float(i)) + 1
assert num_new_digits <= 31
code = (num_new_digits << 11) | offset
p = str(5**i)
powers.extend(p)
shifts.append("0x%04X" % code)
for i in range(61, 65):
shifts.append("0x%04X" % len(powers))
n_shifts = len(shifts)
n_powers = len(powers)
assert n_powers <= 0x07FF
shifts_str = "\n".join(textwrap.wrap(", ".join(shifts), width=78))
powers_str = "\n".join(textwrap.wrap(", ".join(powers), width=78))
return n_shifts, shifts_str, n_powers, powers_str
def gen_row(e):
z = 1 << 2048
if e >= 0:
exp = 10**e
z = z * exp
else:
exp = 10 ** (-e)
z = z // exp
n = -2048
while z >= (1 << 128):
z = z >> 1
n += 1
h = hex(z)[2:]
assert len(h) == 32
approx_n = ((217706 * e) >> 16) + 1087
biased_n = 1214 + n
assert approx_n == biased_n
return "{0x%s, 0x%s}, // 1e%-04d" % (h[16:], h[:16], e)
table_rows = [gen_row(e) for e in range(-307, 289)]
f64_powers = [f"1e{i}" for i in range(23)]
n_shifts, shifts, n_powers, powers = gen_hpd_tables()
text = """\
/* DO NOT EDIT - generated by scripts/generate_atof_consts.py */
#ifndef MSGSPEC_ATOF_CONSTS_H
#define MSGSPEC_ATOF_CONSTS_H
static const uint64_t ms_atof_powers_of_10[%d][2] = {
%s
};
static const double ms_atof_f64_powers_of_10[%d] = {
%s
};
static const uint16_t ms_atof_left_shift[%d] = {
%s
};
static const uint8_t ms_atof_powers_of_5[%d] = {
%s
};
#endif
""" % (
len(table_rows),
"\n".join(table_rows),
len(f64_powers),
"\n".join(textwrap.wrap(", ".join(f64_powers), width=78)),
n_shifts,
shifts,
n_powers,
powers,
)
if __name__ == "__main__":
repo = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
path = os.path.join(repo, "msgspec", "atof_consts.h")
with open(path, "wb") as f:
f.write(text.encode("utf-8"))
|