Accurate decimal-to-float parsing routines.

This commit primarily adds implementations of the algorithms from William
Clinger's paper "How to Read Floating Point Numbers Accurately". It also
includes a lot of infrastructure necessary for those algorithms, and some
unit tests.

Since these algorithms reject a few (extreme) inputs that were previously
accepted, this could be seen as a [breaking-change]
This commit is contained in:
Robin Kruppe
2015-07-26 17:50:29 +02:00
parent b7e39a1c2d
commit ba792a4baa
13 changed files with 2787 additions and 15 deletions
+353
View File
@@ -0,0 +1,353 @@
// 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.
//! The various algorithms from the paper.
use num::flt2dec::strategy::grisu::Fp;
use prelude::v1::*;
use cmp::min;
use cmp::Ordering::{Less, Equal, Greater};
use super::table;
use super::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float};
use super::num::{self, Big};
/// Number of significand bits in Fp
const P: u32 = 64;
// We simply store the best approximation for *all* exponents, so
// the variable "h" and the associated conditions can be omitted.
// This trades performance for space (11 KiB versus... 5 KiB or so?)
fn power_of_ten(e: i16) -> Fp {
assert!(e >= table::MIN_E);
let i = e - table::MIN_E;
let sig = table::POWERS.0[i as usize];
let exp = table::POWERS.1[i as usize];
Fp { f: sig, e: exp }
}
/// The fast path of Bellerophon using machine-sized integers and floats.
///
/// This is extracted into a separate function so that it can be attempted before constructing
/// a bignum.
pub fn fast_path<T: RawFloat>(integral: &[u8], fractional: &[u8], e: i64) -> Option<T> {
let num_digits = integral.len() + fractional.len();
// log_10(f64::max_sig) ~ 15.95. We compare the exact value to max_sig near the end,
// this is just a quick, cheap rejection (and also frees the rest of the code from
// worrying about underflow).
if num_digits > 16 {
return None;
}
if e.abs() >= T::ceil_log5_of_max_sig() as i64 {
return None;
}
let f = num::from_str_unchecked(integral.iter().chain(fractional.iter()));
if f > T::max_sig() {
return None;
}
let e = e as i16; // Can't overflow because e.abs() <= LOG5_OF_EXP_N
// The case e < 0 cannot be folded into the other branch. Negative powers result in
// a repeating fractional part in binary, which are rounded, which causes real
// (and occasioally quite significant!) errors in the final result.
// The case `e == 0`, however, is unnecessary for correctness. It's just measurably faster.
if e == 0 {
Some(T::from_int(f))
} else if e > 0 {
Some(T::from_int(f) * fp_to_float(power_of_ten(e)))
} else {
Some(T::from_int(f) / fp_to_float(power_of_ten(-e)))
}
}
/// Algorithm Bellerophon is trivial code justified by non-trivial numeric analysis.
///
/// It rounds ``f`` to a float with 64 bit significand and multiplies it by the best approximation
/// of `10^e` (in the same floating point format). This is often enough to get the correct result.
/// However, when the result is close to halfway between two adjecent (ordinary) floats, the
/// compound rounding error from multiplying two approximation means the result may be off by a
/// few bits. When this happens, the iterative Algorithm R fixes things up.
///
/// The hand-wavy "close to halfway" is made precise by the numeric analysis in the paper.
/// In the words of Clinger:
///
/// > Slop, expressed in units of the least significant bit, is an inclusive bound for the error
/// > accumulated during the floating point calculation of the approximation to f * 10^e. (Slop is
/// > not a bound for the true error, but bounds the difference between the approximation z and
/// > the best possible approximation that uses p bits of significand.)
pub fn bellerophon<T: RawFloat>(f: &Big, e: i16) -> T {
let slop;
if f <= &Big::from_u64(T::max_sig()) {
// The cases abs(e) < log5(2^N) are in fast_path()
slop = if e >= 0 { 0 } else { 3 };
} else {
slop = if e >= 0 { 1 } else { 4 };
}
let z = rawfp::big_to_fp(f).mul(&power_of_ten(e)).normalize();
let exp_p_n = 1 << (P - T::sig_bits() as u32);
let lowbits: i64 = (z.f % exp_p_n) as i64;
// Is the slop large enough to make a difference when
// rounding to n bits?
if (lowbits - exp_p_n as i64 / 2).abs() <= slop {
algorithm_r(f, e, fp_to_float(z))
} else {
fp_to_float(z)
}
}
/// An iterative algorithm that improves a floating point approximation of `f * 10^e`.
///
/// Each iteration gets one unit in the last place closer, which of course takes terribly long to
/// converge if `z0` is even mildly off. Luckily, when used as fallback for Bellerophon, the
/// starting approximation is off by at most one ULP.
fn algorithm_r<T: RawFloat>(f: &Big, e: i16, z0: T) -> T {
let mut z = z0;
loop {
let raw = z.unpack();
let (m, k) = (raw.sig, raw.k);
let mut x = f.clone();
let mut y = Big::from_u64(m);
// Find positive integers `x`, `y` such that `x / y` is exactly `(f * 10^e) / (m * 2^k)`.
// This not only avoids dealing with the signs of `e` and `k`, we also eliminate the
// power of two common to `10^e` and `2^k` to make the numbers smaller.
make_ratio(&mut x, &mut y, e, k);
let m_digits = [(m & 0xFF_FF_FF_FF) as u32, (m >> 32) as u32];
// This is written a bit awkwardly because our bignums don't support
// negative numbers, so we use the absolute value + sign information.
// The multiplication with m_digits can't overflow. If `x` or `y` are large enough that
// we need to worry about overflow, then they are also large enough that`make_ratio` has
// reduced the fraction by a factor of 2^64 or more.
let (d2, d_negative) = if x >= y {
// Don't need x any more, save a clone().
x.sub(&y).mul_pow2(1).mul_digits(&m_digits);
(x, false)
} else {
// Still need y - make a copy.
let mut y = y.clone();
y.sub(&x).mul_pow2(1).mul_digits(&m_digits);
(y, true)
};
if d2 < y {
let mut d2_double = d2;
d2_double.mul_pow2(1);
if m == T::min_sig() && d_negative && d2_double > y {
z = prev_float(z);
} else {
return z;
}
} else if d2 == y {
if m % 2 == 0 {
if m == T::min_sig() && d_negative {
z = prev_float(z);
} else {
return z;
}
} else if d_negative {
z = prev_float(z);
} else {
z = next_float(z);
}
} else if d_negative {
z = prev_float(z);
} else {
z = next_float(z);
}
}
}
/// Given `x = f` and `y = m` where `f` represent input decimal digits as usual and `m` is the
/// significand of a floating point approximation, make the ratio `x / y` equal to
/// `(f * 10^e) / (m * 2^k)`, possibly reduced by a power of two both have in common.
fn make_ratio(x: &mut Big, y: &mut Big, e: i16, k: i16) {
let (e_abs, k_abs) = (e.abs() as usize, k.abs() as usize);
if e >= 0 {
if k >= 0 {
// x = f * 10^e, y = m * 2^k, except that we reduce the fraction by some power of two.
let common = min(e_abs, k_abs);
x.mul_pow5(e_abs).mul_pow2(e_abs - common);
y.mul_pow2(k_abs - common);
} else {
// x = f * 10^e * 2^abs(k), y = m
// This can't overflow because it requires positive `e` and negative `k`, which can
// only happen for values extremely close to 1, which means that `e` and `k` will be
// comparatively tiny.
x.mul_pow5(e_abs).mul_pow2(e_abs + k_abs);
}
} else {
if k >= 0 {
// x = f, y = m * 10^abs(e) * 2^k
// This can't overflow either, see above.
y.mul_pow5(e_abs).mul_pow2(k_abs + e_abs);
} else {
// x = f * 2^abs(k), y = m * 10^abs(e), again reducing by a common power of two.
let common = min(e_abs, k_abs);
x.mul_pow2(k_abs - common);
y.mul_pow5(e_abs).mul_pow2(e_abs - common);
}
}
}
/// Conceptually, Algorithm M is the simplest way to convert a decimal to a float.
///
/// We form a ratio that is equal to `f * 10^e`, then throwing in powers of two until it gives
/// a valid float significand. The binary exponent `k` is the number of times we multiplied
/// numerator or denominator by two, i.e., at all times `f * 10^e` equals `(u / v) * 2^k`.
/// When we have found out significand, we only need to round by inspecting the remainder of the
/// division, which is done in helper functions further below.
///
/// This algorithm is super slow, even with the optimization described in `quick_start()`.
/// However, it's the simplest of the algorithms to adapt for overflow, underflow, and subnormal
/// results. This implementation takes over when Bellerophon and Algorithm R are overwhelmed.
/// Detecting underflow and overflow is easy: The ratio still isn't an in-range significand,
/// yet the minimum/maximum exponent has been reached. In the case of overflow, we simply return
/// infinity.
///
/// Handling underflow and subnormals is trickier. One big problem is that, with the minimum
/// exponent, the ratio might still be too large for a significand. See underflow() for details.
pub fn algorithm_m<T: RawFloat>(f: &Big, e: i16) -> T {
let mut u;
let mut v;
let e_abs = e.abs() as usize;
let mut k = 0;
if e < 0 {
u = f.clone();
v = Big::from_small(1);
v.mul_pow5(e_abs).mul_pow2(e_abs);
} else {
// FIXME possible optimization: generalize big_to_fp so that we can do the equivalent of
// fp_to_float(big_to_fp(u)) here, only without the double rounding.
u = f.clone();
u.mul_pow5(e_abs).mul_pow2(e_abs);
v = Big::from_small(1);
}
quick_start::<T>(&mut u, &mut v, &mut k);
let mut rem = Big::from_small(0);
let mut x = Big::from_small(0);
let min_sig = Big::from_u64(T::min_sig());
let max_sig = Big::from_u64(T::max_sig());
loop {
u.div_rem(&v, &mut x, &mut rem);
if k == T::min_exp_int() {
// We have to stop at the minimum exponent, if we wait until `k < T::min_exp_int()`,
// then we'd be off by a factor of two. Unfortunately this means we have to special-
// case normal numbers with the minimum exponent.
// FIXME find a more elegant formulation, but run the `tiny-pow10` test to make sure
// that it's actually correct!
if x >= min_sig && x <= max_sig {
break;
}
return underflow(x, v, rem);
}
if k > T::max_exp_int() {
return T::infinity();
}
if x < min_sig {
u.mul_pow2(1);
k -= 1;
} else if x > max_sig {
v.mul_pow2(1);
k += 1;
} else {
break;
}
}
let q = num::to_u64(&x);
let z = rawfp::encode_normal(Unpacked::new(q, k));
round_by_remainder(v, rem, q, z)
}
/// Skip over most AlgorithmM iterations by checking the bit length.
fn quick_start<T: RawFloat>(u: &mut Big, v: &mut Big, k: &mut i16) {
// The bit length is an estimate of the base two logarithm, and log(u / v) = log(u) - log(v).
// The estimate is off by at most 1, but always an under-estimate, so the error on log(u)
// and log(v) are of the same sign and cancel out (if both are large). Therefore the error
// for log(u / v) is at most one as well.
// The target ratio is one where u/v is in an in-range significand. Thus our termination
// condition is log2(u / v) being the significand bits, plus/minus one.
// FIXME Looking at the second bit could improve the estimate and avoid some more divisions.
let target_ratio = f64::sig_bits() as i16;
let log2_u = u.bit_length() as i16;
let log2_v = v.bit_length() as i16;
let mut u_shift: i16 = 0;
let mut v_shift: i16 = 0;
assert!(*k == 0);
loop {
if *k == T::min_exp_int() {
// Underflow or subnormal. Leave it to the main function.
break;
}
if *k == T::max_exp_int() {
// Overflow. Leave it to the main function.
break;
}
let log2_ratio = (log2_u + u_shift) - (log2_v + v_shift);
if log2_ratio < target_ratio - 1 {
u_shift += 1;
*k -= 1;
} else if log2_ratio > target_ratio + 1 {
v_shift += 1;
*k += 1;
} else {
break;
}
}
u.mul_pow2(u_shift as usize);
v.mul_pow2(v_shift as usize);
}
fn underflow<T: RawFloat>(x: Big, v: Big, rem: Big) -> T {
if x < Big::from_u64(T::min_sig()) {
let q = num::to_u64(&x);
let z = rawfp::encode_subnormal(q);
return round_by_remainder(v, rem, q, z);
}
// Ratio isn't an in-range significand with the minimum exponent, so we need to round off
// excess bits and adjust the exponent accordingly. The real value now looks like this:
//
// x lsb
// /--------------\/
// 1010101010101010.10101010101010 * 2^k
// \-----/\-------/ \------------/
// q trunc. (represented by rem)
//
// Therefore, when the rounded-off bits are != 0.5 ULP, they decide the rounding
// on their own. When they are equal and the remainder is non-zero, the value still
// needs to be rounded up. Only when the rounded off bits are 1/2 and the remainer
// is zero, we have a half-to-even situation.
let bits = x.bit_length();
let lsb = bits - T::sig_bits() as usize;
let q = num::get_bits(&x, lsb, bits);
let k = T::min_exp_int() + lsb as i16;
let z = rawfp::encode_normal(Unpacked::new(q, k));
let q_even = q % 2 == 0;
match num::compare_with_half_ulp(&x, lsb) {
Greater => next_float(z),
Less => z,
Equal if rem.is_zero() && q_even => z,
Equal => next_float(z),
}
}
/// Ordinary round-to-even, obfuscated by having to round based on the remainder of a division.
fn round_by_remainder<T: RawFloat>(v: Big, r: Big, q: u64, z: T) -> T {
let mut v_minus_r = v;
v_minus_r.sub(&r);
if r < v_minus_r {
z
} else if r > v_minus_r {
next_float(z)
} else if q % 2 == 0 {
z
} else {
next_float(z)
}
}
+234
View File
@@ -0,0 +1,234 @@
// 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.
//! Converting decimal strings into IEEE 754 binary floating point numbers.
//!
//! # Problem statement
//!
//! We are given a decimal string such as `12.34e56`. This string consists of integral (`12`),
//! fractional (`45`), and exponent (`56`) parts. All parts are optional and interpreted as zero
//! when missing.
//!
//! We seek the IEEE 754 floating point number that is closest to the exact value of the decimal
//! string. It is well-known that many decimal strings do not have terminating representations in
//! base two, so we round to 0.5 units in the last place (in other words, as well as possible).
//! Ties, decimal values exactly half-way between two consecutive floats, are resolved with the
//! half-to-even strategy, also known as banker's rounding.
//!
//! Needless to say, this is quite hard, both in terms of implementation complexity and in terms
//! of CPU cycles taken.
//!
//! # Implementation
//!
//! First, we ignore signs. Or rather, we remove it at the very beginning of the conversion
//! process and re-apply it at the very end. This is correct in all edge cases since IEEE
//! floats are symmetric around zero, negating one simply flips the first bit.
//!
//! Then we remove the decimal point by adjusting the exponent: Conceptually, `12.34e56` turns
//! into `1234e54`, which we describe with a positive integer `f = 1234` and an integer `e = 54`.
//! The `(f, e)` representation is used by almost all code past the parsing stage.
//!
//! We then try a long chain of progressively more general and expensive special cases using
//! machine-sized integers and small, fixed-sized floating point numbers (first `f32`/`f64`, then
//! a type with 64 bit significand, `Fp`). When all these fail, we bite the bullet and resort to a
//! simple but very slow algorithm that involved computing `f * 10^e` fully and doing an iterative
//! search for the best approximation.
//!
//! Primarily, this module and its children implement the algorithms described in:
//! "How to Read Floating Point Numbers Accurately" by William D. Clinger,
//! available online: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.45.4152
//!
//! In addition, there are numerous helper functions that are used in the paper but not available
//! in Rust (or at least in core). Our version is additionally complicated by the need to handle
//! overflow and underflow and the desire to handle subnormal numbers. Bellerophon and
//! Algorithm R have trouble with overflow, subnormals, and underflow. We conservatively switch to
//! Algorithm M (with the modifications described in section 8 of the paper) well before the
//! inputs get into the critical region.
//!
//! Another aspect that needs attention is the ``RawFloat`` trait by which almost all functions
//! are parametrized. One might think that it's enough to parse to `f64` and cast the result to
//! `f32`. Unfortunately this is not the world we live in, and this has nothing to do with using
//! base two or half-to-even rounding.
//!
//! Consider for example two types `d2` and `d4` representing a decimal type with two decimal
//! digits and four decimal digits each and take "0.01499" as input. Let's use half-up rounding.
//! Going directly to two decimal digits gives `0.01`, but if we round to four digits first,
//! we get `0.0150`, which is then rounded up to `0.02`. The same principle applies to other
//! operations as well, if you want 0.5 ULP accuracy you need to do *everything* in full precision
//! and round *exactly once, at the end*, by considering all truncated bits at once.
//!
//! FIXME Although some code duplication is necessary, perhaps parts of the code could be shuffled
//! around such that less code is duplicated. Large parts of the algorithms are independent of the
//! float type to output, or only needs access to a few constants, which could be passed in as
//! parameters.
//!
//! # Other
//!
//! The conversion should *never* panic. There are assertions and explicit panics in the code,
//! but they should never be triggered and only serve as internal sanity checks. Any panics should
//! be considered a bug.
//!
//! There are unit tests but they are woefully inadequate at ensuring correctness, they only cover
//! a small percentage of possible errors. Far more extensive tests are located in the directory
//! `src/etc/test-float-parse` as a Python script.
//!
//! A note on integer overflow: Many parts of this file perform arithmetic with the decimal
//! exponent `e`. Primarily, we shift the decimal point around: Before the first decimal digit,
//! after the last decimal digit, and so on. This could overflow if done carelessly. We rely on
//! the parsing submodule to only hand out sufficiently small exponents, where "sufficient" means
//! "such that the exponent +/- the number of decimal digits fits into a 64 bit integer".
//! Larger exponents are accepted, but we don't do arithmetic with them, they are immediately
//! turned into {positive,negative} {zero,infinity}.
//!
//! FIXME: this uses several things from core::num::flt2dec, which is nonsense. Those things
//! should be moved into core::num::<something else>.
#![doc(hidden)]
#![unstable(feature = "dec2flt",
reason = "internal routines only exposed for testing")]
use prelude::v1::*;
use num::ParseFloatError as PFE;
use num::FloatErrorKind;
use self::parse::{parse_decimal, Decimal, Sign};
use self::parse::ParseResult::{self, Valid, ShortcutToInf, ShortcutToZero};
use self::num::digits_to_big;
use self::rawfp::RawFloat;
mod algorithm;
mod table;
mod num;
// These two have their own tests.
pub mod rawfp;
pub mod parse;
/// Entry point for decimal-to-f32 conversion.
pub fn to_f32(s: &str) -> Result<f32, PFE> {
dec2flt(s)
}
/// Entry point for decimal-to-f64 conversion.
pub fn to_f64(s: &str) -> Result<f64, PFE> {
dec2flt(s)
}
/// Split decimal string into sign and the rest, without inspecting or validating the rest.
fn extract_sign(s: &str) -> (Sign, &str) {
match s.as_bytes()[0] {
b'+' => (Sign::Positive, &s[1..]),
b'-' => (Sign::Negative, &s[1..]),
// If the string is invalid, we never use the sign, so we don't need to validate here.
_ => (Sign::Positive, s),
}
}
/// Convert a decimal string into a floating point number.
fn dec2flt<T: RawFloat>(s: &str) -> Result<T, PFE> {
if s.is_empty() {
return Err(PFE { __kind: FloatErrorKind::Empty });
}
let (sign, s) = extract_sign(s);
let flt = match parse_decimal(s) {
Valid(decimal) => try!(convert(decimal)),
ShortcutToInf => T::infinity(),
ShortcutToZero => T::zero(),
ParseResult::Invalid => match s {
"inf" => T::infinity(),
"NaN" => T::nan(),
_ => { return Err(PFE { __kind: FloatErrorKind::Invalid }); }
}
};
match sign {
Sign::Positive => Ok(flt),
Sign::Negative => Ok(-flt),
}
}
/// The main workhorse for the decimal-to-float conversion: Orchestrate all the preprocessing
/// and figure out which algorithm should do the actual conversion.
fn convert<T: RawFloat>(mut decimal: Decimal) -> Result<T, PFE> {
simplify(&mut decimal);
if let Some(x) = trivial_cases(&decimal) {
return Ok(x);
}
// AlgorithmM and AlgorithmR both compute approximately `f * 10^e`.
let max_digits = decimal.integral.len() + decimal.fractional.len() +
decimal.exp.abs() as usize;
// Remove/shift out the decimal point.
let e = decimal.exp - decimal.fractional.len() as i64;
if let Some(x) = algorithm::fast_path(decimal.integral, decimal.fractional, e) {
return Ok(x);
}
// Big32x40 is limited to 1280 bits, which translates to about 385 decimal digits.
// If we exceed this, perhaps while calculating `f * 10^e` in Algorithm R or Algorithm M,
// we'll crash. So we error out before getting too close, with a generous safety margin.
if max_digits > 375 {
return Err(PFE { __kind: FloatErrorKind::Invalid });
}
let f = digits_to_big(decimal.integral, decimal.fractional);
// Now the exponent certainly fits in 16 bit, which is used throughout the main algorithms.
let e = e as i16;
// FIXME These bounds are rather conservative. A more careful analysis of the failure modes
// of Bellerophon could allow using it in more cases for a massive speed up.
let exponent_in_range = table::MIN_E <= e && e <= table::MAX_E;
let value_in_range = max_digits <= T::max_normal_digits();
if exponent_in_range && value_in_range {
Ok(algorithm::bellerophon(&f, e))
} else {
Ok(algorithm::algorithm_m(&f, e))
}
}
// As written, this optimizes badly (see #27130, though it refers to an old version of the code).
// `inline(always)` is a workaround for that. There are only two call sites overall and it doesn't
// make code size worse.
/// Strip zeros where possible, even when this requires changing the exponent
#[inline(always)]
fn simplify(decimal: &mut Decimal) {
let is_zero = &|&&d: &&u8| -> bool { d == b'0' };
// Trimming these zeros does not change anything but may enable the fast path (< 15 digits).
let leading_zeros = decimal.integral.iter().take_while(is_zero).count();
decimal.integral = &decimal.integral[leading_zeros..];
let trailing_zeros = decimal.fractional.iter().rev().take_while(is_zero).count();
let end = decimal.fractional.len() - trailing_zeros;
decimal.fractional = &decimal.fractional[..end];
// Simplify numbers of the form 0.0...x and x...0.0, adjusting the exponent accordingly.
// This may not always be a win (possibly pushes some numbers out of the fast path), but it
// simplifies other parts significantly (notably, approximating the magnitude of the value).
if decimal.integral.is_empty() {
let leading_zeros = decimal.fractional.iter().take_while(is_zero).count();
decimal.fractional = &decimal.fractional[leading_zeros..];
decimal.exp -= leading_zeros as i64;
} else if decimal.fractional.is_empty() {
let trailing_zeros = decimal.integral.iter().rev().take_while(is_zero).count();
let end = decimal.integral.len() - trailing_zeros;
decimal.integral = &decimal.integral[..end];
decimal.exp += trailing_zeros as i64;
}
}
/// Detect obvious overflows and underflows without even looking at the decimal digits.
fn trivial_cases<T: RawFloat>(decimal: &Decimal) -> Option<T> {
// There were zeros but they were stripped by simplify()
if decimal.integral.is_empty() && decimal.fractional.is_empty() {
return Some(T::zero());
}
// This is a crude approximation of ceil(log10(the real value)).
let max_place = decimal.exp + decimal.integral.len() as i64;
if max_place > T::inf_cutoff() {
return Some(T::infinity());
} else if max_place < T::zero_cutoff() {
return Some(T::zero());
}
None
}
+95
View File
@@ -0,0 +1,95 @@
// 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.
//! Utility functions for bignums that don't make too much sense to turn into methods.
// FIXME This module's name is a bit unfortunate, since other modules also import `core::num`.
use prelude::v1::*;
use cmp::Ordering::{self, Less, Equal, Greater};
use num::flt2dec::bignum::Big32x40;
pub type Big = Big32x40;
/// Test whether truncating all bits less significant than `ones_place` introduces
/// a relative error less, equal, or greater than 0.5 ULP.
pub fn compare_with_half_ulp(f: &Big, ones_place: usize) -> Ordering {
if ones_place == 0 {
return Less;
}
let half_bit = ones_place - 1;
if f.get_bit(half_bit) == 0 {
// < 0.5 ULP
return Less;
}
// If all remaining bits are zero, it's = 0.5 ULP, otherwise > 0.5
// If there are no more bits (half_bit == 0), the below also correctly returns Equal.
for i in 0..half_bit {
if f.get_bit(i) == 1 {
return Greater;
}
}
Equal
}
/// Convert an ASCII string containing only decimal digits to a `u64`.
///
/// Does not perform checks for overflow or invalid characters, so if the caller is not careful,
/// the result is bogus and can panic (though it won't be `unsafe`). Additionally, empty strings
/// are treated as zero. This function exists because
///
/// 1. using `FromStr` on `&[u8]` requires `from_utf8_unchecked`, which is bad, and
/// 2. piecing together the results of `integral.parse()` and `fractional.parse()` is
/// more complicated than this entire function.
pub fn from_str_unchecked<'a, T>(bytes: T) -> u64 where T : IntoIterator<Item=&'a u8> {
let mut result = 0;
for &c in bytes {
result = result * 10 + (c - b'0') as u64;
}
result
}
/// Convert a string of ASCII digits into a bignum.
///
/// Like `from_str_unchecked`, this function relies on the parser to weed out non-digits.
pub fn digits_to_big(integral: &[u8], fractional: &[u8]) -> Big {
let mut f = Big::from_small(0);
for &c in integral.iter().chain(fractional) {
let n = (c - b'0') as u32;
f.mul_small(10);
f.add_small(n);
}
f
}
/// Unwraps a bignum into a 64 bit integer. Panics if the number is too large.
pub fn to_u64(x: &Big) -> u64 {
assert!(x.bit_length() < 64);
let d = x.digits();
if d.len() < 2 {
d[0] as u64
} else {
(d[1] as u64) << 32 | d[0] as u64
}
}
/// Extract a range of bits.
/// Index 0 is the least significant bit and the range is half-open as usual.
/// Panics if asked to extract more bits than fit into the return type.
pub fn get_bits(x: &Big, start: usize, end: usize) -> u64 {
assert!(end - start <= 64);
let mut result: u64 = 0;
for i in (start..end).rev() {
result = result << 1 | x.get_bit(i) as u64;
}
result
}
+128
View File
@@ -0,0 +1,128 @@
// 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.
//! Validating and decomposing a decimal string of the form:
//!
//! `(digits | digits? '.'? digits?) (('e' | 'E') ('+' | '-')? digits)?`
//!
//! In other words, standard floating-point syntax, with two exceptions: No sign, and no
//! handling of "inf" and "NaN". These are handled by the driver function (super::dec2flt).
//!
//! Although recognizing valid inputs is relatively easy, this module also has to reject the
//! countless invalid variations, never panic, and perform numerous checks that the other
//! modules rely on to not panic (or overflow) in turn.
//! To make matters worse, all that happens in a single pass over the input.
//! So, be careful when modifying anything, and double-check with the other modules.
use prelude::v1::*;
use super::num;
use self::ParseResult::{Valid, ShortcutToInf, ShortcutToZero, Invalid};
#[derive(Debug)]
pub enum Sign {
Positive,
Negative,
}
#[derive(Debug, PartialEq, Eq)]
/// The interesting parts of a decimal string.
pub struct Decimal<'a> {
pub integral: &'a [u8],
pub fractional: &'a [u8],
/// The decimal exponent, guaranteed to have fewer than 18 decimal digits.
pub exp: i64,
}
impl<'a> Decimal<'a> {
pub fn new(integral: &'a [u8], fractional: &'a [u8], exp: i64) -> Decimal<'a> {
Decimal { integral: integral, fractional: fractional, exp: exp }
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum ParseResult<'a> {
Valid(Decimal<'a>),
ShortcutToInf,
ShortcutToZero,
Invalid,
}
/// Check if the input string is a valid floating point number and if so, locate the integral
/// part, the fractional part, and the exponent in it. Does not handle signs.
pub fn parse_decimal(s: &str) -> ParseResult {
let s = s.as_bytes();
let (integral, s) = eat_digits(s);
match s.first() {
None => Valid(Decimal::new(integral, b"", 0)),
Some(&b'e') | Some(&b'E') => {
if integral.is_empty() {
return Invalid; // No digits before 'e'
}
parse_exp(integral, b"", &s[1..])
}
Some(&b'.') => {
let (fractional, s) = eat_digits(&s[1..]);
if integral.is_empty() && fractional.is_empty() && s.is_empty() {
// For historic reasons "." is a valid input.
return Valid(Decimal::new(b"", b"", 0));
}
match s.first() {
None => Valid(Decimal::new(integral, fractional, 0)),
Some(&b'e') | Some(&b'E') => parse_exp(integral, fractional, &s[1..]),
_ => Invalid, // Trailing junk after fractional part
}
}
_ => Invalid, // Trailing junk after first digit string
}
}
/// Carve off decimal digits up to the first non-digit character.
fn eat_digits(s: &[u8]) -> (&[u8], &[u8]) {
let mut i = 0;
while i < s.len() && b'0' <= s[i] && s[i] <= b'9' {
i += 1;
}
(&s[..i], &s[i..])
}
/// Exponent extraction and error checking.
fn parse_exp<'a>(integral: &'a [u8], fractional: &'a [u8], rest: &'a [u8]) -> ParseResult<'a> {
let (sign, rest) = match rest.first() {
Some(&b'-') => (Sign::Negative, &rest[1..]),
Some(&b'+') => (Sign::Positive, &rest[1..]),
_ => (Sign::Positive, rest),
};
let (mut number, trailing) = eat_digits(rest);
if !trailing.is_empty() {
return Invalid; // Trailing junk after exponent
}
if number.is_empty() {
return Invalid; // Empty exponent
}
// At this point, we certainly have a valid string of digits. It may be too long to put into
// an `i64`, but if it's that huge, the input is certainly zero or infinity. Since each zero
// in the decimal digits only adjusts the exponent by +/- 1, at exp = 10^18 the input would
// have to be 17 exabyte (!) of zeros to get even remotely close to being finite.
// This is not exactly a use case we need to cater to.
while number.first() == Some(&b'0') {
number = &number[1..];
}
if number.len() >= 18 {
return match sign {
Sign::Positive => ShortcutToInf,
Sign::Negative => ShortcutToZero,
};
}
let abs_exp = num::from_str_unchecked(number);
let e = match sign {
Sign::Positive => abs_exp as i64,
Sign::Negative => -(abs_exp as i64),
};
Valid(Decimal::new(integral, fractional, e))
}
+356
View File
@@ -0,0 +1,356 @@
// 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.
//! Bit fiddling on positive IEEE 754 floats. Negative numbers aren't and needn't be handled.
//! Normal floating point numbers have a canonical representation as (frac, exp) such that the
//! value is 2^exp * (1 + sum(frac[N-i] / 2^i)) where N is the number of bits. Subnormals are
//! slightly different and weird, but the same principle applies.
//!
//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * 2^e.
//! Besides making the "hidden bit" explicit, this changes the exponent by the so-called
//! mantissa shift.
//!
//! Put another way, normally floats are written as (1) but here they are written as (2):
//!
//! 1. `1.101100...11 * 2^m`
//! 2. `1101100...11 * 2^n`
//!
//! We call (1) the **fractional representation** and (2) the **integral representation**.
//!
//! Many functions in this module only handle normal numbers. The dec2flt routines conservatively
//! take the universally-correct slow path (Algorithm M) for very small and very large numbers.
//! That algorithm needs only next_float() which does handle subnormals and zeros.
use prelude::v1::*;
use u32;
use cmp::Ordering::{Less, Equal, Greater};
use ops::{Mul, Div, Neg};
use fmt::{Debug, LowerExp};
use mem::transmute;
use num::flt2dec::strategy::grisu::Fp;
use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
use num::Float;
use super::num::{self, Big};
#[derive(Copy, Clone, Debug)]
pub struct Unpacked {
pub sig: u64,
pub k: i16,
}
impl Unpacked {
pub fn new(sig: u64, k: i16) -> Self {
Unpacked { sig: sig, k: k }
}
}
/// A helper trait to avoid duplicating basically all the conversion code for `f32` and `f64`.
///
/// See the parent module's doc comment for why this is necessary.
///
/// Should **never ever** be implemented for other types or be used outside the dec2flt module.
/// Inherits from `Float` because there is some overlap, but all the reused methods are trivial.
/// The "methods" (pseudo-constants) with default implementation should not be overriden.
pub trait RawFloat : Float + Copy + Debug + LowerExp
+ Mul<Output=Self> + Div<Output=Self> + Neg<Output=Self>
{
/// Get the raw binary representation of the float.
fn transmute(self) -> u64;
/// Transmute the raw binary representation into a float.
fn from_bits(bits: u64) -> Self;
/// Decode the float.
fn unpack(self) -> Unpacked;
/// Cast from a small integer that can be represented exactly. Panic if the integer can't be
/// represented, the other code in this module makes sure to never let that happen.
fn from_int(x: u64) -> Self;
// FIXME Everything that follows should be associated constants, but taking the value of an
// associated constant from a type parameter does not work (yet?)
// A possible workaround is having a `FloatInfo` struct for all the constants, but so far
// the methods aren't painful enough to rewrite.
/// What the name says. It's easier to hard code than juggling intrinsics and
/// hoping LLVM constant folds it.
fn ceil_log5_of_max_sig() -> i16;
// A conservative bound on the decimal digits of inputs that can't produce overflow or zero or
/// subnormals. Probably the decimal exponent of the maximum normal value, hence the name.
fn max_normal_digits() -> usize;
/// When the most significant decimal digit has a place value greater than this, the number
/// is certainly rounded to infinity.
fn inf_cutoff() -> i64;
/// When the most significant decimal digit has a place value less than this, the number
/// is certainly rounded to zero.
fn zero_cutoff() -> i64;
/// The number of bits in the exponent.
fn exp_bits() -> u8;
/// The number of bits in the singificand, *including* the hidden bit.
fn sig_bits() -> u8;
/// The number of bits in the singificand, *excluding* the hidden bit.
fn explicit_sig_bits() -> u8 {
Self::sig_bits() - 1
}
/// The maximum legal exponent in fractional representation.
fn max_exp() -> i16 {
(1 << (Self::exp_bits() - 1)) - 1
}
/// The minimum legal exponent in fractional representation, excluding subnormals.
fn min_exp() -> i16 {
-Self::max_exp() + 1
}
/// `MAX_EXP` for integral representation, i.e., with the shift applied.
fn max_exp_int() -> i16 {
Self::max_exp() - (Self::sig_bits() as i16 - 1)
}
/// `MAX_EXP` encoded (i.e., with offset bias)
fn max_encoded_exp() -> i16 {
(1 << Self::exp_bits()) - 1
}
/// `MIN_EXP` for integral representation, i.e., with the shift applied.
fn min_exp_int() -> i16 {
Self::min_exp() - (Self::sig_bits() as i16 - 1)
}
/// The maximum normalized singificand in integral representation.
fn max_sig() -> u64 {
(1 << Self::sig_bits()) - 1
}
/// The minimal normalized significand in integral representation.
fn min_sig() -> u64 {
1 << (Self::sig_bits() - 1)
}
}
impl RawFloat for f32 {
fn sig_bits() -> u8 {
24
}
fn exp_bits() -> u8 {
8
}
fn ceil_log5_of_max_sig() -> i16 {
11
}
fn transmute(self) -> u64 {
let bits: u32 = unsafe { transmute(self) };
bits as u64
}
fn from_bits(bits: u64) -> f32 {
assert!(bits < u32::MAX as u64, "f32::from_bits: too many bits");
unsafe { transmute(bits as u32) }
}
fn unpack(self) -> Unpacked {
let (sig, exp, _sig) = self.integer_decode();
Unpacked::new(sig, exp)
}
fn from_int(x: u64) -> f32 {
// rkruppe is uncertain whether `as` rounds correctly on all platforms.
debug_assert!(x as f32 == fp_to_float(Fp { f: x, e: 0 }));
x as f32
}
fn max_normal_digits() -> usize {
35
}
fn inf_cutoff() -> i64 {
40
}
fn zero_cutoff() -> i64 {
-48
}
}
impl RawFloat for f64 {
fn sig_bits() -> u8 {
53
}
fn exp_bits() -> u8 {
11
}
fn ceil_log5_of_max_sig() -> i16 {
23
}
fn transmute(self) -> u64 {
let bits: u64 = unsafe { transmute(self) };
bits
}
fn from_bits(bits: u64) -> f64 {
unsafe { transmute(bits) }
}
fn unpack(self) -> Unpacked {
let (sig, exp, _sig) = self.integer_decode();
Unpacked::new(sig, exp)
}
fn from_int(x: u64) -> f64 {
// rkruppe is uncertain whether `as` rounds correctly on all platforms.
debug_assert!(x as f64 == fp_to_float(Fp { f: x, e: 0 }));
x as f64
}
fn max_normal_digits() -> usize {
305
}
fn inf_cutoff() -> i64 {
310
}
fn zero_cutoff() -> i64 {
-326
}
}
/// Convert an Fp to the closest f64. Only handles number that fit into a normalized f64.
pub fn fp_to_float<T: RawFloat>(x: Fp) -> T {
let x = x.normalize();
// x.f is 64 bit, so x.e has a mantissa shift of 63
let e = x.e + 63;
if e > T::max_exp() {
panic!("fp_to_float: exponent {} too large", e)
} else if e > T::min_exp() {
encode_normal(round_normal::<T>(x))
} else {
panic!("fp_to_float: exponent {} too small", e)
}
}
/// Round the 64-bit significand to 53 bit with half-to-even. Does not handle exponent overflow.
pub fn round_normal<T: RawFloat>(x: Fp) -> Unpacked {
let excess = 64 - T::sig_bits() as i16;
let half: u64 = 1 << (excess - 1);
let (q, rem) = (x.f >> excess, x.f & ((1 << excess) - 1));
assert_eq!(q << excess | rem, x.f);
// Adjust mantissa shift
let k = x.e + excess;
if rem < half {
Unpacked::new(q, k)
} else if rem == half && (q % 2) == 0 {
Unpacked::new(q, k)
} else if q == T::max_sig() {
Unpacked::new(T::min_sig(), k + 1)
} else {
Unpacked::new(q + 1, k)
}
}
/// Inverse of `RawFloat::unpack()` for normalized numbers.
/// Panics if the significand or exponent are not valid for normalized numbers.
pub fn encode_normal<T: RawFloat>(x: Unpacked) -> T {
debug_assert!(T::min_sig() <= x.sig && x.sig <= T::max_sig(),
"encode_normal: significand not normalized");
// Remove the hidden bit
let sig_enc = x.sig & !(1 << T::explicit_sig_bits());
// Adjust the exponent for exponent bias and mantissa shift
let k_enc = x.k + T::max_exp() + T::explicit_sig_bits() as i16;
debug_assert!(k_enc != 0 && k_enc < T::max_encoded_exp(),
"encode_normal: exponent out of range");
// Leave sign bit at 0 ("+"), our numbers are all positive
let bits = (k_enc as u64) << T::explicit_sig_bits() | sig_enc;
T::from_bits(bits)
}
/// Construct the subnormal. A mantissa of 0 is allowed and constructs zero.
pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T {
assert!(significand < T::min_sig(), "encode_subnormal: not actually subnormal");
// Êncoded exponent is 0, the sign bit is 0, so we just have to reinterpret the bits.
T::from_bits(significand)
}
/// Approximate a bignum with an Fp. Rounds within 0.5 ULP with half-to-even.
pub fn big_to_fp(f: &Big) -> Fp {
let end = f.bit_length();
assert!(end != 0, "big_to_fp: unexpectedly, input is zero");
let start = end.saturating_sub(64);
let leading = num::get_bits(f, start, end);
// We cut off all bits prior to the index `start`, i.e., we effectively right-shift by
// an amount of `start`, so this is also the exponent we need.
let e = start as i16;
let rounded_down = Fp { f: leading, e: e }.normalize();
// Round (half-to-even) depending on the truncated bits.
match num::compare_with_half_ulp(f, start) {
Less => rounded_down,
Equal if leading % 2 == 0 => rounded_down,
Equal | Greater => match leading.checked_add(1) {
Some(f) => Fp { f: f, e: e }.normalize(),
None => Fp { f: 1 << 63, e: e + 1 },
}
}
}
/// Find the largest floating point number strictly smaller than the argument.
/// Does not handle subnormals, zero, or exponent underflow.
pub fn prev_float<T: RawFloat>(x: T) -> T {
match x.classify() {
Infinite => panic!("prev_float: argument is infinite"),
Nan => panic!("prev_float: argument is NaN"),
Subnormal => panic!("prev_float: argument is subnormal"),
Zero => panic!("prev_float: argument is zero"),
Normal => {
let Unpacked { sig, k } = x.unpack();
if sig == T::min_sig() {
encode_normal(Unpacked::new(T::max_sig(), k - 1))
} else {
encode_normal(Unpacked::new(sig - 1, k))
}
}
}
}
// Find the smallest floating point number strictly larger than the argument.
// This operation is saturating, i.e. next_float(inf) == inf.
// Unlike most code in this module, this function does handle zero, subnormals, and infinities.
// However, like all other code here, it does not deal with NaN and negative numbers.
pub fn next_float<T: RawFloat>(x: T) -> T {
match x.classify() {
Nan => panic!("next_float: argument is NaN"),
Infinite => T::infinity(),
// This seems too good to be true, but it works.
// 0.0 is encoded as the all-zero word. Subnormals are 0x000m...m where m is the mantissa.
// In particular, the smallest subnormal is 0x0...01 and the largest is 0x000F...F.
// The smallest normal number is 0x0010...0, so this corner case works as well.
// If the increment overflows the mantissa, the carry bit increments the exponent as we
// want, and the mantissa bits become zero. Because of the hidden bit convention, this
// too is exactly what we want!
// Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY.
Zero | Subnormal | Normal => {
let bits: u64 = x.transmute();
T::from_bits(bits + 1)
}
}
}
+1239
View File
@@ -0,0 +1,1239 @@
// 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.
// Table of approximations of powers of ten.
// DO NOT MODIFY: Generated by a src/etc/dec2flt_table.py
pub const MIN_E: i16 = -305;
pub const MAX_E: i16 = 305;
pub const POWERS: ([u64; 611], [i16; 611]) = ([
0xe0b62e2929aba83c,
0x8c71dcd9ba0b4926,
0xaf8e5410288e1b6f,
0xdb71e91432b1a24b,
0x892731ac9faf056f,
0xab70fe17c79ac6ca,
0xd64d3d9db981787d,
0x85f0468293f0eb4e,
0xa76c582338ed2622,
0xd1476e2c07286faa,
0x82cca4db847945ca,
0xa37fce126597973d,
0xcc5fc196fefd7d0c,
0xff77b1fcbebcdc4f,
0x9faacf3df73609b1,
0xc795830d75038c1e,
0xf97ae3d0d2446f25,
0x9becce62836ac577,
0xc2e801fb244576d5,
0xf3a20279ed56d48a,
0x9845418c345644d7,
0xbe5691ef416bd60c,
0xedec366b11c6cb8f,
0x94b3a202eb1c3f39,
0xb9e08a83a5e34f08,
0xe858ad248f5c22ca,
0x91376c36d99995be,
0xb58547448ffffb2e,
0xe2e69915b3fff9f9,
0x8dd01fad907ffc3c,
0xb1442798f49ffb4b,
0xdd95317f31c7fa1d,
0x8a7d3eef7f1cfc52,
0xad1c8eab5ee43b67,
0xd863b256369d4a41,
0x873e4f75e2224e68,
0xa90de3535aaae202,
0xd3515c2831559a83,
0x8412d9991ed58092,
0xa5178fff668ae0b6,
0xce5d73ff402d98e4,
0x80fa687f881c7f8e,
0xa139029f6a239f72,
0xc987434744ac874f,
0xfbe9141915d7a922,
0x9d71ac8fada6c9b5,
0xc4ce17b399107c23,
0xf6019da07f549b2b,
0x99c102844f94e0fb,
0xc0314325637a193a,
0xf03d93eebc589f88,
0x96267c7535b763b5,
0xbbb01b9283253ca3,
0xea9c227723ee8bcb,
0x92a1958a7675175f,
0xb749faed14125d37,
0xe51c79a85916f485,
0x8f31cc0937ae58d3,
0xb2fe3f0b8599ef08,
0xdfbdcece67006ac9,
0x8bd6a141006042be,
0xaecc49914078536d,
0xda7f5bf590966849,
0x888f99797a5e012d,
0xaab37fd7d8f58179,
0xd5605fcdcf32e1d7,
0x855c3be0a17fcd26,
0xa6b34ad8c9dfc070,
0xd0601d8efc57b08c,
0x823c12795db6ce57,
0xa2cb1717b52481ed,
0xcb7ddcdda26da269,
0xfe5d54150b090b03,
0x9efa548d26e5a6e2,
0xc6b8e9b0709f109a,
0xf867241c8cc6d4c1,
0x9b407691d7fc44f8,
0xc21094364dfb5637,
0xf294b943e17a2bc4,
0x979cf3ca6cec5b5b,
0xbd8430bd08277231,
0xece53cec4a314ebe,
0x940f4613ae5ed137,
0xb913179899f68584,
0xe757dd7ec07426e5,
0x9096ea6f3848984f,
0xb4bca50b065abe63,
0xe1ebce4dc7f16dfc,
0x8d3360f09cf6e4bd,
0xb080392cc4349ded,
0xdca04777f541c568,
0x89e42caaf9491b61,
0xac5d37d5b79b6239,
0xd77485cb25823ac7,
0x86a8d39ef77164bd,
0xa8530886b54dbdec,
0xd267caa862a12d67,
0x8380dea93da4bc60,
0xa46116538d0deb78,
0xcd795be870516656,
0x806bd9714632dff6,
0xa086cfcd97bf97f4,
0xc8a883c0fdaf7df0,
0xfad2a4b13d1b5d6c,
0x9cc3a6eec6311a64,
0xc3f490aa77bd60fd,
0xf4f1b4d515acb93c,
0x991711052d8bf3c5,
0xbf5cd54678eef0b7,
0xef340a98172aace5,
0x9580869f0e7aac0f,
0xbae0a846d2195713,
0xe998d258869facd7,
0x91ff83775423cc06,
0xb67f6455292cbf08,
0xe41f3d6a7377eeca,
0x8e938662882af53e,
0xb23867fb2a35b28e,
0xdec681f9f4c31f31,
0x8b3c113c38f9f37f,
0xae0b158b4738705f,
0xd98ddaee19068c76,
0x87f8a8d4cfa417ca,
0xa9f6d30a038d1dbc,
0xd47487cc8470652b,
0x84c8d4dfd2c63f3b,
0xa5fb0a17c777cf0a,
0xcf79cc9db955c2cc,
0x81ac1fe293d599c0,
0xa21727db38cb0030,
0xca9cf1d206fdc03c,
0xfd442e4688bd304b,
0x9e4a9cec15763e2f,
0xc5dd44271ad3cdba,
0xf7549530e188c129,
0x9a94dd3e8cf578ba,
0xc13a148e3032d6e8,
0xf18899b1bc3f8ca2,
0x96f5600f15a7b7e5,
0xbcb2b812db11a5de,
0xebdf661791d60f56,
0x936b9fcebb25c996,
0xb84687c269ef3bfb,
0xe65829b3046b0afa,
0x8ff71a0fe2c2e6dc,
0xb3f4e093db73a093,
0xe0f218b8d25088b8,
0x8c974f7383725573,
0xafbd2350644eead0,
0xdbac6c247d62a584,
0x894bc396ce5da772,
0xab9eb47c81f5114f,
0xd686619ba27255a3,
0x8613fd0145877586,
0xa798fc4196e952e7,
0xd17f3b51fca3a7a1,
0x82ef85133de648c5,
0xa3ab66580d5fdaf6,
0xcc963fee10b7d1b3,
0xffbbcfe994e5c620,
0x9fd561f1fd0f9bd4,
0xc7caba6e7c5382c9,
0xf9bd690a1b68637b,
0x9c1661a651213e2d,
0xc31bfa0fe5698db8,
0xf3e2f893dec3f126,
0x986ddb5c6b3a76b8,
0xbe89523386091466,
0xee2ba6c0678b597f,
0x94db483840b717f0,
0xba121a4650e4ddec,
0xe896a0d7e51e1566,
0x915e2486ef32cd60,
0xb5b5ada8aaff80b8,
0xe3231912d5bf60e6,
0x8df5efabc5979c90,
0xb1736b96b6fd83b4,
0xddd0467c64bce4a1,
0x8aa22c0dbef60ee4,
0xad4ab7112eb3929e,
0xd89d64d57a607745,
0x87625f056c7c4a8b,
0xa93af6c6c79b5d2e,
0xd389b47879823479,
0x843610cb4bf160cc,
0xa54394fe1eedb8ff,
0xce947a3da6a9273e,
0x811ccc668829b887,
0xa163ff802a3426a9,
0xc9bcff6034c13053,
0xfc2c3f3841f17c68,
0x9d9ba7832936edc1,
0xc5029163f384a931,
0xf64335bcf065d37d,
0x99ea0196163fa42e,
0xc06481fb9bcf8d3a,
0xf07da27a82c37088,
0x964e858c91ba2655,
0xbbe226efb628afeb,
0xeadab0aba3b2dbe5,
0x92c8ae6b464fc96f,
0xb77ada0617e3bbcb,
0xe55990879ddcaabe,
0x8f57fa54c2a9eab7,
0xb32df8e9f3546564,
0xdff9772470297ebd,
0x8bfbea76c619ef36,
0xaefae51477a06b04,
0xdab99e59958885c5,
0x88b402f7fd75539b,
0xaae103b5fcd2a882,
0xd59944a37c0752a2,
0x857fcae62d8493a5,
0xa6dfbd9fb8e5b88f,
0xd097ad07a71f26b2,
0x825ecc24c8737830,
0xa2f67f2dfa90563b,
0xcbb41ef979346bca,
0xfea126b7d78186bd,
0x9f24b832e6b0f436,
0xc6ede63fa05d3144,
0xf8a95fcf88747d94,
0x9b69dbe1b548ce7d,
0xc24452da229b021c,
0xf2d56790ab41c2a3,
0x97c560ba6b0919a6,
0xbdb6b8e905cb600f,
0xed246723473e3813,
0x9436c0760c86e30c,
0xb94470938fa89bcf,
0xe7958cb87392c2c3,
0x90bd77f3483bb9ba,
0xb4ecd5f01a4aa828,
0xe2280b6c20dd5232,
0x8d590723948a535f,
0xb0af48ec79ace837,
0xdcdb1b2798182245,
0x8a08f0f8bf0f156b,
0xac8b2d36eed2dac6,
0xd7adf884aa879177,
0x86ccbb52ea94baeb,
0xa87fea27a539e9a5,
0xd29fe4b18e88640f,
0x83a3eeeef9153e89,
0xa48ceaaab75a8e2b,
0xcdb02555653131b6,
0x808e17555f3ebf12,
0xa0b19d2ab70e6ed6,
0xc8de047564d20a8c,
0xfb158592be068d2f,
0x9ced737bb6c4183d,
0xc428d05aa4751e4d,
0xf53304714d9265e0,
0x993fe2c6d07b7fac,
0xbf8fdb78849a5f97,
0xef73d256a5c0f77d,
0x95a8637627989aae,
0xbb127c53b17ec159,
0xe9d71b689dde71b0,
0x9226712162ab070e,
0xb6b00d69bb55c8d1,
0xe45c10c42a2b3b06,
0x8eb98a7a9a5b04e3,
0xb267ed1940f1c61c,
0xdf01e85f912e37a3,
0x8b61313bbabce2c6,
0xae397d8aa96c1b78,
0xd9c7dced53c72256,
0x881cea14545c7575,
0xaa242499697392d3,
0xd4ad2dbfc3d07788,
0x84ec3c97da624ab5,
0xa6274bbdd0fadd62,
0xcfb11ead453994ba,
0x81ceb32c4b43fcf5,
0xa2425ff75e14fc32,
0xcad2f7f5359a3b3e,
0xfd87b5f28300ca0e,
0x9e74d1b791e07e48,
0xc612062576589ddb,
0xf79687aed3eec551,
0x9abe14cd44753b53,
0xc16d9a0095928a27,
0xf1c90080baf72cb1,
0x971da05074da7bef,
0xbce5086492111aeb,
0xec1e4a7db69561a5,
0x9392ee8e921d5d07,
0xb877aa3236a4b449,
0xe69594bec44de15b,
0x901d7cf73ab0acd9,
0xb424dc35095cd80f,
0xe12e13424bb40e13,
0x8cbccc096f5088cc,
0xafebff0bcb24aaff,
0xdbe6fecebdedd5bf,
0x89705f4136b4a597,
0xabcc77118461cefd,
0xd6bf94d5e57a42bc,
0x8637bd05af6c69b6,
0xa7c5ac471b478423,
0xd1b71758e219652c,
0x83126e978d4fdf3b,
0xa3d70a3d70a3d70a,
0xcccccccccccccccd,
0x8000000000000000,
0xa000000000000000,
0xc800000000000000,
0xfa00000000000000,
0x9c40000000000000,
0xc350000000000000,
0xf424000000000000,
0x9896800000000000,
0xbebc200000000000,
0xee6b280000000000,
0x9502f90000000000,
0xba43b74000000000,
0xe8d4a51000000000,
0x9184e72a00000000,
0xb5e620f480000000,
0xe35fa931a0000000,
0x8e1bc9bf04000000,
0xb1a2bc2ec5000000,
0xde0b6b3a76400000,
0x8ac7230489e80000,
0xad78ebc5ac620000,
0xd8d726b7177a8000,
0x878678326eac9000,
0xa968163f0a57b400,
0xd3c21bcecceda100,
0x84595161401484a0,
0xa56fa5b99019a5c8,
0xcecb8f27f4200f3a,
0x813f3978f8940984,
0xa18f07d736b90be5,
0xc9f2c9cd04674edf,
0xfc6f7c4045812296,
0x9dc5ada82b70b59e,
0xc5371912364ce305,
0xf684df56c3e01bc7,
0x9a130b963a6c115c,
0xc097ce7bc90715b3,
0xf0bdc21abb48db20,
0x96769950b50d88f4,
0xbc143fa4e250eb31,
0xeb194f8e1ae525fd,
0x92efd1b8d0cf37be,
0xb7abc627050305ae,
0xe596b7b0c643c719,
0x8f7e32ce7bea5c70,
0xb35dbf821ae4f38c,
0xe0352f62a19e306f,
0x8c213d9da502de45,
0xaf298d050e4395d7,
0xdaf3f04651d47b4c,
0x88d8762bf324cd10,
0xab0e93b6efee0054,
0xd5d238a4abe98068,
0x85a36366eb71f041,
0xa70c3c40a64e6c52,
0xd0cf4b50cfe20766,
0x82818f1281ed44a0,
0xa321f2d7226895c8,
0xcbea6f8ceb02bb3a,
0xfee50b7025c36a08,
0x9f4f2726179a2245,
0xc722f0ef9d80aad6,
0xf8ebad2b84e0d58c,
0x9b934c3b330c8577,
0xc2781f49ffcfa6d5,
0xf316271c7fc3908b,
0x97edd871cfda3a57,
0xbde94e8e43d0c8ec,
0xed63a231d4c4fb27,
0x945e455f24fb1cf9,
0xb975d6b6ee39e437,
0xe7d34c64a9c85d44,
0x90e40fbeea1d3a4b,
0xb51d13aea4a488dd,
0xe264589a4dcdab15,
0x8d7eb76070a08aed,
0xb0de65388cc8ada8,
0xdd15fe86affad912,
0x8a2dbf142dfcc7ab,
0xacb92ed9397bf996,
0xd7e77a8f87daf7fc,
0x86f0ac99b4e8dafd,
0xa8acd7c0222311bd,
0xd2d80db02aabd62c,
0x83c7088e1aab65db,
0xa4b8cab1a1563f52,
0xcde6fd5e09abcf27,
0x80b05e5ac60b6178,
0xa0dc75f1778e39d6,
0xc913936dd571c84c,
0xfb5878494ace3a5f,
0x9d174b2dcec0e47b,
0xc45d1df942711d9a,
0xf5746577930d6501,
0x9968bf6abbe85f20,
0xbfc2ef456ae276e9,
0xefb3ab16c59b14a3,
0x95d04aee3b80ece6,
0xbb445da9ca61281f,
0xea1575143cf97227,
0x924d692ca61be758,
0xb6e0c377cfa2e12e,
0xe498f455c38b997a,
0x8edf98b59a373fec,
0xb2977ee300c50fe7,
0xdf3d5e9bc0f653e1,
0x8b865b215899f46d,
0xae67f1e9aec07188,
0xda01ee641a708dea,
0x884134fe908658b2,
0xaa51823e34a7eedf,
0xd4e5e2cdc1d1ea96,
0x850fadc09923329e,
0xa6539930bf6bff46,
0xcfe87f7cef46ff17,
0x81f14fae158c5f6e,
0xa26da3999aef774a,
0xcb090c8001ab551c,
0xfdcb4fa002162a63,
0x9e9f11c4014dda7e,
0xc646d63501a1511e,
0xf7d88bc24209a565,
0x9ae757596946075f,
0xc1a12d2fc3978937,
0xf209787bb47d6b85,
0x9745eb4d50ce6333,
0xbd176620a501fc00,
0xec5d3fa8ce427b00,
0x93ba47c980e98ce0,
0xb8a8d9bbe123f018,
0xe6d3102ad96cec1e,
0x9043ea1ac7e41393,
0xb454e4a179dd1877,
0xe16a1dc9d8545e95,
0x8ce2529e2734bb1d,
0xb01ae745b101e9e4,
0xdc21a1171d42645d,
0x899504ae72497eba,
0xabfa45da0edbde69,
0xd6f8d7509292d603,
0x865b86925b9bc5c2,
0xa7f26836f282b733,
0xd1ef0244af2364ff,
0x8335616aed761f1f,
0xa402b9c5a8d3a6e7,
0xcd036837130890a1,
0x802221226be55a65,
0xa02aa96b06deb0fe,
0xc83553c5c8965d3d,
0xfa42a8b73abbf48d,
0x9c69a97284b578d8,
0xc38413cf25e2d70e,
0xf46518c2ef5b8cd1,
0x98bf2f79d5993803,
0xbeeefb584aff8604,
0xeeaaba2e5dbf6785,
0x952ab45cfa97a0b3,
0xba756174393d88e0,
0xe912b9d1478ceb17,
0x91abb422ccb812ef,
0xb616a12b7fe617aa,
0xe39c49765fdf9d95,
0x8e41ade9fbebc27d,
0xb1d219647ae6b31c,
0xde469fbd99a05fe3,
0x8aec23d680043bee,
0xada72ccc20054aea,
0xd910f7ff28069da4,
0x87aa9aff79042287,
0xa99541bf57452b28,
0xd3fa922f2d1675f2,
0x847c9b5d7c2e09b7,
0xa59bc234db398c25,
0xcf02b2c21207ef2f,
0x8161afb94b44f57d,
0xa1ba1ba79e1632dc,
0xca28a291859bbf93,
0xfcb2cb35e702af78,
0x9defbf01b061adab,
0xc56baec21c7a1916,
0xf6c69a72a3989f5c,
0x9a3c2087a63f6399,
0xc0cb28a98fcf3c80,
0xf0fdf2d3f3c30b9f,
0x969eb7c47859e744,
0xbc4665b596706115,
0xeb57ff22fc0c795a,
0x9316ff75dd87cbd8,
0xb7dcbf5354e9bece,
0xe5d3ef282a242e82,
0x8fa475791a569d11,
0xb38d92d760ec4455,
0xe070f78d3927556b,
0x8c469ab843b89563,
0xaf58416654a6babb,
0xdb2e51bfe9d0696a,
0x88fcf317f22241e2,
0xab3c2fddeeaad25b,
0xd60b3bd56a5586f2,
0x85c7056562757457,
0xa738c6bebb12d16d,
0xd106f86e69d785c8,
0x82a45b450226b39d,
0xa34d721642b06084,
0xcc20ce9bd35c78a5,
0xff290242c83396ce,
0x9f79a169bd203e41,
0xc75809c42c684dd1,
0xf92e0c3537826146,
0x9bbcc7a142b17ccc,
0xc2abf989935ddbfe,
0xf356f7ebf83552fe,
0x98165af37b2153df,
0xbe1bf1b059e9a8d6,
0xeda2ee1c7064130c,
0x9485d4d1c63e8be8,
0xb9a74a0637ce2ee1,
0xe8111c87c5c1ba9a,
0x910ab1d4db9914a0,
0xb54d5e4a127f59c8,
0xe2a0b5dc971f303a,
0x8da471a9de737e24,
0xb10d8e1456105dad,
0xdd50f1996b947519,
0x8a5296ffe33cc930,
0xace73cbfdc0bfb7b,
0xd8210befd30efa5a,
0x8714a775e3e95c78,
0xa8d9d1535ce3b396,
0xd31045a8341ca07c,
0x83ea2b892091e44e,
0xa4e4b66b68b65d61,
0xce1de40642e3f4b9,
0x80d2ae83e9ce78f4,
0xa1075a24e4421731,
0xc94930ae1d529cfd,
0xfb9b7cd9a4a7443c,
0x9d412e0806e88aa6,
0xc491798a08a2ad4f,
0xf5b5d7ec8acb58a3,
0x9991a6f3d6bf1766,
0xbff610b0cc6edd3f,
0xeff394dcff8a948f,
0x95f83d0a1fb69cd9,
0xbb764c4ca7a44410,
0xea53df5fd18d5514,
0x92746b9be2f8552c,
0xb7118682dbb66a77,
0xe4d5e82392a40515,
0x8f05b1163ba6832d,
0xb2c71d5bca9023f8,
0xdf78e4b2bd342cf7,
0x8bab8eefb6409c1a,
0xae9672aba3d0c321,
0xda3c0f568cc4f3e9,
0x8865899617fb1871,
0xaa7eebfb9df9de8e,
0xd51ea6fa85785631,
0x8533285c936b35df,
0xa67ff273b8460357,
0xd01fef10a657842c,
0x8213f56a67f6b29c,
0xa298f2c501f45f43,
0xcb3f2f7642717713,
0xfe0efb53d30dd4d8,
0x9ec95d1463e8a507,
0xc67bb4597ce2ce49,
0xf81aa16fdc1b81db,
0x9b10a4e5e9913129,
0xc1d4ce1f63f57d73,
0xf24a01a73cf2dcd0,
0x976e41088617ca02,
0xbd49d14aa79dbc82,
0xec9c459d51852ba3,
0x93e1ab8252f33b46,
0xb8da1662e7b00a17,
0xe7109bfba19c0c9d,
0x906a617d450187e2,
0xb484f9dc9641e9db,
0xe1a63853bbd26451,
0x8d07e33455637eb3,
0xb049dc016abc5e60,
0xdc5c5301c56b75f7,
0x89b9b3e11b6329bb,
0xac2820d9623bf429,
0xd732290fbacaf134,
0x867f59a9d4bed6c0,
0xa81f301449ee8c70,
0xd226fc195c6a2f8c,
0x83585d8fd9c25db8,
0xa42e74f3d032f526,
0xcd3a1230c43fb26f,
0x80444b5e7aa7cf85,
0xa0555e361951c367,
0xc86ab5c39fa63441,
0xfa856334878fc151,
0x9c935e00d4b9d8d2,
0xc3b8358109e84f07,
0xf4a642e14c6262c9,
0x98e7e9cccfbd7dbe,
0xbf21e44003acdd2d,
0xeeea5d5004981478,
0x95527a5202df0ccb,
0xbaa718e68396cffe,
0xe950df20247c83fd,
0x91d28b7416cdd27e,
], [
-1077,
-1073,
-1070,
-1067,
-1063,
-1060,
-1057,
-1053,
-1050,
-1047,
-1043,
-1040,
-1037,
-1034,
-1030,
-1027,
-1024,
-1020,
-1017,
-1014,
-1010,
-1007,
-1004,
-1000,
-997,
-994,
-990,
-987,
-984,
-980,
-977,
-974,
-970,
-967,
-964,
-960,
-957,
-954,
-950,
-947,
-944,
-940,
-937,
-934,
-931,
-927,
-924,
-921,
-917,
-914,
-911,
-907,
-904,
-901,
-897,
-894,
-891,
-887,
-884,
-881,
-877,
-874,
-871,
-867,
-864,
-861,
-857,
-854,
-851,
-847,
-844,
-841,
-838,
-834,
-831,
-828,
-824,
-821,
-818,
-814,
-811,
-808,
-804,
-801,
-798,
-794,
-791,
-788,
-784,
-781,
-778,
-774,
-771,
-768,
-764,
-761,
-758,
-754,
-751,
-748,
-744,
-741,
-738,
-735,
-731,
-728,
-725,
-721,
-718,
-715,
-711,
-708,
-705,
-701,
-698,
-695,
-691,
-688,
-685,
-681,
-678,
-675,
-671,
-668,
-665,
-661,
-658,
-655,
-651,
-648,
-645,
-642,
-638,
-635,
-632,
-628,
-625,
-622,
-618,
-615,
-612,
-608,
-605,
-602,
-598,
-595,
-592,
-588,
-585,
-582,
-578,
-575,
-572,
-568,
-565,
-562,
-558,
-555,
-552,
-549,
-545,
-542,
-539,
-535,
-532,
-529,
-525,
-522,
-519,
-515,
-512,
-509,
-505,
-502,
-499,
-495,
-492,
-489,
-485,
-482,
-479,
-475,
-472,
-469,
-465,
-462,
-459,
-455,
-452,
-449,
-446,
-442,
-439,
-436,
-432,
-429,
-426,
-422,
-419,
-416,
-412,
-409,
-406,
-402,
-399,
-396,
-392,
-389,
-386,
-382,
-379,
-376,
-372,
-369,
-366,
-362,
-359,
-356,
-353,
-349,
-346,
-343,
-339,
-336,
-333,
-329,
-326,
-323,
-319,
-316,
-313,
-309,
-306,
-303,
-299,
-296,
-293,
-289,
-286,
-283,
-279,
-276,
-273,
-269,
-266,
-263,
-259,
-256,
-253,
-250,
-246,
-243,
-240,
-236,
-233,
-230,
-226,
-223,
-220,
-216,
-213,
-210,
-206,
-203,
-200,
-196,
-193,
-190,
-186,
-183,
-180,
-176,
-173,
-170,
-166,
-163,
-160,
-157,
-153,
-150,
-147,
-143,
-140,
-137,
-133,
-130,
-127,
-123,
-120,
-117,
-113,
-110,
-107,
-103,
-100,
-97,
-93,
-90,
-87,
-83,
-80,
-77,
-73,
-70,
-67,
-63,
-60,
-57,
-54,
-50,
-47,
-44,
-40,
-37,
-34,
-30,
-27,
-24,
-20,
-17,
-14,
-10,
-7,
-4,
0,
3,
6,
10,
13,
16,
20,
23,
26,
30,
33,
36,
39,
43,
46,
49,
53,
56,
59,
63,
66,
69,
73,
76,
79,
83,
86,
89,
93,
96,
99,
103,
106,
109,
113,
116,
119,
123,
126,
129,
132,
136,
139,
142,
146,
149,
152,
156,
159,
162,
166,
169,
172,
176,
179,
182,
186,
189,
192,
196,
199,
202,
206,
209,
212,
216,
219,
222,
226,
229,
232,
235,
239,
242,
245,
249,
252,
255,
259,
262,
265,
269,
272,
275,
279,
282,
285,
289,
292,
295,
299,
302,
305,
309,
312,
315,
319,
322,
325,
328,
332,
335,
338,
342,
345,
348,
352,
355,
358,
362,
365,
368,
372,
375,
378,
382,
385,
388,
392,
395,
398,
402,
405,
408,
412,
415,
418,
422,
425,
428,
431,
435,
438,
441,
445,
448,
451,
455,
458,
461,
465,
468,
471,
475,
478,
481,
485,
488,
491,
495,
498,
501,
505,
508,
511,
515,
518,
521,
524,
528,
531,
534,
538,
541,
544,
548,
551,
554,
558,
561,
564,
568,
571,
574,
578,
581,
584,
588,
591,
594,
598,
601,
604,
608,
611,
614,
617,
621,
624,
627,
631,
634,
637,
641,
644,
647,
651,
654,
657,
661,
664,
667,
671,
674,
677,
681,
684,
687,
691,
694,
697,
701,
704,
707,
711,
714,
717,
720,
724,
727,
730,
734,
737,
740,
744,
747,
750,
754,
757,
760,
764,
767,
770,
774,
777,
780,
784,
787,
790,
794,
797,
800,
804,
807,
810,
813,
817,
820,
823,
827,
830,
833,
837,
840,
843,
847,
850,
853,
857,
860,
863,
867,
870,
873,
877,
880,
883,
887,
890,
893,
897,
900,
903,
907,
910,
913,
916,
920,
923,
926,
930,
933,
936,
940,
943,
946,
950,
]);
+10 -11
View File
@@ -171,20 +171,19 @@ pub fn is_zero(&self) -> bool {
pub fn bit_length(&self) -> usize {
use mem;
let digitbits = mem::size_of::<$ty>()* 8;
// Skip over the most significant digits which are zero.
let nonzero = match self.digits().iter().rposition(|&x| x != 0) {
Some(n) => {
let end = self.size - n;
&self.digits()[..end]
}
None => {
// There are no non-zero digits, i.e. the number is zero.
return 0;
}
};
let digits = self.digits();
let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
let end = digits.len() - zeros;
let nonzero = &digits[..end];
if nonzero.is_empty() {
// There are no non-zero digits, i.e. the number is zero.
return 0;
}
// This could be optimized with leading_zeros() and bit shifts, but that's
// probably not worth the hassle.
let digitbits = mem::size_of::<$ty>()* 8;
let mut i = nonzero.len() * digitbits - 1;
while self.get_bit(i) == 0 {
i -= 1;
+5 -4
View File
@@ -44,6 +44,7 @@
pub mod wrapping;
pub mod flt2dec;
pub mod dec2flt;
/// Types that have a "zero" value.
///
@@ -1364,7 +1365,7 @@ pub trait Float {
}
macro_rules! from_str_float_impl {
($t:ty) => {
($t:ty, $func:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for $t {
type Err = ParseFloatError;
@@ -1397,13 +1398,13 @@ impl FromStr for $t {
#[inline]
#[allow(deprecated)]
fn from_str(src: &str) -> Result<Self, ParseFloatError> {
Self::from_str_radix(src, 10)
dec2flt::$func(src)
}
}
}
}
from_str_float_impl!(f32);
from_str_float_impl!(f64);
from_str_float_impl!(f32, to_f32);
from_str_float_impl!(f64, to_f64);
macro_rules! from_str_radix_int_impl {
($($t:ty)*) => {$(
+1
View File
@@ -19,6 +19,7 @@
#![feature(float_extras)]
#![feature(float_from_str_radix)]
#![feature(flt2dec)]
#![feature(dec2flt)]
#![feature(fmt_radix)]
#![feature(hash_default)]
#![feature(hasher_write)]
+174
View File
@@ -0,0 +1,174 @@
// 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.
#![allow(overflowing_literals)]
use std::{i64, f32, f64};
use test;
use core::num::dec2flt::{to_f32, to_f64};
mod parse;
mod rawfp;
// Take an float literal, turn it into a string in various ways (that are all trusted
// to be correct) and see if those strings are parsed back to the value of the literal.
// Requires a *polymorphic literal*, i.e. one that can serve as f64 as well as f32.
macro_rules! test_literal {
($x: expr) => ({
let x32: f32 = $x;
let x64: f64 = $x;
let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)];
for input in inputs {
if input != "inf" {
assert_eq!(to_f64(input), Ok(x64));
assert_eq!(to_f32(input), Ok(x32));
let neg_input = &format!("-{}", input);
assert_eq!(to_f64(neg_input), Ok(-x64));
assert_eq!(to_f32(neg_input), Ok(-x32));
}
}
})
}
#[test]
fn ordinary() {
test_literal!(1.0);
test_literal!(3e-5);
test_literal!(0.1);
test_literal!(12345.);
test_literal!(0.9999999);
test_literal!(2.2250738585072014e-308);
}
#[test]
fn special_code_paths() {
test_literal!(36893488147419103229.0); // 2^65 - 3, triggers half-to-even with even significand
test_literal!(101e-33); // Triggers the tricky underflow case in AlgorithmM (for f32)
test_literal!(1e23); // Triggers AlgorithmR
test_literal!(2075e23); // Triggers another path through AlgorithmR
test_literal!(8713e-23); // ... and yet another.
}
#[test]
fn large() {
test_literal!(1e300);
test_literal!(123456789.34567e250);
test_literal!(943794359898089732078308743689303290943794359843568973207830874368930329.);
}
#[test]
fn subnormals() {
test_literal!(5e-324);
test_literal!(91e-324);
test_literal!(1e-322);
test_literal!(13245643e-320);
test_literal!(2.22507385851e-308);
test_literal!(2.1e-308);
test_literal!(4.9406564584124654e-324);
}
#[test]
fn infinity() {
test_literal!(1e400);
test_literal!(1e309);
test_literal!(2e308);
test_literal!(1.7976931348624e308);
}
#[test]
fn zero() {
test_literal!(0.0);
test_literal!(1e-325);
test_literal!(1e-326);
test_literal!(1e-500);
}
#[test]
fn lonely_dot() {
assert_eq!(to_f64("."), Ok(0.0));
}
#[test]
fn nan() {
assert!(to_f64("NaN").unwrap().is_nan());
assert!(to_f32("NaN").unwrap().is_nan());
}
#[test]
fn inf() {
assert_eq!(to_f64("inf"), Ok(f64::INFINITY));
assert_eq!(to_f64("-inf"), Ok(f64::NEG_INFINITY));
assert_eq!(to_f32("inf"), Ok(f32::INFINITY));
assert_eq!(to_f32("-inf"), Ok(f32::NEG_INFINITY));
}
#[test]
fn massive_exponent() {
let max = i64::MAX;
assert_eq!(to_f64(&format!("1e{}000", max)), Ok(f64::INFINITY));
assert_eq!(to_f64(&format!("1e-{}000", max)), Ok(0.0));
assert_eq!(to_f64(&format!("1e{}000", max)), Ok(f64::INFINITY));
}
#[bench]
fn bench_0(b: &mut test::Bencher) {
b.iter(|| to_f64("0.0"));
}
#[bench]
fn bench_42(b: &mut test::Bencher) {
b.iter(|| to_f64("42"));
}
#[bench]
fn bench_huge_int(b: &mut test::Bencher) {
// 2^128 - 1
b.iter(|| to_f64("170141183460469231731687303715884105727"));
}
#[bench]
fn bench_short_decimal(b: &mut test::Bencher) {
b.iter(|| to_f64("1234.5678"));
}
#[bench]
fn bench_pi_long(b: &mut test::Bencher) {
b.iter(|| to_f64("3.14159265358979323846264338327950288"));
}
#[bench]
fn bench_pi_short(b: &mut test::Bencher) {
b.iter(|| to_f64("3.141592653589793"))
}
#[bench]
fn bench_1e150(b: &mut test::Bencher) {
b.iter(|| to_f64("1e150"));
}
#[bench]
fn bench_long_decimal_and_exp(b: &mut test::Bencher) {
b.iter(|| to_f64("727501488517303786137132964064381141071e-123"));
}
#[bench]
fn bench_min_subnormal(b: &mut test::Bencher) {
b.iter(|| to_f64("5e-324"));
}
#[bench]
fn bench_min_normal(b: &mut test::Bencher) {
b.iter(|| to_f64("2.2250738585072014e-308"));
}
#[bench]
fn bench_max(b: &mut test::Bencher) {
b.iter(|| to_f64("1.7976931348623157e308"));
}
+52
View File
@@ -0,0 +1,52 @@
// 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.
use std::iter;
use core::num::dec2flt::parse::{Decimal, parse_decimal};
use core::num::dec2flt::parse::ParseResult::{Valid, Invalid};
#[test]
fn missing_pieces() {
let permutations = &[".e", "1e", "e4", "e", ".12e", "321.e", "32.12e+", "12.32e-"];
for &s in permutations {
assert_eq!(parse_decimal(s), Invalid);
}
}
#[test]
fn invalid_chars() {
let invalid = "r,?<j";
let valid_strings = &["123", "666.", ".1", "5e1", "7e-3", "0.0e+1"];
for c in invalid.chars() {
for s in valid_strings {
for i in 0..s.len() {
let mut input = String::new();
input.push_str(s);
input.insert(i, c);
assert!(parse_decimal(&input) == Invalid, "did not reject invalid {:?}", input);
}
}
}
}
#[test]
fn valid() {
assert_eq!(parse_decimal("123.456e789"), Valid(Decimal::new(b"123", b"456", 789)));
assert_eq!(parse_decimal("123.456e+789"), Valid(Decimal::new(b"123", b"456", 789)));
assert_eq!(parse_decimal("123.456e-789"), Valid(Decimal::new(b"123", b"456", -789)));
assert_eq!(parse_decimal(".050"), Valid(Decimal::new(b"", b"050", 0)));
assert_eq!(parse_decimal("999"), Valid(Decimal::new(b"999", b"", 0)));
assert_eq!(parse_decimal("1.e300"), Valid(Decimal::new(b"1", b"", 300)));
assert_eq!(parse_decimal(".1e300"), Valid(Decimal::new(b"", b"1", 300)));
assert_eq!(parse_decimal("101e-33"), Valid(Decimal::new(b"101", b"", -33)));
let zeros: String = iter::repeat('0').take(25).collect();
let s = format!("1.5e{}", zeros);
assert_eq!(parse_decimal(&s), Valid(Decimal::new(b"1", b"5", 0)));
}
+139
View File
@@ -0,0 +1,139 @@
// 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.
use std::f64;
use core::num::flt2dec::strategy::grisu::Fp;
use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal};
#[test]
fn fp_to_float_half_to_even() {
fn is_normalized(sig: u64) -> bool {
// intentionally written without {min,max}_sig() as a sanity check
sig >> 52 == 1 && sig >> 53 == 0
}
fn conv(sig: u64) -> u64 {
// The significands are perfectly in range, so the exponent should not matter
let (m1, e1, _) = fp_to_float::<f64>(Fp { f: sig, e: 0 }).integer_decode();
assert_eq!(e1, 0 + 64 - 53);
let (m2, e2, _) = fp_to_float::<f64>(Fp { f: sig, e: 55 }).integer_decode();
assert_eq!(e2, 55 + 64 - 53);
assert_eq!(m2, m1);
let (m3, e3, _) = fp_to_float::<f64>(Fp { f: sig, e: -78 }).integer_decode();
assert_eq!(e3, -78 + 64 - 53);
assert_eq!(m3, m2);
m3
}
let odd = 0x1F_EDCB_A012_345F;
let even = odd - 1;
assert!(is_normalized(odd));
assert!(is_normalized(even));
assert_eq!(conv(odd << 11), odd);
assert_eq!(conv(even << 11), even);
assert_eq!(conv(odd << 11 | 1 << 10), odd + 1);
assert_eq!(conv(even << 11 | 1 << 10), even);
assert_eq!(conv(even << 11 | 1 << 10 | 1), even + 1);
assert_eq!(conv(odd << 11 | 1 << 9), odd);
assert_eq!(conv(even << 11 | 1 << 9), even);
assert_eq!(conv(odd << 11 | 0x7FF), odd + 1);
assert_eq!(conv(even << 11 | 0x7FF), even + 1);
assert_eq!(conv(odd << 11 | 0x3FF), odd);
assert_eq!(conv(even << 11 | 0x3FF), even);
}
#[test]
fn integers_to_f64() {
assert_eq!(fp_to_float::<f64>(Fp { f: 1, e: 0 }), 1.0);
assert_eq!(fp_to_float::<f64>(Fp { f: 42, e: 7 }), (42 << 7) as f64);
assert_eq!(fp_to_float::<f64>(Fp { f: 1 << 20, e: 30 }), (1u64 << 50) as f64);
assert_eq!(fp_to_float::<f64>(Fp { f: 4, e: -3 }), 0.5);
}
const SOME_FLOATS: [f64; 9] =
[0.1f64, 33.568, 42.1e-5, 777.0e9, 1.1111, 0.347997,
9843579834.35892, 12456.0e-150, 54389573.0e-150];
#[test]
fn human_f64_roundtrip() {
for &x in &SOME_FLOATS {
let (f, e, _) = x.integer_decode();
let fp = Fp { f: f, e: e};
assert_eq!(fp_to_float::<f64>(fp), x);
}
}
#[test]
fn rounding_overflow() {
let x = Fp { f: 0xFF_FF_FF_FF_FF_FF_FF_00u64, e: 42 };
let rounded = round_normal::<f64>(x);
let adjusted_k = x.e + 64 - 53;
assert_eq!(rounded.sig, 1 << 52);
assert_eq!(rounded.k, adjusted_k + 1);
}
#[test]
fn prev_float_monotonic() {
let mut x = 1.0;
for _ in 0..100 {
let x1 = prev_float(x);
assert!(x1 < x);
assert!(x - x1 < 1e-15);
x = x1;
}
}
const MIN_SUBNORMAL: f64 = 5e-324;
#[test]
fn next_float_zero() {
let tiny = next_float(0.0);
assert_eq!(tiny, MIN_SUBNORMAL);
assert!(tiny != 0.0);
}
#[test]
fn next_float_subnormal() {
let second = next_float(MIN_SUBNORMAL);
// For subnormals, MIN_SUBNORMAL is the ULP
assert!(second != MIN_SUBNORMAL);
assert!(second > 0.0);
assert_eq!(second - MIN_SUBNORMAL, MIN_SUBNORMAL);
}
#[test]
fn next_float_inf() {
assert_eq!(next_float(f64::MAX), f64::INFINITY);
assert_eq!(next_float(f64::INFINITY), f64::INFINITY);
}
#[test]
fn next_prev_identity() {
for &x in &SOME_FLOATS {
assert_eq!(prev_float(next_float(x)), x);
assert_eq!(prev_float(prev_float(next_float(next_float(x)))), x);
assert_eq!(next_float(prev_float(x)), x);
assert_eq!(next_float(next_float(prev_float(prev_float(x)))), x);
}
}
#[test]
fn next_float_monotonic() {
let mut x = 0.49999999999999;
assert!(x < 0.5);
for _ in 0..200 {
let x1 = next_float(x);
assert!(x1 > x);
assert!(x1 - x < 1e-15, "next_float_monotonic: delta = {:?}", x1 - x);
x = x1;
}
assert!(x > 0.5);
}
+1
View File
@@ -30,6 +30,7 @@
mod u64;
mod flt2dec;
mod dec2flt;
/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T) where