core: added core::num::flt2dec for floating-point formatting.

This is a fork of the flt2dec portion of rust-strconv [1] with
a necessary relicensing (the original code was licensed CC0-1.0).
Each module is accompanied with large unit tests, integrated
in this commit as coretest::num::flt2dec. This module is added
in order to replace the existing core::fmt::float method.

The forked revision of rust-strconv is from 2015-04-20, with a commit ID
9adf6d3571c6764a6f240a740c823024f70dc1c7.

[1] https://github.com/lifthrasiir/rust-strconv/
This commit is contained in:
Kang Seonghoon 2015-04-19 14:19:54 +09:00
parent 7bd71637ca
commit c82da7a54b
14 changed files with 3895 additions and 0 deletions

View File

@ -0,0 +1,355 @@
// 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.
//! Custom arbitrary-precision number (bignum) implementation.
//!
//! This is designed to avoid the heap allocation at expense of stack memory.
//! The most used bignum type, `Big32x36`, is limited by 32 × 36 = 1,152 bits
//! and will take at most 152 bytes of stack memory. This is (barely) enough
//! for handling all possible finite `f64` values.
//!
//! In principle it is possible to have multiple bignum types for different
//! inputs, but we don't do so to avoid the code bloat. Each bignum is still
//! tracked for the actual usages, so it normally doesn't matter.
#![macro_use]
use prelude::*;
use mem;
use intrinsics;
/// Arithmetic operations required by bignums.
pub trait FullOps {
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
/// where `W` is the number of bits in `Self`.
fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
/// where `W` is the number of bits in `Self`.
fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self);
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
/// where `W` is the number of bits in `Self`.
fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self);
/// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem`
/// and `0 <= rem < other`, where `W` is the number of bits in `Self`.
fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/);
}
macro_rules! impl_full_ops {
($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
$(
impl FullOps for $ty {
fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) {
// this cannot overflow, the output is between 0 and 2*2^nbits - 1
// FIXME will LLVM optimize this into ADC or similar???
let (v, carry1) = unsafe { $addfn(self, other) };
let (v, carry2) = unsafe { $addfn(v, if carry {1} else {0}) };
(carry1 || carry2, v)
}
fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) {
// this cannot overflow, the output is between 0 and 2^nbits * (2^nbits - 1)
let nbits = mem::size_of::<$ty>() * 8;
let v = (self as $bigty) * (other as $bigty) + (carry as $bigty);
((v >> nbits) as $ty, v as $ty)
}
fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
// this cannot overflow, the output is between 0 and 2^(2*nbits) - 1
let nbits = mem::size_of::<$ty>() * 8;
let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) +
(carry as $bigty);
((v >> nbits) as $ty, v as $ty)
}
fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) {
debug_assert!(borrow < other);
// this cannot overflow, the dividend is between 0 and other * 2^nbits - 1
let nbits = mem::size_of::<$ty>() * 8;
let lhs = ((borrow as $bigty) << nbits) | (self as $bigty);
let rhs = other as $bigty;
((lhs / rhs) as $ty, (lhs % rhs) as $ty)
}
}
)*
)
}
impl_full_ops! {
u8: add(intrinsics::u8_add_with_overflow), mul/div(u16);
u16: add(intrinsics::u16_add_with_overflow), mul/div(u32);
u32: add(intrinsics::u32_add_with_overflow), mul/div(u64);
// u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); // damn!
}
macro_rules! define_bignum {
($name:ident: type=$ty:ty, n=$n:expr) => (
/// Stack-allocated arbitrary-precision (up to certain limit) integer.
///
/// This is backed by an fixed-size array of given type ("digit").
/// While the array is not very large (normally some hundred bytes),
/// copying it recklessly may result in the performance hit.
/// Thus this is intentionally not `Copy`.
///
/// All operations available to bignums panic in the case of over/underflows.
/// The caller is responsible to use large enough bignum types.
pub struct $name {
/// One plus the offset to the maximum "digit" in the use.
/// This does not decrease, so be aware of the computation order.
/// `base[size..]` should be zero.
size: usize,
/// Digits. `[a, b, c, ...]` represents `a + b*n + c*n^2 + ...`.
base: [$ty; $n]
}
impl $name {
/// Makes a bignum from one digit.
pub fn from_small(v: $ty) -> $name {
let mut base = [0; $n];
base[0] = v;
$name { size: 1, base: base }
}
/// Makes a bignum from `u64` value.
pub fn from_u64(mut v: u64) -> $name {
use mem;
let mut base = [0; $n];
let mut sz = 0;
while v > 0 {
base[sz] = v as $ty;
v >>= mem::size_of::<$ty>() * 8;
sz += 1;
}
$name { size: sz, base: base }
}
/// Returns true if the bignum is zero.
pub fn is_zero(&self) -> bool {
self.base[..self.size].iter().all(|&v| v == 0)
}
/// Adds `other` to itself and returns its own mutable reference.
pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
use cmp;
use num::flt2dec::bignum::FullOps;
let mut sz = cmp::max(self.size, other.size);
let mut carry = false;
for (a, b) in self.base[..sz].iter_mut().zip(other.base[..sz].iter()) {
let (c, v) = (*a).full_add(*b, carry);
*a = v;
carry = c;
}
if carry {
self.base[sz] = 1;
sz += 1;
}
self.size = sz;
self
}
/// Subtracts `other` from itself and returns its own mutable reference.
pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
use cmp;
use num::flt2dec::bignum::FullOps;
let sz = cmp::max(self.size, other.size);
let mut noborrow = true;
for (a, b) in self.base[..sz].iter_mut().zip(other.base[..sz].iter()) {
let (c, v) = (*a).full_add(!*b, noborrow);
*a = v;
noborrow = c;
}
assert!(noborrow);
self.size = sz;
self
}
/// Multiplies itself by a digit-sized `other` and returns its own
/// mutable reference.
pub fn mul_small<'a>(&'a mut self, other: $ty) -> &'a mut $name {
use num::flt2dec::bignum::FullOps;
let mut sz = self.size;
let mut carry = 0;
for a in self.base[..sz].iter_mut() {
let (c, v) = (*a).full_mul(other, carry);
*a = v;
carry = c;
}
if carry > 0 {
self.base[sz] = carry;
sz += 1;
}
self.size = sz;
self
}
/// Multiplies itself by `2^bits` and returns its own mutable reference.
pub fn mul_pow2<'a>(&'a mut self, bits: usize) -> &'a mut $name {
use mem;
let digitbits = mem::size_of::<$ty>() * 8;
let digits = bits / digitbits;
let bits = bits % digitbits;
assert!(digits < $n);
debug_assert!(self.base[$n-digits..].iter().all(|&v| v == 0));
debug_assert!(bits == 0 || (self.base[$n-digits-1] >> (digitbits - bits)) == 0);
// shift by `digits * digitbits` bits
for i in (0..self.size).rev() {
self.base[i+digits] = self.base[i];
}
for i in 0..digits {
self.base[i] = 0;
}
// shift by `nbits` bits
let mut sz = self.size + digits;
if bits > 0 {
let last = sz;
let overflow = self.base[last-1] >> (digitbits - bits);
if overflow > 0 {
self.base[last] = overflow;
sz += 1;
}
for i in (digits+1..last).rev() {
self.base[i] = (self.base[i] << bits) |
(self.base[i-1] >> (digitbits - bits));
}
self.base[digits] <<= bits;
// self.base[..digits] is zero, no need to shift
}
self.size = sz;
self
}
/// Multiplies itself by a number described by `other[0] + other[1] * n +
/// other[2] * n^2 + ...` and returns its own mutable reference.
pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name {
// the internal routine. works best when aa.len() <= bb.len().
fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize {
use num::flt2dec::bignum::FullOps;
let mut retsz = 0;
for (i, &a) in aa.iter().enumerate() {
if a == 0 { continue; }
let mut sz = bb.len();
let mut carry = 0;
for (j, &b) in bb.iter().enumerate() {
let (c, v) = a.full_mul_add(b, ret[i + j], carry);
ret[i + j] = v;
carry = c;
}
if carry > 0 {
ret[i + sz] = carry;
sz += 1;
}
if retsz < i + sz {
retsz = i + sz;
}
}
retsz
}
let mut ret = [0; $n];
let retsz = if self.size < other.len() {
mul_inner(&mut ret, &self.base[..self.size], other)
} else {
mul_inner(&mut ret, other, &self.base[..self.size])
};
self.base = ret;
self.size = retsz;
self
}
/// Divides itself by a digit-sized `other` and returns its own
/// mutable reference *and* the remainder.
pub fn div_rem_small<'a>(&'a mut self, other: $ty) -> (&'a mut $name, $ty) {
use num::flt2dec::bignum::FullOps;
assert!(other > 0);
let sz = self.size;
let mut borrow = 0;
for a in self.base[..sz].iter_mut().rev() {
let (q, r) = (*a).full_div_rem(other, borrow);
*a = q;
borrow = r;
}
(self, borrow)
}
}
impl ::cmp::PartialEq for $name {
fn eq(&self, other: &$name) -> bool { self.base[..] == other.base[..] }
}
impl ::cmp::Eq for $name {
}
impl ::cmp::PartialOrd for $name {
fn partial_cmp(&self, other: &$name) -> ::option::Option<::cmp::Ordering> {
::option::Option::Some(self.cmp(other))
}
}
impl ::cmp::Ord for $name {
fn cmp(&self, other: &$name) -> ::cmp::Ordering {
use cmp::max;
use iter::order;
let sz = max(self.size, other.size);
let lhs = self.base[..sz].iter().cloned().rev();
let rhs = other.base[..sz].iter().cloned().rev();
order::cmp(lhs, rhs)
}
}
impl ::clone::Clone for $name {
fn clone(&self) -> $name {
$name { size: self.size, base: self.base }
}
}
impl ::fmt::Debug for $name {
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
use mem;
let sz = if self.size < 1 {1} else {self.size};
let digitlen = mem::size_of::<$ty>() * 2;
try!(write!(f, "{:#x}", self.base[sz-1]));
for &v in self.base[..sz-1].iter().rev() {
try!(write!(f, "_{:01$x}", v, digitlen));
}
::result::Result::Ok(())
}
}
)
}
/// The digit type for `Big32x36`.
pub type Digit32 = u32;
define_bignum!(Big32x36: type=Digit32, n=36);
// this one is used for testing only.
#[doc(hidden)]
pub mod tests {
use prelude::*;
define_bignum!(Big8x3: type=u8, n=3);
}

View File

@ -0,0 +1,100 @@
// 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.
//! Decodes a floating-point value into individual parts and error ranges.
use prelude::*;
use {f32, f64};
use num::{Float, FpCategory};
/// Decoded unsigned finite value, such that:
///
/// - The original value equals to `mant * 2^exp`.
///
/// - Any number from `(mant - minus) * 2^exp` to `(mant + plus) * 2^exp` will
/// round to the original value. The range is inclusive only when
/// `inclusive` is true.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Decoded {
/// The scaled mantissa.
pub mant: u64,
/// The lower error range.
pub minus: u64,
/// The upper error range.
pub plus: u64,
/// The shared exponent in base 2.
pub exp: i16,
/// True when the error range is inclusive.
///
/// In IEEE 754, this is true when the original mantissa was even.
pub inclusive: bool,
}
/// Decoded unsigned value.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum FullDecoded {
/// Not-a-number.
Nan,
/// Infinities, either positive or negative.
Infinite,
/// Zero, either positive or negative.
Zero,
/// Finite numbers with further decoded fields.
Finite(Decoded),
}
/// A floating point type which can be `decode`d.
pub trait DecodableFloat: Float + Copy {
/// The minimum positive normalized value.
fn min_pos_norm_value() -> Self;
}
impl DecodableFloat for f32 {
fn min_pos_norm_value() -> Self { f32::MIN_POSITIVE }
}
impl DecodableFloat for f64 {
fn min_pos_norm_value() -> Self { f64::MIN_POSITIVE }
}
/// Returns a sign (true when negative) and `FullDecoded` value
/// from given floating point number.
pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) {
let (mant, exp, sign) = v.integer_decode();
let even = (mant & 1) == 0;
let decoded = match v.classify() {
FpCategory::Nan => FullDecoded::Nan,
FpCategory::Infinite => FullDecoded::Infinite,
FpCategory::Zero => FullDecoded::Zero,
FpCategory::Subnormal => {
// (mant - 2, exp) -- (mant, exp) -- (mant + 2, exp)
// Float::integer_decode always preserves the exponent,
// so the mantissa is scaled for subnormals.
FullDecoded::Finite(Decoded { mant: mant, minus: 1, plus: 1,
exp: exp, inclusive: even })
}
FpCategory::Normal => {
let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode();
if mant == minnorm.0 && exp == minnorm.1 {
// (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp)
// where maxmant = minnormmant * 2 - 1
FullDecoded::Finite(Decoded { mant: mant << 1, minus: 1, plus: 2,
exp: exp - 1, inclusive: even })
} else {
// (mant - 1, exp) -- (mant, exp) -- (mant + 1, exp)
FullDecoded::Finite(Decoded { mant: mant << 1, minus: 1, plus: 1,
exp: exp - 1, inclusive: even })
}
}
};
(sign < 0, decoded)
}

