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