lexical-write-float 0.8.5

Efficient formatting of floats to strings.
Documentation
#![cfg(feature = "power-of-two")]

use fraction::{BigFraction, ToPrimitive};
use lexical_util::step::u64_step;

// NOTE:
//  These are extremely naive, inefficient binary parsers based off
//  of the documentation in `binary.rs`. See the Python code there
//  for a more legible example.

macro_rules! parse_float {
    ($name:ident, $t:ident, $cb:ident) => {
        pub fn $name(string: &[u8], radix: u32, exp: u8) -> $t {
            let index = string.iter().position(|&x| x == b'.').unwrap();
            let integer = &string[..index];
            let rest = &string[index + 1..];
            let fraction: &[u8];
            let exponent: i32;
            if let Some(index) = rest.iter().position(|&x| x == exp) {
                fraction = &rest[..index];
                let exp_digits = unsafe { std::str::from_utf8_unchecked(&rest[index + 1..]) };
                exponent = i32::from_str_radix(exp_digits, radix).unwrap();
            } else {
                fraction = rest;
                exponent = 0;
            }

            // Now need to reconstruct our integer.
            let step = u64_step(radix);
            let pow = BigFraction::new((radix as u128).pow(step as u32), 1u64);
            let mut fint = BigFraction::new(0u64, 1u64);
            let mut index = 0;
            while index < integer.len() {
                let count = step.min(integer.len() - index);
                let end = index + count;
                let digits = unsafe { std::str::from_utf8_unchecked(&integer[index..end]) };
                let tmp = u64::from_str_radix(digits, radix).unwrap();
                fint *= pow.clone();
                fint += BigFraction::new(tmp, 1u64);
                index = end;
            }

            // Scale it to the exponent.
            // Note that these should always be exact, since we can hold
            // all powers-of-two exactly.
            if exponent >= 0 {
                fint *= BigFraction::from((radix as f64).powi(exponent));
            } else {
                fint /= BigFraction::from((radix as f64).powi(-exponent));
            }

            // Now need to reconstruct our fraction.
            let mut ffrac = BigFraction::new(0u64, 1u64);
            let mut index = 0;
            while index < fraction.len() {
                let count = step.min(fraction.len() - index);
                let end = index + count;
                let digits = unsafe { std::str::from_utf8_unchecked(&fraction[index..end]) };
                let tmp = u64::from_str_radix(digits, radix).unwrap();
                ffrac *= pow.clone();
                ffrac += BigFraction::new(tmp, 1u64);
                index = end;
            }

            let exp_shift = fraction.len() as i32 - exponent;
            let ffrac_exp_num;
            let ffrac_exp_den;
            if exp_shift > 0 {
                ffrac_exp_num = 0;
                ffrac_exp_den = exp_shift;
            } else {
                ffrac_exp_num = -exp_shift;
                ffrac_exp_den = 0;
            }

            ffrac *= BigFraction::from((radix as f64).powi(ffrac_exp_num));
            ffrac /= BigFraction::from((radix as f64).powi(ffrac_exp_den));

            (fint + ffrac).$cb().unwrap()
        }
    };
}

parse_float!(parse_f32, f32, to_f32);
parse_float!(parse_f64, f64, to_f64);