View File

@ -0,0 +1,23 @@
// 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 exponent estimator.
/// Finds `k_0` such that `10^(k_0-1) < mant * 2^exp <= 10^(k_0+1)`.
///
/// This is used to approximate `k = ceil(log_10 (mant * 2^exp))`;
/// the true `k` is either `k_0` or `k_0+1`.
#[doc(hidden)]
pub fn estimate_scaling_factor(mant: u64, exp: i16) -> i16 {
// 2^(nbits-1) < mant <= 2^nbits if mant > 0
let nbits = 64 - (mant - 1).leading_zeros() as i64;
(((nbits + exp as i64) * 1292913986) >> 32) as i16
}

View File

@ -0,0 +1,662 @@
// 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.
/*!
Floating-point number to decimal conversion routines.
# Problem statement
We are given the floating-point number `v = f * 2^e` with an integer `f`,
and its bounds `minus` and `plus` such that any number between `v - minus` and
`v + plus` will be rounded to `v`. For the simplicity we assume that
this range is exclusive. Then we would like to get the unique decimal
representation `V = 0.d[0..n-1] * 10^k` such that:
- `d[0]` is non-zero.
- It's correctly rounded when parsed back: `v - minus < V < v + plus`.
Furthermore it is shortest such one, i.e. there is no representation
with less than `n` digits that is correctly rounded.
- It's closest to the original value: `abs(V - v) <= 10^(k-n) / 2`. Note that
there might be two representations satisfying this uniqueness requirement,
in which case some tie-breaking mechanism is used.
We will call this mode of operation as to the *shortest* mode. This mode is used
when there is no additional constraint, and can be thought as a "natural" mode
as it matches the ordinary intuition (it at least prints `0.1f32` as "0.1").
We have two more modes of operation closely related to each other. In these modes
we are given either the number of significant digits `n` or the last-digit
limitation `limit` (which determines the actual `n`), and we would like to get
the representation `V = 0.d[0..n-1] * 10^k` such that:
- `d[0]` is non-zero, unless `n` was zero in which case only `k` is returned.
- It's closest to the original value: `abs(V - v) <= 10^(k-n) / 2`. Again,
there might be some tie-breaking mechanism.
When `limit` is given but not `n`, we set `n` such that `k - n = limit`
so that the last digit `d[n-1]` is scaled by `10^(k-n) = 10^limit`.
If such `n` is negative, we clip it to zero so that we will only get `k`.
We are also limited by the supplied buffer. This limitation is used to print
the number up to given number of fractional digits without knowing
the correct `k` beforehand.
We will call the mode of operation requiring `n` as to the *exact* mode,
and one requiring `limit` as to the *fixed* mode. The exact mode is a subset of
the fixed mode: the sufficiently large last-digit limitation will eventually fill
the supplied buffer and let the algorithm to return.
# Implementation overview
It is easy to get the floating point printing correct but slow (Russ Cox has
[demonstrated](http://research.swtch.com/ftoa) how it's easy), or incorrect but
fast (naïve division and modulo). But it is surprisingly hard to print
floating point numbers correctly *and* efficiently.
There are two classes of algorithms widely known to be correct.
- The "Dragon" family of algorithm is first described by Guy L. Steele Jr. and
Jon L. White. They rely on the fixed-size big integer for their correctness.
A slight improvement was found later, which is posthumously described by
Robert G. Burger and R. Kent Dybvig. David Gay's `dtoa.c` routine is
a popular implementation of this strategy.
- The "Grisu" family of algorithm is first described by Florian Loitsch.
They use very cheap integer-only procedure to determine the close-to-correct
representation which is at least guaranteed to be shortest. The variant,
Grisu3, actively detects if the resulting representation is incorrect.
We implement both algorithms with necessary tweaks to suit our requirements.
In particular, published literatures are short of the actual implementation
difficulties like how to avoid arithmetic overflows. Each implementation,
available in `strategy::dragon` and `strategy::grisu` respectively,
extensively describes all necessary justifications and many proofs for them.
(It is still difficult to follow though. You have been warned.)
Both implementations expose two public functions:
- `format_shortest(decoded, buf)`, which always needs at least
`MAX_SIG_DIGITS` digits of buffer. Implements the shortest mode.
- `format_exact(decoded, buf, limit)`, which accepts as small as
one digit of buffer. Implements exact and fixed modes.
They try to fill the `u8` buffer with digits and returns the number of digits
written and the exponent `k`. They are total for all finite `f32` and `f64`
inputs (Grisu internally falls back to Dragon if possible).
The rendered digits are formatted into the actual string form with
four functions:
- `to_shortest_str` prints the shortest representation, which can be padded by
zeroes to make *at least* given number of fractional digits.
- `to_shortest_exp_str` prints the shortest representation, which can be
padded by zeroes when its exponent is in the specified ranges,
or can be printed in the exponential form such as `1.23e45`.
- `to_exact_exp_str` prints the exact representation with given number of
digits in the exponential form.
- `to_exact_fixed_str` prints the fixed representation with *exactly*
given number of fractional digits.
They all return a slice of preallocated `Part` array, which corresponds to
the individual part of strings: a fixed string, a part of rendered digits,
a number of zeroes or a small (`u16`) number. The caller is expected to
provide an enough buffer and `Part` array, and to assemble the final
string from parts itself.
All algorithms and formatting functions are accompanied by extensive tests
in `coretest::num::flt2dec` module. It also shows how to use individual
functions.
*/
// while this is extensively documented, this is in principle private which is
// only made public for testing. do not expose us.
#![doc(hidden)]
use prelude::*;
use i16;
use num::Float;
use slice::bytes;
pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded};
pub mod estimator;
pub mod bignum;
pub mod decoder;
/// Digit-generation algorithms.
pub mod strategy {
pub mod dragon;
pub mod grisu;
}
/// The minimum size of buffer necessary for the shortest mode.
///
/// It is a bit non-trivial to derive, but this is one plus the maximal number of
/// significant decimal digits from formatting algorithms with the shortest result.
/// The exact formula is `ceil(# bits in mantissa * log_10 2 + 1)`.
pub const MAX_SIG_DIGITS: usize = 17;
/// When `d[..n]` contains decimal digits, increase the last digit and propagate carry.
/// Returns a next digit when it causes the length change.
#[doc(hidden)]
pub fn round_up(d: &mut [u8], n: usize) -> Option<u8> {
match d[..n].iter().rposition(|&c| c != b'9') {
Some(i) => { // d[i+1..n] is all nines
d[i] += 1;
for j in i+1..n { d[j] = b'0'; }
None
}
None if n > 0 => { // 999..999 rounds to 1000..000 with an increased exponent
d[0] = b'1';
for j in 1..n { d[j] = b'0'; }
Some(b'0')
}
None => { // an empty buffer rounds up (a bit strange but reasonable)
Some(b'1')
}
}
}
/// Formatted parts.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Part<'a> {
/// Given number of zero digits.
Zero(usize),
/// A literal number up to 5 digits.
Num(u16),
/// A verbatim copy of given bytes.
Copy(&'a [u8]),
}
impl<'a> Part<'a> {
/// Returns the exact byte length of given part.
pub fn len(&self) -> usize {
match *self {
Part::Zero(nzeroes) => nzeroes,
Part::Num(v) => if v < 1_000 { if v < 10 { 1 } else if v < 100 { 2 } else { 3 } }
else { if v < 10_000 { 4 } else { 5 } },
Part::Copy(buf) => buf.len(),
}
}
/// Writes a part into the supplied buffer.
/// Returns the number of written bytes, or `None` if the buffer is not enough.
/// (It may still leave partially written bytes in the buffer; do not rely on that.)
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
let len = self.len();
if out.len() >= len {
match *self {
Part::Zero(nzeroes) => {
for c in &mut out[..nzeroes] { *c = b'0'; }
}
Part::Num(mut v) => {
for c in out[..len].iter_mut().rev() {
*c = b'0' + (v % 10) as u8;
v /= 10;
}
}
Part::Copy(buf) => {
bytes::copy_memory(buf, out);
}
}
Some(len)
} else {
None
}
}
}
/// Formatted result containing one or more parts.
/// This can be written to the byte buffer or converted to the allocated string.
#[derive(Clone)]
pub struct Formatted<'a> {
/// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
pub sign: &'static [u8],
/// Formatted parts to be rendered after a sign and optional zero padding.
pub parts: &'a [Part<'a>],
}
impl<'a> Formatted<'a> {
/// Returns the exact byte length of combined formatted result.
pub fn len(&self) -> usize {
let mut len = self.sign.len();
for part in self.parts {
len += part.len();
}
len
}
/// Writes all formatted parts into the supplied buffer.
/// Returns the number of written bytes, or `None` if the buffer is not enough.
/// (It may still leave partially written bytes in the buffer; do not rely on that.)
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
if out.len() < self.sign.len() { return None; }
bytes::copy_memory(self.sign, out);
let mut written = self.sign.len();
for part in self.parts {
match part.write(&mut out[written..]) {
Some(len) => { written += len; }
None => { return None; }
}
}
Some(written)
}
}
/// Formats given decimal digits `0.<...buf...> * 10^exp` into the decimal form
/// with at least given number of fractional digits. The result is stored to
/// the supplied parts array and a slice of written parts is returned.
///
/// `frac_digits` can be less than the number of actual fractional digits in `buf`;
/// it will be ignored and full digits will be printed. It is only used to print
/// additional zeroes after rendered digits. Thus `frac_digits` of 0 means that
/// it will only print given digits and nothing else.
fn digits_to_dec_str<'a>(buf: &'a [u8], exp: i16, frac_digits: usize,
parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] {
assert!(!buf.is_empty());
assert!(buf[0] > b'0');
assert!(parts.len() >= 4);
// if there is the restriction on the last digit position, `buf` is assumed to be
// left-padded with the virtual zeroes. the number of virtual zeroes, `nzeroes`,
// equals to `max(0, exp + frag_digits - buf.len())`, so that the position of
// the last digit `exp - buf.len() - nzeroes` is no more than `-frac_digits`:
//
// |<-virtual->|
// |<---- buf ---->| zeroes | exp
// 0. 1 2 3 4 5 6 7 8 9 _ _ _ _ _ _ x 10
// | | |
// 10^exp 10^(exp-buf.len()) 10^(exp-buf.len()-nzeroes)
//
// `nzeroes` is individually calculated for each case in order to avoid overflow.
if exp <= 0 {
// the decimal point is before rendered digits: [0.][000...000][1234][____]
let minus_exp = -(exp as i32) as usize;
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(minus_exp);
parts[2] = Part::Copy(buf);
if frac_digits > buf.len() && frac_digits - buf.len() > minus_exp {
parts[3] = Part::Zero((frac_digits - buf.len()) - minus_exp);
&parts[..4]
} else {
&parts[..3]
}
} else {
let exp = exp as usize;
if exp < buf.len() {
// the decimal point is inside rendered digits: [12][.][34][____]
parts[0] = Part::Copy(&buf[..exp]);
parts[1] = Part::Copy(b".");
parts[2] = Part::Copy(&buf[exp..]);
if frac_digits > buf.len() - exp {
parts[3] = Part::Zero(frac_digits - (buf.len() - exp));
&parts[..4]
} else {
&parts[..3]
}
} else {
// the decimal point is after rendered digits: [1234][____0000] or [1234][__][.][__].
parts[0] = Part::Copy(buf);
parts[1] = Part::Zero(exp - buf.len());
if frac_digits > 0 {
parts[2] = Part::Copy(b".");
parts[3] = Part::Zero(frac_digits);
&parts[..4]
} else {
&parts[..2]
}
}
}
}
/// Formats given decimal digits `0.<...buf...> * 10^exp` into the exponential form
/// with at least given number of significant digits. When `upper` is true,
/// the exponent will be prefixed by `E`; otherwise that's `e`. The result is
/// stored to the supplied parts array and a slice of written parts is returned.
///
/// `min_digits` can be less than the number of actual significant digits in `buf`;
/// it will be ignored and full digits will be printed. It is only used to print
/// additional zeroes after rendered digits. Thus `min_digits` of 0 means that
/// it will only print given digits and nothing else.
fn digits_to_exp_str<'a>(buf: &'a [u8], exp: i16, min_ndigits: usize, upper: bool,
parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] {
assert!(!buf.is_empty());
assert!(buf[0] > b'0');
assert!(parts.len() >= 6);
let mut n = 0;
parts[n] = Part::Copy(&buf[..1]);
n += 1;
if buf.len() > 1 || min_ndigits > 1 {
parts[n] = Part::Copy(b".");
parts[n + 1] = Part::Copy(&buf[1..]);
n += 2;
if min_ndigits > buf.len() {
parts[n] = Part::Zero(min_ndigits - buf.len());
n += 1;
}
}
// 0.1234 x 10^exp = 1.234 x 10^(exp-1)
let exp = exp as i32 - 1; // avoid underflow when exp is i16::MIN
if exp < 0 {
parts[n] = Part::Copy(if upper { b"E-" } else { b"e-" });
parts[n + 1] = Part::Num(-exp as u16);
} else {
parts[n] = Part::Copy(if upper { b"E" } else { b"e" });
parts[n + 1] = Part::Num(exp as u16);
}
&parts[..n + 2]
}
/// Sign formatting options.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Sign {
/// Prints `-` only for the negative non-zero values.
Minus, // -inf -1 0 0 1 inf nan
/// Prints `-` only for any negative values (including the negative zero).
MinusRaw, // -inf -1 0 0 1 inf nan
/// Prints `-` for the negative non-zero values, or `+` otherwise.
MinusPlus, // -inf -1 +0 +0 +1 +inf nan
/// Prints `-` for any negative values (including the negative zero), or `+` otherwise.
MinusPlusRaw, // -inf -1 -0 +0 +1 +inf nan
}
/// Returns the static byte string corresponding to the sign to be formatted.
/// It can be either `b""`, `b"+"` or `b"-"`.
fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static [u8] {
match (*decoded, sign) {
(FullDecoded::Nan, _) => b"",
(FullDecoded::Zero, Sign::Minus) => b"",
(FullDecoded::Zero, Sign::MinusRaw) => if negative { b"-" } else { b"" },
(FullDecoded::Zero, Sign::MinusPlus) => b"+",
(FullDecoded::Zero, Sign::MinusPlusRaw) => if negative { b"-" } else { b"+" },
(_, Sign::Minus) | (_, Sign::MinusRaw) => if negative { b"-" } else { b"" },
(_, Sign::MinusPlus) | (_, Sign::MinusPlusRaw) => if negative { b"-" } else { b"+" },
}
}
/// Formats given floating point number into the decimal form with at least
/// given number of fractional digits. The result is stored to the supplied parts
/// array while utilizing given byte buffer as a scratch. `upper` is only used to
/// determine the case of non-finite values, i.e. `inf` and `nan`. The first part
/// to be rendered is always a `Part::Sign` (which can be an empty string
/// if no sign is rendered).
///
/// `format_shortest` should be the underlying digit-generation function.
/// You probably would want `strategy::grisu::format_shortest` for this.
///
/// `frac_digits` can be less than the number of actual fractional digits in `v`;
/// it will be ignored and full digits will be printed. It is only used to print
/// additional zeroes after rendered digits. Thus `frac_digits` of 0 means that
/// it will only print given digits and nothing else.
///
/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long.
/// There should be at least 5 parts available, due to the worst case like
/// `[+][0.][0000][45][0000]` with `frac_digits = 10`.
pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T,
sign: Sign, frac_digits: usize, upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
assert!(parts.len() >= 4);
assert!(buf.len() >= MAX_SIG_DIGITS);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(if upper { b"NAN" } else { b"nan" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(if upper { b"INF" } else { b"inf" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if frac_digits > 0 { // [0.][0000]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
Formatted { sign: sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
Formatted { sign: sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
let (len, exp) = format_shortest(decoded, buf);
Formatted { sign: sign,
parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
}
}
}
/// Formats given floating point number into the decimal form or
/// the exponential form, depending on the resulting exponent. The result is
/// stored to the supplied parts array while utilizing given byte buffer
/// as a scratch. `upper` is used to determine the case of non-finite values
/// (`inf` and `nan`) or the case of the exponent prefix (`e` or `E`).
/// The first part to be rendered is always a `Part::Sign` (which can be
/// an empty string if no sign is rendered).
///
/// `format_shortest` should be the underlying digit-generation function.
/// You probably would want `strategy::grisu::format_shortest` for this.
///
/// The `dec_bounds` is a tuple `(lo, hi)` such that the number is formatted
/// as decimal only when `10^lo <= V < 10^hi`. Note that this is the *apparant* `V`
/// instead of the actual `v`! Thus any printed exponent in the exponential form
/// cannot be in this range, avoiding any confusion.
///
/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long.
/// There should be at least 7 parts available, due to the worst case like
/// `[+][1][.][2345][e][-][67]`.
pub fn to_shortest_exp_str<'a, T, F>(mut format_shortest: F, v: T,
sign: Sign, dec_bounds: (i16, i16), upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
assert!(parts.len() >= 6);
assert!(buf.len() >= MAX_SIG_DIGITS);
assert!(dec_bounds.0 <= dec_bounds.1);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(if upper { b"NAN" } else { b"nan" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(if upper { b"INF" } else { b"inf" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 {
Part::Copy(b"0")
} else {
Part::Copy(if upper { b"0E0" } else { b"0e0" })
};
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Finite(ref decoded) => {
let (len, exp) = format_shortest(decoded, buf);
let vis_exp = exp as i32 - 1;
let parts = if dec_bounds.0 as i32 <= vis_exp && vis_exp < dec_bounds.1 as i32 {
digits_to_dec_str(&buf[..len], exp, 0, parts)
} else {
digits_to_exp_str(&buf[..len], exp, 0, upper, parts)
};
Formatted { sign: sign, parts: parts }
}
}
}
/// Returns rather crude approximation (upper bound) for the maximum buffer size
/// calculated from the given decoded exponent.
///
/// The exact limit is:
///
/// - when `exp < 0`, the maximum length is `ceil(log_10 (5^-exp * (2^64 - 1)))`.
/// - when `exp >= 0`, the maximum length is `ceil(log_10 (2^exp * (2^64 - 1)))`.
///
/// `ceil(log_10 (x^exp * (2^64 - 1)))` is less than `ceil(log_10 (2^64 - 1)) +
/// ceil(exp * log_10 x)`, which is in turn less than `20 + (1 + exp * log_10 x)`.
/// We use the facts that `log_10 2 < 5/16` and `log_10 5 < 12/16`, which is
/// enough for our purposes.
///
/// Why do we need this? `format_exact` functions will fill the entire buffer
/// unless limited by the last digit restriction, but it is possible that
/// the number of digits requested is ridiculously large (say, 30,000 digits).
/// The vast majority of buffer will be filled with zeroes, so we don't want to
/// allocate all the buffer beforehand. Consequently, for any given arguments,
/// 826 bytes of buffer should be sufficient for `f64`. Compare this with
/// the actual number for the worst case: 770 bytes (when `exp = -1074`).
fn estimate_max_buf_len(exp: i16) -> usize {
21 + ((if exp < 0 { -12 } else { 5 } * exp as i32) as usize >> 4)
}
/// Formats given floating point number into the exponential form with
/// exactly given number of significant digits. The result is stored to
/// the supplied parts array while utilizing given byte buffer as a scratch.
/// `upper` is used to determine the case of the exponent prefix (`e` or `E`).
/// The first part to be rendered is always a `Part::Sign` (which can be
/// an empty string if no sign is rendered).
///
/// `format_exact` should be the underlying digit-generation function.
/// You probably would want `strategy::grisu::format_exact` for this.
///
/// The byte buffer should be at least `ndigits` bytes long unless `ndigits` is
/// so large that only the fixed number of digits will be ever written.
/// (The tipping point for `f64` is about 800, so 1000 bytes should be enough.)
/// There should be at least 7 parts available, due to the worst case like
/// `[+][1][.][2345][e][-][67]`.
pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T,
sign: Sign, ndigits: usize, upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
assert!(parts.len() >= 6);
assert!(ndigits > 0);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(if upper { b"NAN" } else { b"nan" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(if upper { b"INF" } else { b"inf" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if ndigits > 1 { // [0.][0000][e0]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(ndigits - 1);
parts[2] = Part::Copy(if upper { b"E0" } else { b"e0" });
Formatted { sign: sign, parts: &parts[..3] }
} else {
parts[0] = Part::Copy(if upper { b"0E0" } else { b"0e0" });
Formatted { sign: sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
let maxlen = estimate_max_buf_len(decoded.exp);
assert!(buf.len() >= ndigits || buf.len() >= maxlen);
let trunc = if ndigits < maxlen { ndigits } else { maxlen };
let (len, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN);
Formatted { sign: sign,
parts: digits_to_exp_str(&buf[..len], exp, ndigits, upper, parts) }
}
}
}
/// Formats given floating point number into the decimal form with exactly
/// given number of fractional digits. The result is stored to the supplied parts
/// array while utilizing given byte buffer as a scratch. `upper` is only used to
/// determine the case of non-finite values, i.e. `inf` and `nan`. The first part
/// to be rendered is always a `Part::Sign` (which can be an empty string
/// if no sign is rendered).
///
/// `format_exact` should be the underlying digit-generation function.
/// You probably would want `strategy::grisu::format_exact` for this.
///
/// The byte buffer should be enough for the output unless `frac_digits` is
/// so large that only the fixed number of digits will be ever written.
/// (The tipping point for `f64` is about 800, and 1000 bytes should be enough.)
/// There should be at least 5 parts available, due to the worst case like
/// `[+][0.][0000][45][0000]` with `frac_digits = 10`.
pub fn to_exact_fixed_str<'a, T, F>(mut format_exact: F, v: T,
sign: Sign, frac_digits: usize, upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
assert!(parts.len() >= 4);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(if upper { b"NAN" } else { b"nan" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(if upper { b"INF" } else { b"inf" });
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if frac_digits > 0 { // [0.][0000]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
Formatted { sign: sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
Formatted { sign: sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
let maxlen = estimate_max_buf_len(decoded.exp);
assert!(buf.len() >= maxlen);
// it *is* possible that `frac_digits` is ridiculously large.
// `format_exact` will end rendering digits much earlier in this case,
// because we are strictly limited by `maxlen`.
let limit = if frac_digits < 0x8000 { -(frac_digits as i16) } else { i16::MIN };
let (len, exp) = format_exact(decoded, &mut buf[..maxlen], limit);
if exp <= limit {
// `format_exact` always returns at least one digit even though the restriction
// hasn't been met, so we catch this condition and treats as like zeroes.
// this does not include the case that the restriction has been met
// only after the final rounding-up; it's a regular case with `exp = limit + 1`.
debug_assert_eq!(len, 0);
if frac_digits > 0 { // [0.][0000]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
Formatted { sign: sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
Formatted { sign: sign, parts: &parts[..1] }
}
} else {
Formatted { sign: sign,
parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
}
}
}
}

View File

@ -0,0 +1,327 @@
// 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.
/*!
Almost direct (but slightly optimized) Rust translation of Figure 3 of [1].
[1] Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers
quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116.
*/
use prelude::*;
use num::Float;
use cmp::Ordering;
use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
use num::flt2dec::estimator::estimate_scaling_factor;
use num::flt2dec::bignum::Digit32 as Digit;
use num::flt2dec::bignum::Big32x36 as Big;
// FIXME(#22540) const ref to static array seems to ICE
static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000];
static TWOPOW10: [Digit; 10] = [2, 20, 200, 2000, 20000, 200000,
2000000, 20000000, 200000000, 2000000000];
// precalculated arrays of `Digit`s for 10^(2^n)
static POW10TO16: [Digit; 2] = [0x6fc10000, 0x2386f2];
static POW10TO32: [Digit; 4] = [0, 0x85acef81, 0x2d6d415b, 0x4ee];
static POW10TO64: [Digit; 7] = [0, 0, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
static POW10TO128: [Digit; 14] =
[0, 0, 0, 0, 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08,
0xbccdb0da, 0xa6337f19, 0xe91f2603, 0x24e];
static POW10TO256: [Digit; 27] =
[0, 0, 0, 0, 0, 0, 0, 0, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6,
0xcf4a6e70, 0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e,
0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7];
#[doc(hidden)]
pub fn mul_pow10<'a>(x: &'a mut Big, n: usize) -> &'a mut Big {
debug_assert!(n < 512);
if n & 7 != 0 { x.mul_small(POW10[n & 7]); }
if n & 8 != 0 { x.mul_small(POW10[8]); }
if n & 16 != 0 { x.mul_digits(&POW10TO16); }
if n & 32 != 0 { x.mul_digits(&POW10TO32); }
if n & 64 != 0 { x.mul_digits(&POW10TO64); }
if n & 128 != 0 { x.mul_digits(&POW10TO128); }
if n & 256 != 0 { x.mul_digits(&POW10TO256); }
x
}
fn div_2pow10<'a>(x: &'a mut Big, mut n: usize) -> &'a mut Big {
let largest = POW10.len() - 1;
while n > largest {
x.div_rem_small(POW10[largest]);
n -= largest;
}
x.div_rem_small(TWOPOW10[n]);
x
}
// only usable when `x < 16 * scale`; `scaleN` should be `scale.mul_small(N)`
fn div_rem_upto_16<'a>(x: &'a mut Big, scale: &Big,
scale2: &Big, scale4: &Big, scale8: &Big) -> (u8, &'a mut Big) {
let mut d = 0;
if *x >= *scale8 { x.sub(scale8); d += 8; }
if *x >= *scale4 { x.sub(scale4); d += 4; }
if *x >= *scale2 { x.sub(scale2); d += 2; }
if *x >= *scale { x.sub(scale); d += 1; }
debug_assert!(*x < *scale);
(d, x)
}
/// The shortest mode implementation for Dragon.
pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) {
// the number `v` to format is known to be:
// - equal to `mant * 2^exp`;
// - preceded by `(mant - 2 * minus) * 2^exp` in the original type; and
// - followed by `(mant + 2 * plus) * 2^exp` in the original type.
//
// obviously, `minus` and `plus` cannot be zero. (for infinities, we use out-of-range values.)
// also we assume that at least one digit is generated, i.e. `mant` cannot be zero too.
//
// this also means that any number between `low = (mant - minus) * 2^exp` and
// `high = (mant + plus) * 2^exp` will map to this exact floating point number,
// with bounds included when the original mantissa was even (i.e. `!mant_was_odd`).
assert!(d.mant > 0);
assert!(d.minus > 0);
assert!(d.plus > 0);
assert!(d.mant.checked_add(d.plus).is_some());
assert!(d.mant.checked_sub(d.minus).is_some());
assert!(buf.len() >= MAX_SIG_DIGITS);
// `a.cmp(&b) < rounding` is `if d.inclusive {a <= b} else {a < b}`
let rounding = if d.inclusive {Ordering::Greater} else {Ordering::Equal};
// estimate `k_0` from original inputs satisfying `10^(k_0-1) < high <= 10^(k_0+1)`.
// the tight bound `k` satisfying `10^(k-1) < high <= 10^k` is calculated later.
let mut k = estimate_scaling_factor(d.mant + d.plus, d.exp);
// convert `{mant, plus, minus} * 2^exp` into the fractional form so that:
// - `v = mant / scale`
// - `low = (mant - minus) / scale`
// - `high = (mant + plus) / scale`
let mut mant = Big::from_u64(d.mant);
let mut minus = Big::from_u64(d.minus);
let mut plus = Big::from_u64(d.plus);
let mut scale = Big::from_small(1);
if d.exp < 0 {
scale.mul_pow2(-d.exp as usize);
} else {
mant.mul_pow2(d.exp as usize);
minus.mul_pow2(d.exp as usize);
plus.mul_pow2(d.exp as usize);
}
// divide `mant` by `10^k`. now `scale / 10 < mant + plus <= scale * 10`.
if k >= 0 {
mul_pow10(&mut scale, k as usize);
} else {
mul_pow10(&mut mant, -k as usize);
mul_pow10(&mut minus, -k as usize);
mul_pow10(&mut plus, -k as usize);
}
// fixup when `mant + plus > scale` (or `>=`).
// we are not actually modifying `scale`, since we can skip the initial multiplication instead.
// now `scale < mant + plus <= scale * 10` and we are ready to generate digits.
//
// note that `d[0]` *can* be zero, when `scale - plus < mant < scale`.
// in this case rounding-up condition (`up` below) will be triggered immediately.
if scale.cmp(mant.clone().add(&plus)) < rounding {
// equivalent to scaling `scale` by 10
k += 1;
} else {
mant.mul_small(10);
minus.mul_small(10);
plus.mul_small(10);
}
// cache `(2, 4, 8) * scale` for digit generation.
let mut scale2 = scale.clone(); scale2.mul_pow2(1);
let mut scale4 = scale.clone(); scale4.mul_pow2(2);
let mut scale8 = scale.clone(); scale8.mul_pow2(3);
let mut down;
let mut up;
let mut i = 0;
loop {
// invariants, where `d[0..n-1]` are digits generated so far:
// - `v = mant / scale * 10^(k-n-1) + d[0..n-1] * 10^(k-n)`
// - `v - low = minus / scale * 10^(k-n-1)`
// - `high - v = plus / scale * 10^(k-n-1)`
// - `(mant + plus) / scale <= 10` (thus `mant / scale < 10`)
// where `d[i..j]` is a shorthand for `d[i] * 10^(j-i) + ... + d[j-1] * 10 + d[j]`.
// generate one digit: `d[n] = floor(mant / scale) < 10`.
let (d, _) = div_rem_upto_16(&mut mant, &scale, &scale2, &scale4, &scale8);
debug_assert!(d < 10);
buf[i] = b'0' + d;
i += 1;
// this is a simplified description of the modified Dragon algorithm.
// many intermediate derivations and completeness arguments are omitted for convenience.
//
// start with modified invariants, as we've updated `n`:
// - `v = mant / scale * 10^(k-n) + d[0..n-1] * 10^(k-n)`
// - `v - low = minus / scale * 10^(k-n)`
// - `high - v = plus / scale * 10^(k-n)`
//
// assume that `d[0..n-1]` is the shortest representation between `low` and `high`,
// i.e. `d[0..n-1]` satisfies both of the following but `d[0..n-2]` doesn't:
// - `low < d[0..n-1] * 10^(k-n) < high` (bijectivity: digits round to `v`); and
// - `abs(v / 10^(k-n) - d[0..n-1]) <= 1/2` (the last digit is correct).
//
// the second condition simplifies to `2 * mant <= scale`.
// solving invariants in terms of `mant`, `low` and `high` yields
// a simpler version of the first condition: `-plus < mant < minus`.
// since `-plus < 0 <= mant`, we have the correct shortest representation
// when `mant < minus` and `2 * mant <= scale`.
// (the former becomes `mant <= minus` when the original mantissa is even.)
//
// when the second doesn't hold (`2 * mant > scale`), we need to increase the last digit.
// this is enough for restoring that condition: we already know that
// the digit generation guarantees `0 <= v / 10^(k-n) - d[0..n-1] < 1`.
// in this case, the first condition becomes `-plus < mant - scale < minus`.
// since `mant < scale` after the generation, we have `scale < mant + plus`.
// (again, this becomes `scale <= mant + plus` when the original mantissa is even.)
//
// in short:
// - stop and round `down` (keep digits as is) when `mant < minus` (or `<=`).
// - stop and round `up` (increase the last digit) when `scale < mant + plus` (or `<=`).
// - keep generating otherwise.
down = mant.cmp(&minus) < rounding;
up = scale.cmp(mant.clone().add(&plus)) < rounding;
if down || up { break; } // we have the shortest representation, proceed to the rounding
// restore the invariants.
// this makes the algorithm always terminating: `minus` and `plus` always increases,
// but `mant` is clipped modulo `scale` and `scale` is fixed.
mant.mul_small(10);
minus.mul_small(10);
plus.mul_small(10);
}
// rounding up happens when
// i) only the rounding-up condition was triggered, or
// ii) both conditions were triggered and tie breaking prefers rounding up.
if up && (!down || *mant.mul_pow2(1) >= scale) {
// if rounding up changes the length, the exponent should also change.
// it seems that this condition is very hard to satisfy (possibly impossible),
// but we are just being safe and consistent here.
if let Some(c) = round_up(buf, i) {
buf[i] = c;
i += 1;
k += 1;
}
}
(i, k)
}
/// The exact and fixed mode implementation for Dragon.
pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) {
assert!(d.mant > 0);
assert!(d.minus > 0);
assert!(d.plus > 0);
assert!(d.mant.checked_add(d.plus).is_some());
assert!(d.mant.checked_sub(d.minus).is_some());
// estimate `k_0` from original inputs satisfying `10^(k_0-1) < v <= 10^(k_0+1)`.
let mut k = estimate_scaling_factor(d.mant, d.exp);
// `v = mant / scale`.
let mut mant = Big::from_u64(d.mant);
let mut scale = Big::from_small(1);
if d.exp < 0 {
scale.mul_pow2(-d.exp as usize);
} else {
mant.mul_pow2(d.exp as usize);
}
// divide `mant` by `10^k`. now `scale / 10 < mant <= scale * 10`.
if k >= 0 {
mul_pow10(&mut scale, k as usize);
} else {
mul_pow10(&mut mant, -k as usize);
}
// fixup when `mant + plus >= scale`, where `plus / scale = 10^-buf.len() / 2`.
// in order to keep the fixed-size bignum, we actually use `mant + floor(plus) >= scale`.
// we are not actually modifying `scale`, since we can skip the initial multiplication instead.
// again with the shortest algorithm, `d[0]` can be zero but will be eventually rounded up.
if *div_2pow10(&mut scale.clone(), buf.len()).add(&mant) >= scale {
// equivalent to scaling `scale` by 10
k += 1;
} else {
mant.mul_small(10);
}
// if we are working with the last-digit limitation, we need to shorten the buffer
// before the actual rendering in order to avoid double rounding.
// note that we have to enlarge the buffer again when rounding up happens!
let mut len = if k < limit {
// oops, we cannot even produce *one* digit.
// this is possible when, say, we've got something like 9.5 and it's being rounded to 10.
// we return an empty buffer, with an exception of the later rounding-up case
// which occurs when `k == limit` and has to produce exactly one digit.
0
} else if ((k as i32 - limit as i32) as usize) < buf.len() {
(k - limit) as usize
} else {
buf.len()
};
if len > 0 {
// cache `(2, 4, 8) * scale` for digit generation.
// (this can be expensive, so do not calculate them when the buffer is empty.)
let mut scale2 = scale.clone(); scale2.mul_pow2(1);
let mut scale4 = scale.clone(); scale4.mul_pow2(2);
let mut scale8 = scale.clone(); scale8.mul_pow2(3);
for i in 0..len {
if mant.is_zero() { // following digits are all zeroes, we stop here
// do *not* try to perform rounding! rather, fill remaining digits.
for c in &mut buf[i..len] { *c = b'0'; }
return (len, k);
}
let mut d = 0;
if mant >= scale8 { mant.sub(&scale8); d += 8; }
if mant >= scale4 { mant.sub(&scale4); d += 4; }
if mant >= scale2 { mant.sub(&scale2); d += 2; }
if mant >= scale { mant.sub(&scale); d += 1; }
debug_assert!(mant < scale);
debug_assert!(d < 10);
buf[i] = b'0' + d;
mant.mul_small(10);
}
}
// rounding up if we stop in the middle of digits
if mant >= *scale.mul_small(5) {
// if rounding up changes the length, the exponent should also change.
// but we've been requested a fixed number of digits, so do not alter the buffer...
if let Some(c) = round_up(buf, len) {
// ...unless we've been requested the fixed precision instead.
// we also need to check that, if the original buffer was empty,
// the additional digit can only be added when `k == limit` (edge case).
k += 1;
if k > limit && len < buf.len() {
buf[len] = c;
len += 1;
}
}
}
(len, k)
}

View File

@ -0,0 +1,749 @@
// 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.
/*!
Rust adaptation of Grisu3 algorithm described in [1]. It uses about
1KB of precomputed table, and in turn, it's very quick for most inputs.
[1] Florian Loitsch. 2010. Printing floating-point numbers quickly and
accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243.
*/
use prelude::*;
use num::Float;
use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
/// A custom 64-bit floating point type, representing `f * 2^e`.
#[derive(Copy, Clone, Debug)]
#[doc(hidden)]
pub struct Fp {
/// The integer mantissa.
pub f: u64,
/// The exponent in base 2.
pub e: i16,
}
impl Fp {
/// Returns a correctly rounded product of itself and `other`.
fn mul(&self, other: &Fp) -> Fp {
const MASK: u64 = 0xffffffff;
let a = self.f >> 32;
let b = self.f & MASK;
let c = other.f >> 32;
let d = other.f & MASK;
let ac = a * c;
let bc = b * c;
let ad = a * d;
let bd = b * d;
let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */;
let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
let e = self.e + other.e + 64;
Fp { f: f, e: e }
}
/// Normalizes itself so that the resulting mantissa is at least `2^63`.
fn normalize(&self) -> Fp {
let mut f = self.f;
let mut e = self.e;
if f >> (64 - 32) == 0 { f <<= 32; e -= 32; }
if f >> (64 - 16) == 0 { f <<= 16; e -= 16; }
if f >> (64 - 8) == 0 { f <<= 8; e -= 8; }
if f >> (64 - 4) == 0 { f <<= 4; e -= 4; }
if f >> (64 - 2) == 0 { f <<= 2; e -= 2; }
if f >> (64 - 1) == 0 { f <<= 1; e -= 1; }
debug_assert!(f >= (1 >> 63));
Fp { f: f, e: e }
}
/// Normalizes itself to have the shared exponent.
/// It can only decrease the exponent (and thus increase the mantissa).
fn normalize_to(&self, e: i16) -> Fp {
let edelta = self.e - e;
assert!(edelta >= 0);
let edelta = edelta as usize;
assert_eq!(self.f << edelta >> edelta, self.f);
Fp { f: self.f << edelta, e: e }
}
}
// see the comments in `format_shortest_opt` for the rationale.
#[doc(hidden)] pub const ALPHA: i16 = -60;
#[doc(hidden)] pub const GAMMA: i16 = -32;
/*
# the following Python code generates this table:
for i in xrange(-308, 333, 8):
if i >= 0: f = 10**i; e = 0
else: f = 2**(80-4*i) // 10**-i; e = 4 * i - 80
l = f.bit_length()
f = ((f << 64 >> (l-1)) + 1) >> 1; e += l - 64
print ' (%#018x, %5d, %4d),' % (f, e, i)
*/
// FIXME(#22540) const ref to static array seems to ICE
#[doc(hidden)]
pub static CACHED_POW10: [(u64, i16, i16); 81] = [ // (f, e, k)
(0xe61acf033d1a45df, -1087, -308),
(0xab70fe17c79ac6ca, -1060, -300),
(0xff77b1fcbebcdc4f, -1034, -292),
(0xbe5691ef416bd60c, -1007, -284),
(0x8dd01fad907ffc3c, -980, -276),
(0xd3515c2831559a83, -954, -268),
(0x9d71ac8fada6c9b5, -927, -260),
(0xea9c227723ee8bcb, -901, -252),
(0xaecc49914078536d, -874, -244),
(0x823c12795db6ce57, -847, -236),
(0xc21094364dfb5637, -821, -228),
(0x9096ea6f3848984f, -794, -220),
(0xd77485cb25823ac7, -768, -212),
(0xa086cfcd97bf97f4, -741, -204),
(0xef340a98172aace5, -715, -196),
(0xb23867fb2a35b28e, -688, -188),
(0x84c8d4dfd2c63f3b, -661, -180),
(0xc5dd44271ad3cdba, -635, -172),
(0x936b9fcebb25c996, -608, -164),
(0xdbac6c247d62a584, -582, -156),
(0xa3ab66580d5fdaf6, -555, -148),
(0xf3e2f893dec3f126, -529, -140),
(0xb5b5ada8aaff80b8, -502, -132),
(0x87625f056c7c4a8b, -475, -124),
(0xc9bcff6034c13053, -449, -116),
(0x964e858c91ba2655, -422, -108),
(0xdff9772470297ebd, -396, -100),
(0xa6dfbd9fb8e5b88f, -369, -92),
(0xf8a95fcf88747d94, -343, -84),
(0xb94470938fa89bcf, -316, -76),
(0x8a08f0f8bf0f156b, -289, -68),
(0xcdb02555653131b6, -263, -60),
(0x993fe2c6d07b7fac, -236, -52),
(0xe45c10c42a2b3b06, -210, -44),
(0xaa242499697392d3, -183, -36),
(0xfd87b5f28300ca0e, -157, -28),
(0xbce5086492111aeb, -130, -20),
(0x8cbccc096f5088cc, -103, -12),
(0xd1b71758e219652c, -77, -4),
(0x9c40000000000000, -50, 4),
(0xe8d4a51000000000, -24, 12),
(0xad78ebc5ac620000, 3, 20),
(0x813f3978f8940984, 30, 28),
(0xc097ce7bc90715b3, 56, 36),
(0x8f7e32ce7bea5c70, 83, 44),
(0xd5d238a4abe98068, 109, 52),
(0x9f4f2726179a2245, 136, 60),
(0xed63a231d4c4fb27, 162, 68),
(0xb0de65388cc8ada8, 189, 76),
(0x83c7088e1aab65db, 216, 84),
(0xc45d1df942711d9a, 242, 92),
(0x924d692ca61be758, 269, 100),
(0xda01ee641a708dea, 295, 108),
(0xa26da3999aef774a, 322, 116),
(0xf209787bb47d6b85, 348, 124),
(0xb454e4a179dd1877, 375, 132),
(0x865b86925b9bc5c2, 402, 140),
(0xc83553c5c8965d3d, 428, 148),
(0x952ab45cfa97a0b3, 455, 156),
(0xde469fbd99a05fe3, 481, 164),
(0xa59bc234db398c25, 508, 172),
(0xf6c69a72a3989f5c, 534, 180),
(0xb7dcbf5354e9bece, 561, 188),
(0x88fcf317f22241e2, 588, 196),
(0xcc20ce9bd35c78a5, 614, 204),
(0x98165af37b2153df, 641, 212),
(0xe2a0b5dc971f303a, 667, 220),
(0xa8d9d1535ce3b396, 694, 228),
(0xfb9b7cd9a4a7443c, 720, 236),
(0xbb764c4ca7a44410, 747, 244),
(0x8bab8eefb6409c1a, 774, 252),
(0xd01fef10a657842c, 800, 260),
(0x9b10a4e5e9913129, 827, 268),
(0xe7109bfba19c0c9d, 853, 276),
(0xac2820d9623bf429, 880, 284),
(0x80444b5e7aa7cf85, 907, 292),
(0xbf21e44003acdd2d, 933, 300),
(0x8e679c2f5e44ff8f, 960, 308),
(0xd433179d9c8cb841, 986, 316),
(0x9e19db92b4e31ba9, 1013, 324),
(0xeb96bf6ebadf77d9, 1039, 332),
];
#[doc(hidden)] pub const CACHED_POW10_FIRST_E: i16 = -1087;
#[doc(hidden)] pub const CACHED_POW10_LAST_E: i16 = 1039;
#[doc(hidden)]
pub fn cached_power(alpha: i16, gamma: i16) -> (i16, Fp) {
let offset = CACHED_POW10_FIRST_E as i32;
let range = (CACHED_POW10.len() as i32) - 1;
let domain = (CACHED_POW10_LAST_E - CACHED_POW10_FIRST_E) as i32;
let idx = ((gamma as i32) - offset) * range / domain;
let (f, e, k) = CACHED_POW10[idx as usize];
debug_assert!(alpha <= e && e <= gamma);
(k, Fp { f: f, e: e })
}
/// Given `x > 0`, returns `(k, 10^k)` such that `10^k <= x < 10^(k+1)`.
#[doc(hidden)]
pub fn max_pow10_no_more_than(x: u32) -> (u8, u32) {
debug_assert!(x > 0);
const X9: u32 = 10_0000_0000;
const X8: u32 = 1_0000_0000;
const X7: u32 = 1000_0000;
const X6: u32 = 100_0000;
const X5: u32 = 10_0000;
const X4: u32 = 1_0000;
const X3: u32 = 1000;
const X2: u32 = 100;
const X1: u32 = 10;
if x < X4 {
if x < X2 { if x < X1 {(0, 1)} else {(1, X1)} }
else { if x < X3 {(2, X2)} else {(3, X3)} }
} else {
if x < X6 { if x < X5 {(4, X4)} else {(5, X5)} }
else if x < X8 { if x < X7 {(6, X6)} else {(7, X7)} }
else { if x < X9 {(8, X8)} else {(9, X9)} }
}
}
/// The shortest mode implementation for Grisu.
///
/// It returns `None` when it would return an inexact representation otherwise.
pub fn format_shortest_opt(d: &Decoded,
buf: &mut [u8]) -> Option<(/*#digits*/ usize, /*exp*/ i16)> {
assert!(d.mant > 0);
assert!(d.minus > 0);
assert!(d.plus > 0);
assert!(d.mant.checked_add(d.plus).is_some());
assert!(d.mant.checked_sub(d.minus).is_some());
assert!(buf.len() >= MAX_SIG_DIGITS);
assert!(d.mant + d.plus < (1 << 61)); // we need at least three bits of additional precision
// start with the normalized values with the shared exponent
let plus = Fp { f: d.mant + d.plus, e: d.exp }.normalize();
let minus = Fp { f: d.mant - d.minus, e: d.exp }.normalize_to(plus.e);
let v = Fp { f: d.mant, e: d.exp }.normalize_to(plus.e);
// find any `cached = 10^minusk` such that `ALPHA <= minusk + plus.e + 64 <= GAMMA`.
// since `plus` is normalized, this means `2^(62 + ALPHA) <= plus * cached < 2^(64 + GAMMA)`;
// given our choices of `ALPHA` and `GAMMA`, this puts `plus * cached` into `[4, 2^32)`.
//
// it is obviously desirable to maximize `GAMMA - ALPHA`,
// so that we don't need many cached powers of 10, but there are some considerations:
//
// 1. we want to keep `floor(plus * cached)` within `u32` since it needs a costly division.
// (this is not really avoidable, remainder is required for accuracy estimation.)
// 2. the remainder of `floor(plus * cached)` repeatedly gets multiplied by 10,
// and it should not overflow.
//
// the first gives `64 + GAMMA <= 32`, while the second gives `10 * 2^-ALPHA <= 2^64`;
// -60 and -32 is the maximal range with this constraint, and V8 also uses them.
let (minusk, cached) = cached_power(ALPHA - plus.e - 64, GAMMA - plus.e - 64);
// scale fps. this gives the maximal error of 1 ulp (proved from Theorem 5.1).
let plus = plus.mul(&cached);
let minus = minus.mul(&cached);
let v = v.mul(&cached);
debug_assert_eq!(plus.e, minus.e);
debug_assert_eq!(plus.e, v.e);
// +- actual range of minus
// | <---|---------------------- unsafe region --------------------------> |
// | | |
// | |<--->| | <--------------- safe region ---------------> | |
// | | | | | |
// |1 ulp|1 ulp| |1 ulp|1 ulp| |1 ulp|1 ulp|
// |<--->|<--->| |<--->|<--->| |<--->|<--->|
// |-----|-----|-------...-------|-----|-----|-------...-------|-----|-----|
// | minus | | v | | plus |
// minus1 minus0 v - 1 ulp v + 1 ulp plus0 plus1
//
// above `minus`, `v` and `plus` are *quantized* approximations (error < 1 ulp).
// as we don't know the error is positive or negative, we use two approximations spaced equally
// and have the maximal error of 2 ulps.
//
// the "unsafe region" is a liberal interval which we initially generate.
// the "safe region" is a conservative interval which we only accept.
// we start with the correct repr within the unsafe region, and try to find the closest repr
// to `v` which is also within the safe region. if we can't, we give up.
let plus1 = plus.f + 1;
// let plus0 = plus.f - 1; // only for explanation
// let minus0 = minus.f + 1; // only for explanation
let minus1 = minus.f - 1;
let e = -plus.e as usize; // shared exponent
// divide `plus1` into integral and fractional parts.
// integral parts are guaranteed to fit in u32, since cached power guarantees `plus < 2^32`
// and normalized `plus.f` is always less than `2^64 - 2^4` due to the precision requirement.
let plus1int = (plus1 >> e) as u32;
let plus1frac = plus1 & ((1 << e) - 1);
// calculate the largest `10^max_kappa` no more than `plus1` (thus `plus1 < 10^(max_kappa+1)`).
// this is an upper bound of `kappa` below.
let (max_kappa, max_ten_kappa) = max_pow10_no_more_than(plus1int);
let mut i = 0;
let exp = max_kappa as i16 - minusk + 1;
// Theorem 6.2: if `k` is the greatest integer s.t. `0 <= y mod 10^k <= y - x`,
// then `V = floor(y / 10^k) * 10^k` is in `[x, y]` and one of the shortest
// representations (with the minimal number of significant digits) in that range.
//
// find the digit length `kappa` between `(minus1, plus1)` as per Theorem 6.2.
// Theorem 6.2 can be adopted to exclude `x` by requiring `y mod 10^k < y - x` instead.
// (e.g. `x` = 32000, `y` = 32777; `kappa` = 2 since `y mod 10^3 = 777 < y - x = 777`.)
// the algorithm relies on the later verification phase to exclude `y`.
let delta1 = plus1 - minus1;
// let delta1int = (delta1 >> e) as usize; // only for explanation
let delta1frac = delta1 & ((1 << e) - 1);
// render integral parts, while checking for the accuracy at each step.
let mut kappa = max_kappa as i16;
let mut ten_kappa = max_ten_kappa; // 10^kappa
let mut remainder = plus1int; // digits yet to be rendered
loop { // we always have at least one digit to render, as `plus1 >= 10^kappa`
// invariants:
// - `delta1int <= remainder < 10^(kappa+1)`
// - `plus1int = d[0..n-1] * 10^(kappa+1) + remainder`
// (it follows that `remainder = plus1int % 10^(kappa+1)`)
// divide `remainder` by `10^kappa`. both are scaled by `2^-e`.
let q = remainder / ten_kappa;
let r = remainder % ten_kappa;
debug_assert!(q < 10);
buf[i] = b'0' + q as u8;
i += 1;
let plus1rem = ((r as u64) << e) + plus1frac; // == (plus1 % 10^kappa) * 2^e
if plus1rem < delta1 {
// `plus1 % 10^kappa < delta1 = plus1 - minus1`; we've found the correct `kappa`.
let ten_kappa = (ten_kappa as u64) << e; // scale 10^kappa back to the shared exponent
return round_and_weed(&mut buf[..i], exp, plus1rem, delta1, plus1 - v.f, ten_kappa, 1);
}
// break the loop when we have rendered all integral digits.
// the exact number of digits is `max_kappa + 1` as `plus1 < 10^(max_kappa+1)`.
if i > max_kappa as usize {
debug_assert_eq!(ten_kappa, 1);
debug_assert_eq!(kappa, 0);
break;
}
// restore invariants
kappa -= 1;
ten_kappa /= 10;
remainder = r;
}
// render fractional parts, while checking for the accuracy at each step.
// this time we rely on repeated multiplications, as division will lose the precision.
let mut remainder = plus1frac;
let mut threshold = delta1frac;
let mut ulp = 1;
loop { // the next digit should be significant as we've tested that before breaking out
// invariants, where `m = max_kappa + 1` (# of digits in the integral part):
// - `remainder < 2^e`
// - `plus1frac * 10^(n-m) = d[m..n-1] * 2^e + remainder`
remainder *= 10; // won't overflow, `2^e * 10 < 2^64`
threshold *= 10;
ulp *= 10;
// divide `remainder` by `10^kappa`.
// both are scaled by `2^e / 10^kappa`, so the latter is implicit here.
let q = remainder >> e;
let r = remainder & ((1 << e) - 1);
debug_assert!(q < 10);
buf[i] = b'0' + q as u8;
i += 1;
if r < threshold {
let ten_kappa = 1 << e; // implicit divisor
return round_and_weed(&mut buf[..i], exp, r, threshold,
(plus1 - v.f) * ulp, ten_kappa, ulp);
}
// restore invariants
kappa -= 1;
remainder = r;
}
// we've generated all significant digits of `plus1`, but not sure if it's the optimal one.
// for example, if `minus1` is 3.14153... and `plus1` is 3.14158..., there are 5 different
// shortest representation from 3.14154 to 3.14158 but we only have the greatest one.
// we have to successively decrease the last digit and check if this is the optimal repr.
// there are at most 9 candidates (..1 to ..9), so this is fairly quick. ("rounding" phase)
//
// the function checks if this "optimal" repr is actually within the ulp ranges,
// and also, it is possible that the "second-to-optimal" repr can actually be optimal
// due to the rounding error. in either cases this returns `None`. ("weeding" phase)
//
// all arguments here are scaled by the common (but implicit) value `k`, so that:
// - `remainder = (plus1 % 10^kappa) * k`
// - `threshold = (plus1 - minus1) * k` (and also, `remainder < threshold`)
// - `plus1v = (plus1 - v) * k` (and also, `threshold > plus1v` from prior invariants)
// - `ten_kappa = 10^kappa * k`
// - `ulp = 2^-e * k`
fn round_and_weed(buf: &mut [u8], exp: i16, remainder: u64, threshold: u64, plus1v: u64,
ten_kappa: u64, ulp: u64) -> Option<(usize, i16)> {
assert!(!buf.is_empty());
// produce two approximations to `v` (actually `plus1 - v`) within 1.5 ulps.
// the resulting representation should be the closest representation to both.
//
// here `plus1 - v` is used since calculations are done with respect to `plus1`
// in order to avoid overflow/underflow (hence the seemingly swapped names).
let plus1v_down = plus1v + ulp; // plus1 - (v - 1 ulp)
let plus1v_up = plus1v - ulp; // plus1 - (v + 1 ulp)
// decrease the last digit and stop at the closest representation to `v + 1 ulp`.
let mut plus1w = remainder; // plus1w(n) = plus1 - w(n)
{
let last = buf.last_mut().unwrap();
// we work with the approximated digits `w(n)`, which is initially equal to `plus1 -
// plus1 % 10^kappa`. after running the loop body `n` times, `w(n) = plus1 -
// plus1 % 10^kappa - n * 10^kappa`. we set `plus1w(n) = plus1 - w(n) =
// plus1 % 10^kappa + n * 10^kappa` (thus `remainder = plus1w(0)`) to simplify checks.
// note that `plus1w(n)` is always increasing.
//
// we have three conditions to terminate. any of them will make the loop unable to
// proceed, but we then have at least one valid representation known to be closest to
// `v + 1 ulp` anyway. we will denote them as TC1 through TC3 for brevity.
//
// TC1: `w(n) <= v + 1 ulp`, i.e. this is the last repr that can be the closest one.
// this is equivalent to `plus1 - w(n) = plus1w(n) >= plus1 - (v + 1 ulp) = plus1v_up`.
// combined with TC2 (which checks if `w(n+1)` is valid), this prevents the possible
// overflow on the calculation of `plus1w(n)`.
//
// TC2: `w(n+1) < minus1`, i.e. the next repr definitely does not round to `v`.
// this is equivalent to `plus1 - w(n) + 10^kappa = plus1w(n) + 10^kappa >
// plus1 - minus1 = threshold`. the left hand side can overflow, but we know
// `threshold > plus1v`, so if TC1 is false, `threshold - plus1w(n) >
// threshold - (plus1v - 1 ulp) > 1 ulp` and we can safely test if
// `threshold - plus1w(n) < 10^kappa` instead.
//
// TC3: `abs(w(n) - (v + 1 ulp)) <= abs(w(n+1) - (v + 1 ulp))`, i.e. the next repr is
// no closer to `v + 1 ulp` than the current repr. given `z(n) = plus1v_up - plus1w(n)`,
// this becomes `abs(z(n)) <= abs(z(n+1))`. again assuming that TC1 is false, we have
// `z(n) > 0`. we have two cases to consider:
//
// - when `z(n+1) >= 0`: TC3 becomes `z(n) <= z(n+1)`. as `plus1w(n)` is increasing,
// `z(n)` should be decreasing and this is clearly false.
// - when `z(n+1) < 0`:
// - TC3a: the precondition is `plus1v_up < plus1w(n) + 10^kappa`. assuming TC2 is
// false, `threshold >= plus1w(n) + 10^kappa` so it cannot overflow.
// - TC3b: TC3 becomes `z(n) <= -z(n+1)`, i.e. `plus1v_up - plus1w(n) >=
// plus1w(n+1) - plus1v_up = plus1w(n) + 10^kappa - plus1v_up`. the negated TC1
// gives `plus1v_up > plus1w(n)`, so it cannot overflow or underflow when
// combined with TC3a.
//
// consequently, we should stop when `TC1 || TC2 || (TC3a && TC3b)`. the following is
// equal to its inverse, `!TC1 && !TC2 && (!TC3a || !TC3b)`.
while plus1w < plus1v_up &&
threshold - plus1w >= ten_kappa &&
(plus1w + ten_kappa < plus1v_up ||
plus1v_up - plus1w >= plus1w + ten_kappa - plus1v_up) {
*last -= 1;
debug_assert!(*last > b'0'); // the shortest repr cannot end with `0`
plus1w += ten_kappa;
}
}
// check if this representation is also the closest representation to `v - 1 ulp`.
//
// this is simply same to the terminating conditions for `v + 1 ulp`, with all `plus1v_up`
// replaced by `plus1v_down` instead. overflow analysis equally holds.
if plus1w < plus1v_down &&
threshold - plus1w >= ten_kappa &&
(plus1w + ten_kappa < plus1v_down ||
plus1v_down - plus1w >= plus1w + ten_kappa - plus1v_down) {
return None;
}
// now we have the closest representation to `v` between `plus1` and `minus1`.
// this is too liberal, though, so we reject any `w(n)` not between `plus0` and `minus0`,
// i.e. `plus1 - plus1w(n) <= minus0` or `plus1 - plus1w(n) >= plus0`. we utilize the facts
// that `threshold = plus1 - minus1` and `plus1 - plus0 = minus0 - minus1 = 2 ulp`.
if 2 * ulp <= plus1w && plus1w <= threshold - 4 * ulp {
Some((buf.len(), exp))
} else {
None
}
}
}
/// The shortest mode implementation for Grisu with Dragon fallback.
///
/// This should be used for most cases.
pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) {
use num::flt2dec::strategy::dragon::format_shortest as fallback;
match format_shortest_opt(d, buf) {
Some(ret) => ret,
None => fallback(d, buf),
}
}
/// The exact and fixed mode implementation for Grisu.
///
/// It returns `None` when it would return an inexact representation otherwise.
pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16)
-> Option<(/*#digits*/ usize, /*exp*/ i16)> {
assert!(d.mant > 0);
assert!(d.mant < (1 << 61)); // we need at least three bits of additional precision
assert!(!buf.is_empty());
// normalize and scale `v`.
let v = Fp { f: d.mant, e: d.exp }.normalize();
let (minusk, cached) = cached_power(ALPHA - v.e - 64, GAMMA - v.e - 64);
let v = v.mul(&cached);
// divide `v` into integral and fractional parts.
let e = -v.e as usize;
let vint = (v.f >> e) as u32;
let vfrac = v.f & ((1 << e) - 1);
// both old `v` and new `v` (scaled by `10^-k`) has an error of < 1 ulp (Theorem 5.1).
// as we don't know the error is positive or negative, we use two approximations
// spaced equally and have the maximal error of 2 ulps (same to the shortest case).
//
// the goal is to find the exactly rounded series of digits that are common to
// both `v - 1 ulp` and `v + 1 ulp`, so that we are maximally confident.
// if this is not possible, we don't know which one is the correct output for `v`,
// so we give up and fall back.
//
// `err` is defined as `1 ulp * 2^e` here (same to the ulp in `vfrac`),
// and we will scale it whenever `v` gets scaled.
let mut err = 1;
// calculate the largest `10^max_kappa` no more than `v` (thus `v < 10^(max_kappa+1)`).
// this is an upper bound of `kappa` below.
let (max_kappa, max_ten_kappa) = max_pow10_no_more_than(vint);
let mut i = 0;
let exp = max_kappa as i16 - minusk + 1;
// if we are working with the last-digit limitation, we need to shorten the buffer
// before the actual rendering in order to avoid double rounding.
// note that we have to enlarge the buffer again when rounding up happens!
let len = if exp <= limit {
// oops, we cannot even produce *one* digit.
// this is possible when, say, we've got something like 9.5 and it's being rounded to 10.
//
// in principle we can immediately call `possibly_round` with an empty buffer,
// but scaling `max_ten_kappa << e` by 10 can result in overflow.
// thus we are being sloppy here and widen the error range by a factor of 10.
// this will increase the false negative rate, but only very, *very* slightly;
// it can only matter noticably when the mantissa is bigger than 60 bits.
return possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e);
} else if ((exp as i32 - limit as i32) as usize) < buf.len() {
(exp - limit) as usize
} else {
buf.len()
};
debug_assert!(len > 0);
// render integral parts.
// the error is entirely fractional, so we don't need to check it in this part.
let mut kappa = max_kappa as i16;
let mut ten_kappa = max_ten_kappa; // 10^kappa
let mut remainder = vint; // digits yet to be rendered
loop { // we always have at least one digit to render
// invariants:
// - `remainder < 10^(kappa+1)`
// - `vint = d[0..n-1] * 10^(kappa+1) + remainder`
// (it follows that `remainder = vint % 10^(kappa+1)`)
// divide `remainder` by `10^kappa`. both are scaled by `2^-e`.
let q = remainder / ten_kappa;
let r = remainder % ten_kappa;
debug_assert!(q < 10);
buf[i] = b'0' + q as u8;
i += 1;
// is the buffer full? run the rounding pass with the remainder.
if i == len {
let vrem = ((r as u64) << e) + vfrac; // == (v % 10^kappa) * 2^e
return possibly_round(buf, len, exp, limit, vrem, (ten_kappa as u64) << e, err << e);
}
// break the loop when we have rendered all integral digits.
// the exact number of digits is `max_kappa + 1` as `plus1 < 10^(max_kappa+1)`.
if i > max_kappa as usize {
debug_assert_eq!(ten_kappa, 1);
debug_assert_eq!(kappa, 0);
break;
}
// restore invariants
kappa -= 1;
ten_kappa /= 10;
remainder = r;
}
// render fractional parts.
//
// in principle we can continue to the last available digit and check for the accuracy.
// unfortunately we are working with the finite-sized integers, so we need some criterion
// to detect the overflow. V8 uses `remainder > err`, which becomes false when
// the first `i` significant digits of `v - 1 ulp` and `v` differ. however this rejects
// too many otherwise valid input.
//
// since the later phase has a correct overflow detection, we instead use tighter criterion:
// we continue til `err` exceeds `10^kappa / 2`, so that the range between `v - 1 ulp` and
// `v + 1 ulp` definitely contains two or more rounded representations. this is same to
// the first two comparisons from `possibly_round`, for the reference.
let mut remainder = vfrac;
let maxerr = 1 << (e - 1);
while err < maxerr {
// invariants, where `m = max_kappa + 1` (# of digits in the integral part):
// - `remainder < 2^e`
// - `vfrac * 10^(n-m) = d[m..n-1] * 2^e + remainder`
// - `err = 10^(n-m)`
remainder *= 10; // won't overflow, `2^e * 10 < 2^64`
err *= 10; // won't overflow, `err * 10 < 2^e * 5 < 2^64`
// divide `remainder` by `10^kappa`.
// both are scaled by `2^e / 10^kappa`, so the latter is implicit here.
let q = remainder >> e;
let r = remainder & ((1 << e) - 1);
debug_assert!(q < 10);
buf[i] = b'0' + q as u8;
i += 1;
// is the buffer full? run the rounding pass with the remainder.
if i == len {
return possibly_round(buf, len, exp, limit, r, 1 << e, err);
}
// restore invariants
remainder = r;
}
// further calculation is useless (`possibly_round` definitely fails), so we give up.
return None;
// we've generated all requested digits of `v`, which should be also same to corresponding
// digits of `v - 1 ulp`. now we check if there is a unique representation shared by
// both `v - 1 ulp` and `v + 1 ulp`; this can be either same to generated digits, or
// to the rounded-up version of those digits. if the range contains multiple representations
// of the same length, we cannot be sure and should return `None` instead.
//
// all arguments here are scaled by the common (but implicit) value `k`, so that:
// - `remainder = (v % 10^kappa) * k`
// - `ten_kappa = 10^kappa * k`
// - `ulp = 2^-e * k`
fn possibly_round(buf: &mut [u8], mut len: usize, mut exp: i16, limit: i16,
remainder: u64, ten_kappa: u64, ulp: u64) -> Option<(usize, i16)> {
debug_assert!(remainder < ten_kappa);
// 10^kappa
// : : :<->: :
// : : : : :
// :|1 ulp|1 ulp| :
// :|<--->|<--->| :
// ----|-----|-----|----
// | v |
// v - 1 ulp v + 1 ulp
//
// (for the reference, the dotted line indicates the exact value for
// possible representations in given number of digits.)
//
// error is too large that there are at least three possible representations
// between `v - 1 ulp` and `v + 1 ulp`. we cannot determine which one is correct.
if ulp >= ten_kappa { return None; }
// 10^kappa
// :<------->:
// : :
// : |1 ulp|1 ulp|
// : |<--->|<--->|
// ----|-----|-----|----
// | v |
// v - 1 ulp v + 1 ulp
//
// in fact, 1/2 ulp is enough to introduce two possible representations.
// (remember that we need a unique representation for both `v - 1 ulp` and `v + 1 ulp`.)
// this won't overflow, as `ulp < ten_kappa` from the first check.
if ten_kappa - ulp <= ulp { return None; }
// remainder
// :<->| :
// : | :
// :<--------- 10^kappa ---------->:
// | : | :
// |1 ulp|1 ulp| :
// |<--->|<--->| :
// ----|-----|-----|------------------------
// | v |
// v - 1 ulp v + 1 ulp
//
// if `v + 1 ulp` is closer to the rounded-down representation (which is already in `buf`),
// then we can safely return. note that `v - 1 ulp` *can* be less than the current
// representation, but as `1 ulp < 10^kappa / 2`, this condition is enough:
// the distance between `v - 1 ulp` and the current representation
// cannot exceed `10^kappa / 2`.
//
// the condition equals to `remainder + ulp < 10^kappa / 2`.
// since this can easily overflow, first check if `remainder < 10^kappa / 2`.
// we've already verified that `ulp < 10^kappa / 2`, so as long as
// `10^kappa` did not overflow after all, the second check is fine.
if ten_kappa - remainder > remainder && ten_kappa - 2 * remainder >= 2 * ulp {
return Some((len, exp));
}
// :<------- remainder ------>| :
// : | :
// :<--------- 10^kappa --------->:
// : | | : |
// : |1 ulp|1 ulp|
// : |<--->|<--->|
// -----------------------|-----|-----|-----
// | v |
// v - 1 ulp v + 1 ulp
//
// on the other hands, if `v - 1 ulp` is closer to the rounded-up representation,
// we should round up and return. for the same reason we don't need to check `v + 1 ulp`.
//
// the condition equals to `remainder - ulp >= 10^kappa / 2`.
// again we first check if `remainder > ulp` (note that this is not `remainder >= ulp`,
// as `10^kappa` is never zero). also note that `remainder - ulp <= 10^kappa`,
// so the second check does not overflow.
if remainder > ulp && ten_kappa - (remainder - ulp) <= remainder - ulp {
if let Some(c) = round_up(buf, len) {
// only add an additional digit when we've been requested the fixed precision.
// we also need to check that, if the original buffer was empty,
// the additional digit can only be added when `exp == limit` (edge case).
exp += 1;
if exp > limit && len < buf.len() {
buf[len] = c;
len += 1;
}
}
return Some((len, exp));
}
// otherwise we are doomed (i.e. some values between `v - 1 ulp` and `v + 1 ulp` are
// rounding down and others are rounding up) and give up.
None
}
}
/// The exact and fixed mode implementation for Grisu with Dragon fallback.
///
/// This should be used for most cases.
pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) {
use num::flt2dec::strategy::dragon::format_exact as fallback;
match format_exact_opt(d, buf, limit) {
Some(ret) => ret,
None => fallback(d, buf, limit),
}
}

View File

@ -44,6 +44,9 @@ pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
#[unstable(feature = "core", reason = "may be removed or relocated")]
pub mod wrapping;
#[unstable(feature = "core", reason = "internal routines only exposed for testing")]
pub mod flt2dec;
/// Types that have a "zero" value.
///
/// This trait is intended for use in conjunction with `Add`, as an identity:

View File

@ -30,6 +30,7 @@ extern crate core;
extern crate test;
extern crate libc;
extern crate rustc_unicode;
extern crate rand;
mod any;
mod atomic;

View File

@ -0,0 +1,160 @@
// 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::prelude::v1::*;
use core::num::flt2dec::bignum::tests::Big8x3 as Big;
#[test]
#[should_panic]
fn test_from_u64_overflow() {
Big::from_u64(0x1000000);
}
#[test]
fn test_add() {
assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7));
assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3));
assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3));
assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001));
assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665));
assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665));
}
#[test]
#[should_panic]
fn test_add_overflow_1() {
Big::from_small(1).add(&Big::from_u64(0xffffff));
}
#[test]
#[should_panic]
fn test_add_overflow_2() {
Big::from_u64(0xffffff).add(&Big::from_small(1));
}
#[test]
fn test_sub() {
assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3));
assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc));
assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789));
assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1));
assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0));
}
#[test]
#[should_panic]
fn test_sub_underflow_1() {
Big::from_u64(0x10665).sub(&Big::from_u64(0x10666));
}
#[test]
#[should_panic]
fn test_sub_underflow_2() {
Big::from_small(0).sub(&Big::from_u64(0x123456));
}
#[test]
fn test_mul_small() {
assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35));
assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01));
assert_eq!(*Big::from_u64(0xffffff/13).mul_small(13), Big::from_u64(0xffffff));
}
#[test]
#[should_panic]
fn test_mul_small_overflow() {
Big::from_u64(0x800000).mul_small(2);
}
#[test]
fn test_mul_pow2() {
assert_eq!(*Big::from_small(0x7).mul_pow2(4), Big::from_small(0x70));
assert_eq!(*Big::from_small(0xff).mul_pow2(1), Big::from_u64(0x1fe));
assert_eq!(*Big::from_small(0xff).mul_pow2(12), Big::from_u64(0xff000));
assert_eq!(*Big::from_small(0x1).mul_pow2(23), Big::from_u64(0x800000));
assert_eq!(*Big::from_u64(0x123).mul_pow2(0), Big::from_u64(0x123));
assert_eq!(*Big::from_u64(0x123).mul_pow2(7), Big::from_u64(0x9180));
assert_eq!(*Big::from_u64(0x123).mul_pow2(15), Big::from_u64(0x918000));
assert_eq!(*Big::from_small(0).mul_pow2(23), Big::from_small(0));
}
#[test]
#[should_panic]
fn test_mul_pow2_overflow_1() {
Big::from_u64(0x1).mul_pow2(24);
}
#[test]
#[should_panic]
fn test_mul_pow2_overflow_2() {
Big::from_u64(0x123).mul_pow2(16);
}
#[test]
fn test_mul_digits() {
assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15));
assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01));
assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2));
assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3));
assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e));
assert_eq!(*Big::from_u64(0xffffff/13).mul_digits(&[13]), Big::from_u64(0xffffff));
assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff));
}
#[test]
#[should_panic]
fn test_mul_digits_overflow_1() {
Big::from_u64(0x800000).mul_digits(&[2]);
}
#[test]
#[should_panic]
fn test_mul_digits_overflow_2() {
Big::from_u64(0x1000).mul_digits(&[0, 0x10]);
}
#[test]
fn test_div_rem_small() {
let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r);
assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0));
assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15));
assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3));
assert_eq!(as_val(Big::from_u64(0xffffff).div_rem_small(123)),
(Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8));
assert_eq!(as_val(Big::from_u64(0x10000).div_rem_small(123)),
(Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8));
}
#[test]
fn test_is_zero() {
assert!(Big::from_small(0).is_zero());
assert!(!Big::from_small(3).is_zero());
assert!(!Big::from_u64(0x123).is_zero());
assert!(!Big::from_u64(0xffffff).sub(&Big::from_u64(0xfffffe)).is_zero());
assert!(Big::from_u64(0xffffff).sub(&Big::from_u64(0xffffff)).is_zero());
}
#[test]
fn test_ord() {
assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
assert!(Big::from_u64(0x102) < Big::from_u64(0x201));
}
#[test]
fn test_fmt() {
assert_eq!(format!("{:?}", Big::from_u64(0)), "0x0");
assert_eq!(format!("{:?}", Big::from_u64(0x1)), "0x1");
assert_eq!(format!("{:?}", Big::from_u64(0x12)), "0x12");
assert_eq!(format!("{:?}", Big::from_u64(0x123)), "0x1_23");
assert_eq!(format!("{:?}", Big::from_u64(0x1234)), "0x12_34");
assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45");
assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56");
}

