1cbd624adSopenharmony_ci#!/usr/bin/env python3 2cbd624adSopenharmony_ci 3cbd624adSopenharmony_ci""" 4cbd624adSopenharmony_ciGenerate powers of a given radix for the Bellerophon algorithm. 5cbd624adSopenharmony_ci 6cbd624adSopenharmony_ciSpecifically, computes and outputs (as Rust code) a table of 10^e for some 7cbd624adSopenharmony_cirange of exponents e. The output is one array of 128 bit significands. 8cbd624adSopenharmony_ciThe base two exponents can be inferred using a logarithmic slope 9cbd624adSopenharmony_ciof the decimal exponent. The approximations are normalized and rounded perfectly, 10cbd624adSopenharmony_cii.e., within 0.5 ULP of the true value. 11cbd624adSopenharmony_ci 12cbd624adSopenharmony_ciPorted from Rust's core library implementation, which itself is 13cbd624adSopenharmony_ciadapted from Daniel Lemire's fast_float ``table_generation.py``, 14cbd624adSopenharmony_ciavailable here: <https://github.com/fastfloat/fast_float/blob/main/script/table_generation.py>. 15cbd624adSopenharmony_ci""" 16cbd624adSopenharmony_ci 17cbd624adSopenharmony_ciimport math 18cbd624adSopenharmony_cifrom collections import deque 19cbd624adSopenharmony_ci 20cbd624adSopenharmony_ciSTEP_STR = "static BASE{0}_STEP: i32 = {1};" 21cbd624adSopenharmony_ciSMALL_MANTISSA_STR = "static BASE{0}_SMALL_MANTISSA: [u64; {1}] = [" 22cbd624adSopenharmony_ciSMALL_EXPONENT_STR = "static BASE{0}_SMALL_EXPONENT: [i32; {1}] = [" 23cbd624adSopenharmony_ciLARGE_MANTISSA_STR = "static BASE{0}_LARGE_MANTISSA: [u64; {1}] = [" 24cbd624adSopenharmony_ciLARGE_EXPONENT_STR = "static BASE{0}_LARGE_EXPONENT: [i32; {1}] = [" 25cbd624adSopenharmony_ciSMALL_INT_STR = "static BASE{0}_SMALL_INT_POWERS: [u64; {1}] = {2};" 26cbd624adSopenharmony_ciBIAS_STR = "static BASE{0}_BIAS: i32 = {1};" 27cbd624adSopenharmony_ciEXP_STR = "// {}^{}" 28cbd624adSopenharmony_ciPOWER_STR = """pub static BASE{0}_POWERS: BellerophonPowers = BellerophonPowers {{ 29cbd624adSopenharmony_ci small: ExtendedFloatArray {{ mant: &BASE{0}_SMALL_MANTISSA, exp: &BASE{0}_SMALL_EXPONENT }}, 30cbd624adSopenharmony_ci large: ExtendedFloatArray {{ mant: &BASE{0}_LARGE_MANTISSA, exp: &BASE{0}_LARGE_EXPONENT }}, 31cbd624adSopenharmony_ci small_int: &BASE{0}_SMALL_INT_POWERS, 32cbd624adSopenharmony_ci step: BASE{0}_STEP, 33cbd624adSopenharmony_ci bias: BASE{0}_BIAS, 34cbd624adSopenharmony_ci}};\n""" 35cbd624adSopenharmony_ci 36cbd624adSopenharmony_cidef calculate_bitshift(base, exponent): 37cbd624adSopenharmony_ci ''' 38cbd624adSopenharmony_ci Calculate the bitshift required for a given base. The exponent 39cbd624adSopenharmony_ci is the absolute value of the max exponent (log distance from 1.) 40cbd624adSopenharmony_ci ''' 41cbd624adSopenharmony_ci 42cbd624adSopenharmony_ci return 63 + math.ceil(math.log2(base**exponent)) 43cbd624adSopenharmony_ci 44cbd624adSopenharmony_ci 45cbd624adSopenharmony_cidef next_fp(fp, base, step = 1): 46cbd624adSopenharmony_ci '''Generate the next extended-floating point value.''' 47cbd624adSopenharmony_ci 48cbd624adSopenharmony_ci return (fp[0] * (base**step), fp[1]) 49cbd624adSopenharmony_ci 50cbd624adSopenharmony_ci 51cbd624adSopenharmony_cidef prev_fp(fp, base, step = 1): 52cbd624adSopenharmony_ci '''Generate the previous extended-floating point value.''' 53cbd624adSopenharmony_ci 54cbd624adSopenharmony_ci return (fp[0] // (base**step), fp[1]) 55cbd624adSopenharmony_ci 56cbd624adSopenharmony_ci 57cbd624adSopenharmony_cidef normalize_fp(fp): 58cbd624adSopenharmony_ci '''Normalize a extended-float so the MSB is the 64th bit''' 59cbd624adSopenharmony_ci 60cbd624adSopenharmony_ci while fp[0] >> 64 != 0: 61cbd624adSopenharmony_ci fp = (fp[0] >> 1, fp[1] + 1) 62cbd624adSopenharmony_ci return fp 63cbd624adSopenharmony_ci 64cbd624adSopenharmony_ci 65cbd624adSopenharmony_cidef generate_small(base, count): 66cbd624adSopenharmony_ci '''Generate the small powers for a given base''' 67cbd624adSopenharmony_ci 68cbd624adSopenharmony_ci bitshift = calculate_bitshift(base, count) 69cbd624adSopenharmony_ci fps = [] 70cbd624adSopenharmony_ci fp = (1 << bitshift, -bitshift) 71cbd624adSopenharmony_ci for exp in range(count): 72cbd624adSopenharmony_ci fps.append((normalize_fp(fp), exp)) 73cbd624adSopenharmony_ci fp = next_fp(fp, base) 74cbd624adSopenharmony_ci 75cbd624adSopenharmony_ci # Print the small powers as integers. 76cbd624adSopenharmony_ci ints = [base**i for _, i in fps] 77cbd624adSopenharmony_ci 78cbd624adSopenharmony_ci return fps, ints 79cbd624adSopenharmony_ci 80cbd624adSopenharmony_ci 81cbd624adSopenharmony_cidef generate_large(base, step): 82cbd624adSopenharmony_ci '''Generate the large powers for a given base.''' 83cbd624adSopenharmony_ci 84cbd624adSopenharmony_ci # Get our starting parameters 85cbd624adSopenharmony_ci min_exp = math.floor(math.log(5e-324, base) - math.log(0xFFFFFFFFFFFFFFFF, base)) 86cbd624adSopenharmony_ci max_exp = math.ceil(math.log(1.7976931348623157e+308, base)) 87cbd624adSopenharmony_ci bitshift = calculate_bitshift(base, abs(min_exp - step)) 88cbd624adSopenharmony_ci fps = deque() 89cbd624adSopenharmony_ci 90cbd624adSopenharmony_ci # Add negative exponents 91cbd624adSopenharmony_ci # We need to go below the minimum exponent, since we need 92cbd624adSopenharmony_ci # all resulting exponents to be positive. 93cbd624adSopenharmony_ci fp = (1 << bitshift, -bitshift) 94cbd624adSopenharmony_ci for exp in range(-step, min_exp-step, -step): 95cbd624adSopenharmony_ci fp = prev_fp(fp, base, step) 96cbd624adSopenharmony_ci fps.appendleft((normalize_fp(fp), exp)) 97cbd624adSopenharmony_ci 98cbd624adSopenharmony_ci # Add positive exponents 99cbd624adSopenharmony_ci fp = (1 << bitshift, -bitshift) 100cbd624adSopenharmony_ci fps.append((normalize_fp(fp), 0)) 101cbd624adSopenharmony_ci for exp in range(step, max_exp, step): 102cbd624adSopenharmony_ci fp = next_fp(fp, base, step) 103cbd624adSopenharmony_ci fps.append((normalize_fp(fp), exp)) 104cbd624adSopenharmony_ci 105cbd624adSopenharmony_ci # Return the smallest exp, AKA, the bias 106cbd624adSopenharmony_ci return fps, -fps[0][1] 107cbd624adSopenharmony_ci 108cbd624adSopenharmony_ci 109cbd624adSopenharmony_cidef print_array(base, string, fps, index): 110cbd624adSopenharmony_ci '''Print an entire array''' 111cbd624adSopenharmony_ci 112cbd624adSopenharmony_ci print(string.format(base, len(fps))) 113cbd624adSopenharmony_ci for fp, exp in fps: 114cbd624adSopenharmony_ci value = " {},".format(fp[index]) 115cbd624adSopenharmony_ci exp = EXP_STR.format(base, exp) 116cbd624adSopenharmony_ci print(value.ljust(30, " ") + exp) 117cbd624adSopenharmony_ci print("];") 118cbd624adSopenharmony_ci 119cbd624adSopenharmony_ci 120cbd624adSopenharmony_cidef generate_base(base): 121cbd624adSopenharmony_ci '''Generate all powers and variables.''' 122cbd624adSopenharmony_ci 123cbd624adSopenharmony_ci step = math.floor(math.log(1e10, base)) 124cbd624adSopenharmony_ci small, ints = generate_small(base, step) 125cbd624adSopenharmony_ci large, bias = generate_large(base, step) 126cbd624adSopenharmony_ci 127cbd624adSopenharmony_ci print_array(base, SMALL_MANTISSA_STR, small, 0) 128cbd624adSopenharmony_ci print_array(base, SMALL_EXPONENT_STR, small, 1) 129cbd624adSopenharmony_ci print_array(base, LARGE_MANTISSA_STR, large, 0) 130cbd624adSopenharmony_ci print_array(base, LARGE_EXPONENT_STR, large, 1) 131cbd624adSopenharmony_ci print(SMALL_INT_STR.format(base, len(ints), ints)) 132cbd624adSopenharmony_ci print(STEP_STR.format(base, step)) 133cbd624adSopenharmony_ci print(BIAS_STR.format(base, bias)) 134cbd624adSopenharmony_ci 135cbd624adSopenharmony_ci 136cbd624adSopenharmony_cidef generate(): 137cbd624adSopenharmony_ci '''Generate all bases.''' 138cbd624adSopenharmony_ci 139cbd624adSopenharmony_ci print("// BASE{}\n".format(10)) 140cbd624adSopenharmony_ci generate_base(10) 141cbd624adSopenharmony_ci print("") 142cbd624adSopenharmony_ci 143cbd624adSopenharmony_ci print("// HIGH LEVEL\n// ----------\n") 144cbd624adSopenharmony_ci print(POWER_STR.format(10)) 145cbd624adSopenharmony_ci 146cbd624adSopenharmony_ci 147cbd624adSopenharmony_ciif __name__ == '__main__': 148cbd624adSopenharmony_ci generate() 149