xref: /llvm-project/libc/utils/mathtools/ryu_tablegen.py (revision 69c0b2febe01108f50db6e8ed21cd8b2e6088caf)
1688b9730SMichael Jones"""
2688b9730SMichael Jones//===-- Table Generator for Ryu Printf ------------------------------------===//
3688b9730SMichael Jones//
4688b9730SMichael Jones// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5688b9730SMichael Jones// See https://llvm.org/LICENSE.txt for license information.
6688b9730SMichael Jones// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7688b9730SMichael Jones//
8688b9730SMichael Jones//===----------------------------------------------------------------------===//
9688b9730SMichael Jones
10688b9730SMichael Jones
11688b9730SMichael JonesThis file is used to generate the tables of values in
12688b9730SMichael Jonessrc/__support/ryu_constants.h and ryu_long_double constants.h. To use it, set
13688b9730SMichael Jonesthe constants at the top of the file to the values you want to use for the Ryu
14688b9730SMichael Jonesalgorithm, then run this file. It will output the appropriate tables to stdout,
15688b9730SMichael Jonesso it's recommended to pipe stdout to a file. The following is a brief
16688b9730SMichael Jonesexplenation of each of the constants.
17688b9730SMichael Jones
18688b9730SMichael JonesBLOCK_SIZE:
19688b9730SMichael Jones    Default: 9
20688b9730SMichael Jones    The number of digits that will be calculated together in a block.
21688b9730SMichael Jones    Don't touch this unless you really know what you're doing.
22688b9730SMichael Jones
23688b9730SMichael JonesCONSTANT:
24688b9730SMichael Jones    Default: 120
25688b9730SMichael Jones    Also known as c_0 and c_1 in the Ryu Printf paper and SHIFT_CONST in
26688b9730SMichael Jones    float_to_string.h.
27688b9730SMichael Jones    The table value is shifted left by this amount, and the final value is
28688b9730SMichael Jones    shifted right by this amount. It effectively makes the table value a fixed
29688b9730SMichael Jones    point number with the decimal point at the bit that is CONSTANT bits from
30688b9730SMichael Jones    the right.
31688b9730SMichael Jones    Higher values increase accuracy, but also require higher MID_INT_WIDTH
32688b9730SMichael Jones    values to fit the result.
33688b9730SMichael Jones
34688b9730SMichael JonesIDX_SIZE:
35688b9730SMichael Jones    Default: 16
36688b9730SMichael Jones    By increasing the MOD_SIZE slightly we can significantly decrease the number
37688b9730SMichael Jones    of table entries we need.
38688b9730SMichael Jones    We can divide the number of table entries by IDX_SIZE, and multiply MOD_SIZE
39688b9730SMichael Jones    by 2^IDX_SIZE, and the math still works out.
40688b9730SMichael Jones    This optimization isn't mentioned in the original Ryu Printf paper but it
41688b9730SMichael Jones    saves a lot of space.
42688b9730SMichael Jones
43688b9730SMichael JonesMID_INT_WIDTH:
44688b9730SMichael Jones    Default: 192
45688b9730SMichael Jones    This is the size of integer that the tables use. It's called mid int because
46688b9730SMichael Jones    it's the integer used in the middle of the calculation. There are large ints
47688b9730SMichael Jones    used to calculate the mid int table values, then those are used to calculate
48688b9730SMichael Jones    the small int final values.
49688b9730SMichael Jones    This must be divisible by 64 since each table entry is an array of 64 bit
50688b9730SMichael Jones    integers.
51688b9730SMichael Jones    If this is too small, then the results will get cut off. It should be at
52688b9730SMichael Jones    least CONSTANT + IDX_SIZE + log_2(10^9) to be able to fit the table values.
53688b9730SMichael Jones
54688b9730SMichael JonesMANT_WIDTH:
55688b9730SMichael Jones    The width of the widest float mantissa that this table will work for.
56688b9730SMichael Jones    This has a small effect on table size.
57688b9730SMichael Jones
58688b9730SMichael JonesEXP_WIDTH:
59688b9730SMichael Jones    The width of the widest float exponent that this table will work for.
60688b9730SMichael Jones    This has a large effect on table size.
61688b9730SMichael Jones        Specifically, table size is proportional to the square of this number.
62688b9730SMichael Jones"""
63688b9730SMichael Jones
64688b9730SMichael JonesBLOCK_SIZE = 9
65688b9730SMichael Jones
66688b9730SMichael Jones
67688b9730SMichael Jones# Values for double
68688b9730SMichael Jones# CONSTANT = 120
69688b9730SMichael Jones# IDX_SIZE = 16
70688b9730SMichael Jones# MANT_WIDTH = 52
71688b9730SMichael Jones# EXP_WIDTH = 11
72688b9730SMichael Jones# MID_INT_SIZE = 192
73688b9730SMichael Jones
74688b9730SMichael Jones# Values for 128 bit float
75688b9730SMichael JonesCONSTANT = 120
76688b9730SMichael JonesIDX_SIZE = 128
77688b9730SMichael JonesMANT_WIDTH = 112
78688b9730SMichael JonesEXP_WIDTH = 15
79688b9730SMichael JonesMID_INT_SIZE = 256 + 64
80688b9730SMichael Jones
81688b9730SMichael JonesMAX_EXP = 2 ** (EXP_WIDTH - 1)
82688b9730SMichael JonesPOSITIVE_ARR_SIZE = MAX_EXP // IDX_SIZE
83688b9730SMichael JonesNEGATIVE_ARR_SIZE = (MAX_EXP // IDX_SIZE) + ((MANT_WIDTH + (IDX_SIZE - 1)) // IDX_SIZE)
84688b9730SMichael JonesMOD_SIZE = (10**BLOCK_SIZE) << (CONSTANT + (IDX_SIZE if IDX_SIZE > 1 else 0))
85688b9730SMichael Jones
86688b9730SMichael Jones
87688b9730SMichael Jones# floor(5^(-9i) * 2^(e + c_1 - 9i) + 1) % (10^9 * 2^c_1)
88688b9730SMichael Jonesdef get_table_positive(exponent, i):
89688b9730SMichael Jones    pow_of_two = 1 << (exponent + CONSTANT - (BLOCK_SIZE * i))
90688b9730SMichael Jones    pow_of_five = 5 ** (BLOCK_SIZE * i)
91688b9730SMichael Jones    result = (pow_of_two // pow_of_five) + 1
92688b9730SMichael Jones    return result % MOD_SIZE
93688b9730SMichael Jones
94688b9730SMichael Jones
95688b9730SMichael Jones# floor(10^(9*(-i)) * 2^(c_0 + (-e))) % (10^9 * 2^c_0)
96688b9730SMichael Jonesdef get_table_negative(exponent, i):
97688b9730SMichael Jones    result = 1
98688b9730SMichael Jones    pow_of_ten = 10 ** (BLOCK_SIZE * i)
99688b9730SMichael Jones    shift_amount = CONSTANT - exponent
100688b9730SMichael Jones    if shift_amount < 0:
101688b9730SMichael Jones        result = pow_of_ten >> (-shift_amount)
102688b9730SMichael Jones    else:
103688b9730SMichael Jones        result = pow_of_ten << (shift_amount)
104688b9730SMichael Jones    return result % MOD_SIZE
105688b9730SMichael Jones
106688b9730SMichael Jones
107688b9730SMichael Jones# Returns floor(log_10(2^e)); requires 0 <= e <= 42039.
108688b9730SMichael Jonesdef ceil_log10_pow2(e):
109688b9730SMichael Jones    return ((e * 0x13441350FBD) >> 42) + 1
110688b9730SMichael Jones
111688b9730SMichael Jones
112688b9730SMichael Jonesdef length_for_num(idx, index_size=IDX_SIZE):
113688b9730SMichael Jones    return (
114688b9730SMichael Jones        ceil_log10_pow2(idx * index_size) + ceil_log10_pow2(MANT_WIDTH) + BLOCK_SIZE - 1
115688b9730SMichael Jones    ) // BLOCK_SIZE
116688b9730SMichael Jones
117688b9730SMichael Jones
118688b9730SMichael Jonesdef get_64bit_window(num, index):
119688b9730SMichael Jones    return (num >> (index * 64)) % (2**64)
120688b9730SMichael Jones
121688b9730SMichael Jones
122688b9730SMichael Jonesdef mid_int_to_str(num):
123688b9730SMichael Jones    outstr = "    {"
124688b9730SMichael Jones    outstr += str(get_64bit_window(num, 0)) + "u"
125688b9730SMichael Jones    for i in range(1, MID_INT_SIZE // 64):
126688b9730SMichael Jones        outstr += ", " + str(get_64bit_window(num, i)) + "u"
127688b9730SMichael Jones    outstr += "},"
128688b9730SMichael Jones    return outstr
129688b9730SMichael Jones
130688b9730SMichael Jones
131688b9730SMichael Jonesdef print_positive_table_for_idx(idx):
132688b9730SMichael Jones    positive_blocks = length_for_num(idx)
133688b9730SMichael Jones    for i in range(positive_blocks):
134688b9730SMichael Jones        table_val = get_table_positive(idx * IDX_SIZE, i)
135688b9730SMichael Jones        # print(hex(table_val))
136688b9730SMichael Jones        print(mid_int_to_str(table_val))
137688b9730SMichael Jones    return positive_blocks
138688b9730SMichael Jones
139688b9730SMichael Jones
140688b9730SMichael Jonesdef print_negative_table_for_idx(idx):
141688b9730SMichael Jones    i = 0
142688b9730SMichael Jones    min_block = -1
143688b9730SMichael Jones    table_val = 0
144688b9730SMichael Jones    MIN_USEFUL_VAL = 2 ** (CONSTANT - (MANT_WIDTH + 2))
145688b9730SMichael Jones    # Iterate through the zero blocks
146688b9730SMichael Jones    while table_val < MIN_USEFUL_VAL:
147688b9730SMichael Jones        i += 1
148688b9730SMichael Jones        table_val = get_table_negative((idx) * IDX_SIZE, i)
149688b9730SMichael Jones    else:
150688b9730SMichael Jones        i -= 1
151688b9730SMichael Jones
152688b9730SMichael Jones    min_block = i
153688b9730SMichael Jones
154688b9730SMichael Jones    # Iterate until another zero block is found
155688b9730SMichael Jones    while table_val >= MIN_USEFUL_VAL:
156688b9730SMichael Jones        table_val = get_table_negative((idx) * IDX_SIZE, i + 1)
157688b9730SMichael Jones        if table_val >= MIN_USEFUL_VAL:
158688b9730SMichael Jones            print(mid_int_to_str(table_val))
159688b9730SMichael Jones            i += 1
160688b9730SMichael Jones    return i - min_block, min_block
161688b9730SMichael Jones
162688b9730SMichael Jones
163688b9730SMichael Jonespositive_size_arr = [0] * (POSITIVE_ARR_SIZE + 1)
164688b9730SMichael Jones
165688b9730SMichael Jonesnegative_size_arr = [0] * (NEGATIVE_ARR_SIZE + 1)
166688b9730SMichael Jonesmin_block_arr = [0] * (NEGATIVE_ARR_SIZE + 1)
167688b9730SMichael Jonesacc = 0
168688b9730SMichael Jones
169688b9730SMichael Jonesif MOD_SIZE > (2**MID_INT_SIZE):
170688b9730SMichael Jones    print(
171688b9730SMichael Jones        "Mod size is too big for current MID_INT_SIZE by a factor of",
172688b9730SMichael Jones        MOD_SIZE // (2**MID_INT_SIZE),
173688b9730SMichael Jones    )
174688b9730SMichael Joneselse:
175688b9730SMichael Jones    print("static const uint64_t POW10_SPLIT[][" + str(MID_INT_SIZE // 64) + "] = {")
176*5bd34e0aSmichaelrj-google    for idx in range(0, POSITIVE_ARR_SIZE + 1):
177688b9730SMichael Jones        num_size = print_positive_table_for_idx(idx)
178*5bd34e0aSmichaelrj-google        positive_size_arr[idx] = acc
179688b9730SMichael Jones        acc += num_size
180688b9730SMichael Jones    print("};")
181688b9730SMichael Jones
182688b9730SMichael Jones    print(
183688b9730SMichael Jones        "static const uint32_t POW10_OFFSET_2[" + str(len(positive_size_arr)) + "] = {",
184688b9730SMichael Jones        str(positive_size_arr)[1:-2],
185688b9730SMichael Jones        "};",
186688b9730SMichael Jones    )
187688b9730SMichael Jones
188688b9730SMichael Jones    print("static const uint64_t POW10_SPLIT_2[][" + str(MID_INT_SIZE // 64) + "] = {")
189688b9730SMichael Jones    for idx in range(0, NEGATIVE_ARR_SIZE):
190688b9730SMichael Jones        num_size, min_block = print_negative_table_for_idx(idx)
191688b9730SMichael Jones        acc += num_size
192688b9730SMichael Jones        negative_size_arr[idx + 1] = acc
193688b9730SMichael Jones        min_block_arr[idx] = min_block
194688b9730SMichael Jones    print("};")
195688b9730SMichael Jones    print(
196688b9730SMichael Jones        "static const uint32_t POW10_OFFSET_2[" + str(len(negative_size_arr)) + "] = {",
197688b9730SMichael Jones        str(negative_size_arr)[1:-2],
198688b9730SMichael Jones        "};",
199688b9730SMichael Jones    )
200688b9730SMichael Jones    print(
201688b9730SMichael Jones        "static const uint16_t MIN_BLOCK_2[" + str(len(min_block_arr)) + "] = {",
202688b9730SMichael Jones        str(min_block_arr)[1:-2],
203688b9730SMichael Jones        "};",
204688b9730SMichael Jones    )
205