      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116

    // This file comes from the `dtoa` port by David Tolnay:
    // https://github.com/dtolnay/dtoa
    //
    // It's an implementation of a Grisu2 algorithm by Florian Loitsch:
    // http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
    //
    // The algorithm here has been modified to produce a `u64` mantisa and
    // a decimal exponent instead of writing to a string.
    //
    // Copyright 2016 Dtoa Developers
    //
    // 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.

    use crate::util::diyfp::{ self, DiyFp };

    #[inline]
    unsafe fn grisu_round(buffer: &mut u64, delta: u64, mut rest: u64, ten_kappa: u64, wp_w: u64) {
        while rest < wp_w && delta - rest >= ten_kappa &&
               (rest + ten_kappa < wp_w || // closer
                wp_w - rest > rest + ten_kappa - wp_w) {
            *buffer -= 1;
            rest += ten_kappa;
        }
    }

    #[inline]
    fn count_decimal_digit32(n: u32) -> i16 {
        if n < 10 { 1 }
        else if n < 100 { 2 }
        else if n < 1000 { 3 }
        else if n < 10000 { 4 }
        else if n < 100000 { 5 }
        else if n < 1000000 { 6 }
        else if n < 10000000 { 7 }
        else if n < 100000000 { 8 }
        // Will not reach 10 digits in digit_gen()
        else { 9 }
    }

    #[inline]
    unsafe fn digit_gen(w: DiyFp, mp: DiyFp, mut delta: u64, mut k: i16) -> (u64, i16) {
        static POW10: [u32; 10] = [ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 ];
        let one = DiyFp::new(1u64 << -mp.e, mp.e);
        let wp_w = mp - w;
        let mut p1 = (mp.f >> -one.e) as u32;
        let mut p2 = mp.f & (one.f - 1);
        let mut kappa = count_decimal_digit32(p1); // kappa in [0, 9]

        let mut buffer = p1 as u64;

        while kappa > 0 {
            match kappa {
                9 => { p1 %=  100000000; }
                8 => { p1 %=   10000000; }
                7 => { p1 %=    1000000; }
                6 => { p1 %=     100000; }
                5 => { p1 %=      10000; }
                4 => { p1 %=       1000; }
                3 => { p1 %=        100; }
                2 => { p1 %=         10; }
                1 => { p1 =           0; }
                _ => {}
            }
            kappa = kappa.wrapping_sub(1);
            let tmp = ((p1 as u64) << -one.e) + p2;
            if tmp <= delta {
                k += kappa;
                let pow10 = POW10[kappa as usize] as u64;
                buffer /= pow10;

                grisu_round(&mut buffer, delta, tmp, pow10 << -one.e, wp_w.f);
                return (buffer, k);
            }
        }

        loop {
            p2 *= 10;
            delta *= 10;
            let d = (p2 >> -one.e) as u8;
            if d != 0 || buffer != 0 {
                buffer = buffer * 10 + d as u64;
            }
            p2 &= one.f - 1;
            kappa = kappa.wrapping_sub(1);
            if p2 < delta {
                k += kappa;
                let index = -(kappa as isize);

                grisu_round(&mut buffer, delta, p2, one.f, wp_w.f * if index < 9 { POW10[-(kappa as isize) as usize] as u64 } else { 0 });
                return (buffer, k);
            }
        }
    }

    #[inline]
    pub fn convert(float: f64) -> (u64, i16) {
        if float == 0.0 {
            return (0, 0);
        }
        unsafe {
            let v = DiyFp::from_f64(float);
            let (w_m, w_p) = v.normalized_boundaries();
            let (c_mk, k) = diyfp::get_cached_power(w_p.e);
            let w = v.normalize() * c_mk;
            let mut wp = w_p * c_mk;
            let mut wm = w_m * c_mk;
            wm.f += 1;
            wp.f -= 1;

            digit_gen(w, wp, wp.f - wm.f, k as i16)
        }
    }