View File

@ -0,0 +1,61 @@
// 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::num::Float;
use core::num::flt2dec::estimator::*;
#[test]
fn test_estimate_scaling_factor() {
macro_rules! assert_almost_eq {
($actual:expr, $expected:expr) => ({
let actual = $actual;
let expected = $expected;
println!("{} - {} = {} - {} = {}", stringify!($expected), stringify!($actual),
expected, actual, expected - actual);
assert!(expected == actual || expected == actual + 1,
"expected {}, actual {}", expected, actual);
})
}
assert_almost_eq!(estimate_scaling_factor(1, 0), 0);
assert_almost_eq!(estimate_scaling_factor(2, 0), 1);
assert_almost_eq!(estimate_scaling_factor(10, 0), 1);
assert_almost_eq!(estimate_scaling_factor(11, 0), 2);
assert_almost_eq!(estimate_scaling_factor(100, 0), 2);
assert_almost_eq!(estimate_scaling_factor(101, 0), 3);
assert_almost_eq!(estimate_scaling_factor(10000000000000000000, 0), 19);
assert_almost_eq!(estimate_scaling_factor(10000000000000000001, 0), 20);
// 1/2^20 = 0.00000095367...
assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000, -20), -6);
assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000 + 1, -20), -5);
assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000, -20), -5);
assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000 + 1, -20), -4);
assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000, -20), -4);
assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000 + 1, -20), -3);
assert_almost_eq!(estimate_scaling_factor(1048575, -20), 0);
assert_almost_eq!(estimate_scaling_factor(1048576, -20), 0);
assert_almost_eq!(estimate_scaling_factor(1048577, -20), 1);
assert_almost_eq!(estimate_scaling_factor(10485759999999999999, -20), 13);
assert_almost_eq!(estimate_scaling_factor(10485760000000000000, -20), 13);
assert_almost_eq!(estimate_scaling_factor(10485760000000000001, -20), 14);
// extreme values:
// 2^-1074 = 4.94065... * 10^-324
// (2^53-1) * 2^971 = 1.79763... * 10^308
assert_almost_eq!(estimate_scaling_factor(1, -1074), -323);
assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309);
for i in -1074..972 {
let expected = Float::ldexp(1.0, i).log10().ceil();
assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
// 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::prelude::v1::*;
use std::{i16, f64};
use super::super::*;
use core::num::flt2dec::*;
use core::num::flt2dec::bignum::Big32x36 as Big;
use core::num::flt2dec::strategy::dragon::*;
#[test]
fn test_mul_pow10() {
let mut prevpow10 = Big::from_small(1);
for i in 1..340 {
let mut curpow10 = Big::from_small(1);
mul_pow10(&mut curpow10, i);
assert_eq!(curpow10, *prevpow10.clone().mul_small(10));
prevpow10 = curpow10;
}
}
#[test]
fn shortest_sanity_test() {
f64_shortest_sanity_test(format_shortest);
f32_shortest_sanity_test(format_shortest);
more_shortest_sanity_test(format_shortest);
}
#[test]
fn exact_sanity_test() {
f64_exact_sanity_test(format_exact);
f32_exact_sanity_test(format_exact);
}
#[bench]
fn bench_small_shortest(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; MAX_SIG_DIGITS];
b.iter(|| format_shortest(&decoded, &mut buf));
}
#[bench]
fn bench_big_shortest(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; MAX_SIG_DIGITS];
b.iter(|| format_shortest(&decoded, &mut buf));
}
#[bench]
fn bench_small_exact_3(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; 3];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_big_exact_3(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; 3];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_small_exact_12(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; 12];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_big_exact_12(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; 12];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_small_exact_inf(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; 1024];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_big_exact_inf(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; 1024];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[test]
fn test_to_shortest_str() {
to_shortest_str_test(format_shortest);
}
#[test]
fn test_to_shortest_exp_str() {
to_shortest_exp_str_test(format_shortest);
}
#[test]
fn test_to_exact_exp_str() {
to_exact_exp_str_test(format_exact);
}
#[test]
fn test_to_exact_fixed_str() {
to_exact_fixed_str_test(format_exact);
}

