diff options
| author | Robin Kruppe <robin.kruppe@gmail.com> | 2015-07-26 15:44:24 +0200 |
|---|---|---|
| committer | Robin Kruppe <robin.kruppe@gmail.com> | 2015-08-08 17:15:25 +0200 |
| commit | b7e39a1c2dd24fd4110c22c70cad254365b0ffd3 (patch) | |
| tree | 64ba88e005c6feeac29f1efcd311918eccfffb12 | |
| parent | 7ebd7f3b9a7ebc020663a13b29b1e50446b3c262 (diff) | |
| download | rust-b7e39a1c2dd24fd4110c22c70cad254365b0ffd3.tar.gz rust-b7e39a1c2dd24fd4110c22c70cad254365b0ffd3.zip | |
Script for generating the powers-of-ten tables necessary for correct and
fast decimal-to-float conversions.
| -rw-r--r-- | src/etc/dec2flt_table.py | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py new file mode 100644 index 00000000000..b0140fb2455 --- /dev/null +++ b/src/etc/dec2flt_table.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python2.7 +# +# Copyright 2015 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +""" +Generate powers of ten using William Clinger's ``AlgorithmM`` for use in +decimal to floating point conversions. + +Specifically, computes and outputs (as Rust code) a table of 10^e for some +range of exponents e. The output is one array of 64 bit significands and +another array of corresponding base two exponents. The approximations are +normalized and rounded perfectly, i.e., within 0.5 ULP of the true value. + +The representation ([u64], [i16]) instead of the more natural [(u64, i16)] +is used because (u64, i16) has a ton of padding which would make the table +even larger, and it's already uncomfortably large (6 KiB). +""" +from __future__ import print_function +import sys +from fractions import Fraction +from collections import namedtuple + + +N = 64 # Size of the significand field in bits +MIN_SIG = 2 ** (N - 1) +MAX_SIG = (2 ** N) - 1 + + +# Hand-rolled fp representation without arithmetic or any other operations. +# The significand is normalized and always N bit, but the exponent is +# unrestricted in range. +Fp = namedtuple('Fp', 'sig exp') + + +def algorithm_m(f, e): + assert f > 0 + if e < 0: + u = f + v = 10 ** abs(e) + else: + u = f * 10 ** e + v = 1 + k = 0 + x = u // v + while True: + if x < MIN_SIG: + u <<= 1 + k -= 1 + elif x >= MAX_SIG: + v <<= 1 + k += 1 + else: + break + x = u // v + return ratio_to_float(u, v, k) + + +def ratio_to_float(u, v, k): + q, r = divmod(u, v) + v_r = v - r + z = Fp(q, k) + if r < v_r: + return z + elif r > v_r: + return next_float(z) + elif q % 2 == 0: + return z + else: + return next_float(z) + + +def next_float(z): + if z.sig == MAX_SIG: + return Fp(MIN_SIG, z.exp + 1) + else: + return Fp(z.sig + 1, z.exp) + + +def error(f, e, z): + decimal = f * Fraction(10) ** e + binary = z.sig * Fraction(2) ** z.exp + abs_err = abs(decimal - binary) + # The unit in the last place has value z.exp + ulp_err = abs_err / Fraction(2) ** z.exp + return float(ulp_err) + +LICENSE = """ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +""" + +def main(): + MIN_E = -305 + MAX_E = 305 + e_range = range(MIN_E, MAX_E+1) + powers = [] + for e in e_range: + z = algorithm_m(1, e) + err = error(1, e, z) + assert err < 0.5 + powers.append(z) + typ = "([u64; {0}], [i16; {0}])".format(len(e_range)) + print(LICENSE.strip()) + print("// Table of approximations of powers of ten.") + print("// DO NOT MODIFY: Generated by a src/etc/dec2flt_table.py") + print("pub const MIN_E: i16 = {};".format(MIN_E)) + print("pub const MAX_E: i16 = {};".format(MAX_E)) + print() + print("pub const POWERS: ", typ, " = ([", sep='') + for z in powers: + print(" 0x{:x},".format(z.sig)) + print("], [") + for z in powers: + print(" {},".format(z.exp)) + print("]);") + + +if __name__ == '__main__': + main() |
