1cbd624adSopenharmony_ci#!/usr/bin/env python3 2cbd624adSopenharmony_ci 3cbd624adSopenharmony_ci""" 4cbd624adSopenharmony_ciGenerate powers of five using Daniel Lemire's ``Eisel-Lemire algorithm`` for use in 5cbd624adSopenharmony_cidecimal to floating point conversions. 6cbd624adSopenharmony_ci 7cbd624adSopenharmony_ciSpecifically, computes and outputs (as Rust code) a table of 10^e for some 8cbd624adSopenharmony_cirange of exponents e. The output is one array of 128 bit significands. 9cbd624adSopenharmony_ciThe base two exponents can be inferred using a logarithmic slope 10cbd624adSopenharmony_ciof the decimal exponent. The approximations are normalized and rounded perfectly, 11cbd624adSopenharmony_cii.e., within 0.5 ULP of the true value. 12cbd624adSopenharmony_ci 13cbd624adSopenharmony_ciPorted from Rust's core library implementation, which itself is 14cbd624adSopenharmony_ciadapted from Daniel Lemire's fast_float ``table_generation.py``, 15cbd624adSopenharmony_ciavailable here: <https://github.com/fastfloat/fast_float/blob/main/script/table_generation.py>. 16cbd624adSopenharmony_ci""" 17cbd624adSopenharmony_cifrom __future__ import print_function 18cbd624adSopenharmony_cifrom math import ceil, floor, log, log2 19cbd624adSopenharmony_cifrom fractions import Fraction 20cbd624adSopenharmony_cifrom collections import deque 21cbd624adSopenharmony_ci 22cbd624adSopenharmony_ciHEADER = """ 23cbd624adSopenharmony_ci//! Pre-computed tables powers-of-5 for extended-precision representations. 24cbd624adSopenharmony_ci//! 25cbd624adSopenharmony_ci//! These tables enable fast scaling of the significant digits 26cbd624adSopenharmony_ci//! of a float to the decimal exponent, with minimal rounding 27cbd624adSopenharmony_ci//! errors, in a 128 or 192-bit representation. 28cbd624adSopenharmony_ci//! 29cbd624adSopenharmony_ci//! DO NOT MODIFY: Generated by `src/etc/lemire_table.py` 30cbd624adSopenharmony_ci""" 31cbd624adSopenharmony_ci 32cbd624adSopenharmony_ciSTATIC_WARNING = """ 33cbd624adSopenharmony_ci// Use static to avoid long compile times: Rust compiler errors 34cbd624adSopenharmony_ci// can have the entire table compiled multiple times, and then 35cbd624adSopenharmony_ci// emit code multiple times, even if it's stripped out in 36cbd624adSopenharmony_ci// the final binary. 37cbd624adSopenharmony_ci""" 38cbd624adSopenharmony_ci 39cbd624adSopenharmony_cidef main(): 40cbd624adSopenharmony_ci min_exp = minimum_exponent(10) 41cbd624adSopenharmony_ci max_exp = maximum_exponent(10) 42cbd624adSopenharmony_ci bias = -minimum_exponent(5) 43cbd624adSopenharmony_ci 44cbd624adSopenharmony_ci print(HEADER.strip()) 45cbd624adSopenharmony_ci print() 46cbd624adSopenharmony_ci print('pub const SMALLEST_POWER_OF_FIVE: i32 = {};'.format(min_exp)) 47cbd624adSopenharmony_ci print('pub const LARGEST_POWER_OF_FIVE: i32 = {};'.format(max_exp)) 48cbd624adSopenharmony_ci print('pub const N_POWERS_OF_FIVE: usize = ', end='') 49cbd624adSopenharmony_ci print('(LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;') 50cbd624adSopenharmony_ci print() 51cbd624adSopenharmony_ci print_proper_powers(min_exp, max_exp, bias) 52cbd624adSopenharmony_ci 53cbd624adSopenharmony_ci 54cbd624adSopenharmony_cidef minimum_exponent(base): 55cbd624adSopenharmony_ci return ceil(log(5e-324, base) - log(0xFFFFFFFFFFFFFFFF, base)) 56cbd624adSopenharmony_ci 57cbd624adSopenharmony_ci 58cbd624adSopenharmony_cidef maximum_exponent(base): 59cbd624adSopenharmony_ci return floor(log(1.7976931348623157e+308, base)) 60cbd624adSopenharmony_ci 61cbd624adSopenharmony_ci 62cbd624adSopenharmony_cidef print_proper_powers(min_exp, max_exp, bias): 63cbd624adSopenharmony_ci powers = deque() 64cbd624adSopenharmony_ci 65cbd624adSopenharmony_ci # Add negative exponents. 66cbd624adSopenharmony_ci # 2^(2b)/(5^−q) with b=64 + int(math.ceil(log2(5^−q))) 67cbd624adSopenharmony_ci powers = [] 68cbd624adSopenharmony_ci for q in range(min_exp, 0): 69cbd624adSopenharmony_ci power5 = 5 ** -q 70cbd624adSopenharmony_ci z = 0 71cbd624adSopenharmony_ci while (1 << z) < power5: 72cbd624adSopenharmony_ci z += 1 73cbd624adSopenharmony_ci if q >= -27: 74cbd624adSopenharmony_ci b = z + 127 75cbd624adSopenharmony_ci c = 2 ** b // power5 + 1 76cbd624adSopenharmony_ci powers.append((c, q)) 77cbd624adSopenharmony_ci else: 78cbd624adSopenharmony_ci b = 2 * z + 2 * 64 79cbd624adSopenharmony_ci c = 2 ** b // power5 + 1 80cbd624adSopenharmony_ci # truncate 81cbd624adSopenharmony_ci while c >= (1<<128): 82cbd624adSopenharmony_ci c //= 2 83cbd624adSopenharmony_ci powers.append((c, q)) 84cbd624adSopenharmony_ci 85cbd624adSopenharmony_ci # Add positive exponents 86cbd624adSopenharmony_ci for q in range(0, max_exp + 1): 87cbd624adSopenharmony_ci power5 = 5 ** q 88cbd624adSopenharmony_ci # move the most significant bit in position 89cbd624adSopenharmony_ci while power5 < (1<<127): 90cbd624adSopenharmony_ci power5 *= 2 91cbd624adSopenharmony_ci # *truncate* 92cbd624adSopenharmony_ci while power5 >= (1<<128): 93cbd624adSopenharmony_ci power5 //= 2 94cbd624adSopenharmony_ci powers.append((power5, q)) 95cbd624adSopenharmony_ci 96cbd624adSopenharmony_ci # Print the powers. 97cbd624adSopenharmony_ci print(STATIC_WARNING.strip()) 98cbd624adSopenharmony_ci print('#[rustfmt::skip]') 99cbd624adSopenharmony_ci typ = '[(u64, u64); N_POWERS_OF_FIVE]' 100cbd624adSopenharmony_ci print('pub static POWER_OF_FIVE_128: {} = ['.format(typ)) 101cbd624adSopenharmony_ci lo_mask = (1 << 64) - 1 102cbd624adSopenharmony_ci for c, exp in powers: 103cbd624adSopenharmony_ci hi = '0x{:x}'.format(c // (1 << 64)) 104cbd624adSopenharmony_ci lo = '0x{:x}'.format(c % (1 << 64)) 105cbd624adSopenharmony_ci value = ' ({}, {}), '.format(hi, lo) 106cbd624adSopenharmony_ci comment = '// {}^{}'.format(5, exp) 107cbd624adSopenharmony_ci print(value.ljust(46, ' ') + comment) 108cbd624adSopenharmony_ci print('];') 109cbd624adSopenharmony_ci 110cbd624adSopenharmony_ci 111cbd624adSopenharmony_ciif __name__ == '__main__': 112cbd624adSopenharmony_ci main() 113