View File

@ -0,0 +1,177 @@
// 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::{i16, f64};
use super::super::*;
use core::num::flt2dec::*;
use core::num::flt2dec::strategy::grisu::*;
#[test]
fn test_cached_power() {
assert_eq!(CACHED_POW10.first().unwrap().1, CACHED_POW10_FIRST_E);
assert_eq!(CACHED_POW10.last().unwrap().1, CACHED_POW10_LAST_E);
for e in -1137..961 { // full range for f64
let low = ALPHA - e - 64;
let high = GAMMA - e - 64;
let (_k, cached) = cached_power(low, high);
assert!(low <= cached.e && cached.e <= high,
"cached_power({}, {}) = {:?} is incorrect", low, high, cached);
}
}
#[test]
fn test_max_pow10_no_more_than() {
let mut prevtenk = 1;
for k in 1..10 {
let tenk = prevtenk * 10;
assert_eq!(max_pow10_no_more_than(tenk - 1), (k - 1, prevtenk));
assert_eq!(max_pow10_no_more_than(tenk), (k, tenk));
prevtenk = tenk;
}
}
#[test]
fn shortest_sanity_test() {
f64_shortest_sanity_test(format_shortest);
f32_shortest_sanity_test(format_shortest);
more_shortest_sanity_test(format_shortest);
}
#[test]
fn shortest_random_equivalence_test() {
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
}
#[test] #[ignore] // it is too expensive
fn shortest_f32_exhaustive_equivalence_test() {
// it is hard to directly test the optimality of the output, but we can at least test if
// two different algorithms agree to each other.
//
// this reports the progress and the number of f32 values returned `None`.
// with `--nocapture` (and plenty of time and appropriate rustc flags), this should print:
// `done, ignored=17643160 passed=2121451879 failed=0`.
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
}
#[test] #[ignore] // is is too expensive
fn shortest_f64_hard_random_equivalence_test() {
// this again probably has to use appropriate rustc flags.
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
f64_random_equivalence_test(format_shortest_opt, fallback,
MAX_SIG_DIGITS, 100_000_000);
}
#[test]
fn exact_sanity_test() {
f64_exact_sanity_test(format_exact);
f32_exact_sanity_test(format_exact);
}
#[test]
fn exact_f32_random_equivalence_test() {
use core::num::flt2dec::strategy::dragon::format_exact as fallback;
for k in 1..21 {
f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
|d, buf| fallback(d, buf, i16::MIN), k, 1_000);
}
}
#[test]
fn exact_f64_random_equivalence_test() {
use core::num::flt2dec::strategy::dragon::format_exact as fallback;
for k in 1..21 {
f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
|d, buf| fallback(d, buf, i16::MIN), k, 1_000);
}
}
#[bench]
fn bench_small_shortest(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; MAX_SIG_DIGITS];
b.iter(|| format_shortest(&decoded, &mut buf));
}
#[bench]
fn bench_big_shortest(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; MAX_SIG_DIGITS];
b.iter(|| format_shortest(&decoded, &mut buf));
}
#[bench]
fn bench_small_exact_3(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; 3];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_big_exact_3(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; 3];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_small_exact_12(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; 12];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_big_exact_12(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; 12];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_small_exact_inf(b: &mut Bencher) {
let decoded = decode_finite(3.141592f64);
let mut buf = [0; 1024];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[bench]
fn bench_big_exact_inf(b: &mut Bencher) {
let decoded = decode_finite(f64::MAX);
let mut buf = [0; 1024];
b.iter(|| format_exact(&decoded, &mut buf, i16::MIN));
}
#[test]
fn test_to_shortest_str() {
to_shortest_str_test(format_shortest);
}
#[test]
fn test_to_shortest_exp_str() {
to_shortest_exp_str_test(format_shortest);
}
#[test]
fn test_to_exact_exp_str() {
to_exact_exp_str_test(format_exact);
}
#[test]
fn test_to_exact_fixed_str() {
to_exact_fixed_str_test(format_exact);
}

View File

@ -29,6 +29,8 @@ mod u16;
mod u32;
mod u64;
mod flt2dec;
/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T) where
T: PartialEq