Format libcore with rustfmt
This commit applies rustfmt with default settings to files in src/libcore *that are not involved in any currently open PR* to minimize merge conflicts. The list of files involved in open PRs was determined by querying GitHub's GraphQL API with this script: https://gist.github.com/dtolnay/aa9c34993dc051a4f344d1b10e4487e8 With the list of files from the script in `outstanding_files`, the relevant commands were: $ find src/libcore -name '*.rs' | xargs rustfmt --edition=2018 $ rg libcore outstanding_files | xargs git checkout -- Repeating this process several months apart should get us coverage of most of the rest of libcore.
This commit is contained in:
@@ -12,13 +12,15 @@
|
||||
// This module is only for dec2flt and flt2dec, and only public because of coretests.
|
||||
// It is not intended to ever be stabilized.
|
||||
#![doc(hidden)]
|
||||
#![unstable(feature = "core_private_bignum",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0")]
|
||||
#![unstable(
|
||||
feature = "core_private_bignum",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0"
|
||||
)]
|
||||
#![macro_use]
|
||||
|
||||
use crate::mem;
|
||||
use crate::intrinsics;
|
||||
use crate::mem;
|
||||
|
||||
/// Arithmetic operations required by bignums.
|
||||
pub trait FullOps: Sized {
|
||||
@@ -36,10 +38,8 @@ pub trait FullOps: Sized {
|
||||
|
||||
/// 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 */);
|
||||
fn full_div_rem(self, other: Self, borrow: Self)
|
||||
-> (Self /* quotient */, Self /* remainder */);
|
||||
}
|
||||
|
||||
macro_rules! impl_full_ops {
|
||||
@@ -98,7 +98,7 @@ impl_full_ops! {
|
||||
const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)];
|
||||
|
||||
macro_rules! define_bignum {
|
||||
($name:ident: type=$ty:ty, n=$n:expr) => (
|
||||
($name:ident: type=$ty:ty, n=$n:expr) => {
|
||||
/// Stack-allocated arbitrary-precision (up to certain limit) integer.
|
||||
///
|
||||
/// This is backed by a fixed-size array of given type ("digit").
|
||||
@@ -115,7 +115,7 @@ macro_rules! define_bignum {
|
||||
size: usize,
|
||||
/// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...`
|
||||
/// where `W` is the number of bits in the digit type.
|
||||
base: [$ty; $n]
|
||||
base: [$ty; $n],
|
||||
}
|
||||
|
||||
impl $name {
|
||||
@@ -180,7 +180,7 @@ macro_rules! define_bignum {
|
||||
}
|
||||
// This could be optimized with leading_zeros() and bit shifts, but that's
|
||||
// probably not worth the hassle.
|
||||
let digitbits = mem::size_of::<$ty>()* 8;
|
||||
let digitbits = mem::size_of::<$ty>() * 8;
|
||||
let mut i = nonzero.len() * digitbits - 1;
|
||||
while self.get_bit(i) == 0 {
|
||||
i -= 1;
|
||||
@@ -272,12 +272,12 @@ macro_rules! define_bignum {
|
||||
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);
|
||||
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];
|
||||
self.base[i + digits] = self.base[i];
|
||||
}
|
||||
for i in 0..digits {
|
||||
self.base[i] = 0;
|
||||
@@ -287,14 +287,14 @@ macro_rules! define_bignum {
|
||||
let mut sz = self.size + digits;
|
||||
if bits > 0 {
|
||||
let last = sz;
|
||||
let overflow = self.base[last-1] >> (digitbits - bits);
|
||||
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));
|
||||
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
|
||||
@@ -331,7 +331,6 @@ macro_rules! define_bignum {
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
/// Multiplies itself by a number described by `other[0] + other[1] * 2^W +
|
||||
/// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type)
|
||||
/// and returns its own mutable reference.
|
||||
@@ -342,7 +341,9 @@ macro_rules! define_bignum {
|
||||
|
||||
let mut retsz = 0;
|
||||
for (i, &a) in aa.iter().enumerate() {
|
||||
if a == 0 { continue; }
|
||||
if a == 0 {
|
||||
continue;
|
||||
}
|
||||
let mut sz = bb.len();
|
||||
let mut carry = 0;
|
||||
for (j, &b) in bb.iter().enumerate() {
|
||||
@@ -430,11 +431,12 @@ macro_rules! define_bignum {
|
||||
}
|
||||
|
||||
impl crate::cmp::PartialEq for $name {
|
||||
fn eq(&self, other: &$name) -> bool { self.base[..] == other.base[..] }
|
||||
fn eq(&self, other: &$name) -> bool {
|
||||
self.base[..] == other.base[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::cmp::Eq for $name {
|
||||
}
|
||||
impl crate::cmp::Eq for $name {}
|
||||
|
||||
impl crate::cmp::PartialOrd for $name {
|
||||
fn partial_cmp(&self, other: &$name) -> crate::option::Option<crate::cmp::Ordering> {
|
||||
@@ -462,17 +464,17 @@ macro_rules! define_bignum {
|
||||
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
|
||||
use crate::mem;
|
||||
|
||||
let sz = if self.size < 1 {1} else {self.size};
|
||||
let sz = if self.size < 1 { 1 } else { self.size };
|
||||
let digitlen = mem::size_of::<$ty>() * 2;
|
||||
|
||||
write!(f, "{:#x}", self.base[sz-1])?;
|
||||
for &v in self.base[..sz-1].iter().rev() {
|
||||
write!(f, "{:#x}", self.base[sz - 1])?;
|
||||
for &v in self.base[..sz - 1].iter().rev() {
|
||||
write!(f, "_{:01$x}", v, digitlen)?;
|
||||
}
|
||||
crate::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/// The digit type for `Big32x40`.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
//! The various algorithms from the paper.
|
||||
|
||||
use crate::cmp::min;
|
||||
use crate::cmp::Ordering::{Less, Equal, Greater};
|
||||
use crate::num::diy_float::Fp;
|
||||
use crate::num::dec2flt::table;
|
||||
use crate::num::dec2flt::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float};
|
||||
use crate::cmp::Ordering::{Equal, Greater, Less};
|
||||
use crate::num::dec2flt::num::{self, Big};
|
||||
use crate::num::dec2flt::rawfp::{self, fp_to_float, next_float, prev_float, RawFloat, Unpacked};
|
||||
use crate::num::dec2flt::table;
|
||||
use crate::num::diy_float::Fp;
|
||||
|
||||
/// Number of significand bits in Fp
|
||||
const P: u32 = 64;
|
||||
@@ -23,9 +23,9 @@ fn power_of_ten(e: i16) -> Fp {
|
||||
|
||||
// In most architectures, floating point operations have an explicit bit size, therefore the
|
||||
// precision of the computation is determined on a per-operation basis.
|
||||
#[cfg(any(not(target_arch="x86"), target_feature="sse2"))]
|
||||
#[cfg(any(not(target_arch = "x86"), target_feature = "sse2"))]
|
||||
mod fpu_precision {
|
||||
pub fn set_precision<T>() { }
|
||||
pub fn set_precision<T>() {}
|
||||
}
|
||||
|
||||
// On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available.
|
||||
@@ -33,7 +33,7 @@ mod fpu_precision {
|
||||
// round to 80 bits causing double rounding to happen when values are eventually represented as
|
||||
// 32/64 bit float values. To overcome this, the FPU control word can be set so that the
|
||||
// computations are performed in the desired precision.
|
||||
#[cfg(all(target_arch="x86", not(target_feature="sse2")))]
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
mod fpu_precision {
|
||||
use crate::mem::size_of;
|
||||
|
||||
|
||||
@@ -78,23 +78,25 @@
|
||||
//! turned into {positive,negative} {zero,infinity}.
|
||||
|
||||
#![doc(hidden)]
|
||||
#![unstable(feature = "dec2flt",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0")]
|
||||
#![unstable(
|
||||
feature = "dec2flt",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0"
|
||||
)]
|
||||
|
||||
use crate::fmt;
|
||||
use crate::str::FromStr;
|
||||
|
||||
use self::parse::{parse_decimal, Decimal, Sign, ParseResult};
|
||||
use self::num::digits_to_big;
|
||||
use self::parse::{parse_decimal, Decimal, ParseResult, Sign};
|
||||
use self::rawfp::RawFloat;
|
||||
|
||||
mod algorithm;
|
||||
mod table;
|
||||
mod num;
|
||||
mod table;
|
||||
// These two have their own tests.
|
||||
pub mod rawfp;
|
||||
pub mod parse;
|
||||
pub mod rawfp;
|
||||
|
||||
macro_rules! from_str_float_impl {
|
||||
($t:ty) => {
|
||||
@@ -155,7 +157,7 @@ macro_rules! from_str_float_impl {
|
||||
dec2flt(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
from_str_float_impl!(f32);
|
||||
from_str_float_impl!(f64);
|
||||
@@ -171,7 +173,7 @@ from_str_float_impl!(f64);
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct ParseFloatError {
|
||||
kind: FloatErrorKind
|
||||
kind: FloatErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -181,10 +183,12 @@ enum FloatErrorKind {
|
||||
}
|
||||
|
||||
impl ParseFloatError {
|
||||
#[unstable(feature = "int_error_internals",
|
||||
reason = "available through Error trait and this method should \
|
||||
not be exposed publicly",
|
||||
issue = "0")]
|
||||
#[unstable(
|
||||
feature = "int_error_internals",
|
||||
reason = "available through Error trait and this method should \
|
||||
not be exposed publicly",
|
||||
issue = "0"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub fn __description(&self) -> &str {
|
||||
match self.kind {
|
||||
@@ -222,7 +226,7 @@ fn extract_sign(s: &str) -> (Sign, &str) {
|
||||
/// Converts a decimal string into a floating point number.
|
||||
fn dec2flt<T: RawFloat>(s: &str) -> Result<T, ParseFloatError> {
|
||||
if s.is_empty() {
|
||||
return Err(pfe_empty())
|
||||
return Err(pfe_empty());
|
||||
}
|
||||
let (sign, s) = extract_sign(s);
|
||||
let flt = match parse_decimal(s) {
|
||||
@@ -232,8 +236,10 @@ fn dec2flt<T: RawFloat>(s: &str) -> Result<T, ParseFloatError> {
|
||||
ParseResult::Invalid => match s {
|
||||
"inf" => T::INFINITY,
|
||||
"NaN" => T::NAN,
|
||||
_ => { return Err(pfe_invalid()); }
|
||||
}
|
||||
_ => {
|
||||
return Err(pfe_invalid());
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match sign {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// FIXME This module's name is a bit unfortunate, since other modules also import `core::num`.
|
||||
|
||||
use crate::cmp::Ordering::{self, Less, Equal, Greater};
|
||||
use crate::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
|
||||
pub use crate::num::bignum::Big32x40 as Big;
|
||||
|
||||
@@ -36,7 +36,10 @@ pub fn compare_with_half_ulp(f: &Big, ones_place: usize) -> Ordering {
|
||||
/// 1. using `FromStr` on `&[u8]` requires `from_utf8_unchecked`, which is bad, and
|
||||
/// 2. piecing together the results of `integral.parse()` and `fractional.parse()` is
|
||||
/// more complicated than this entire function.
|
||||
pub fn from_str_unchecked<'a, T>(bytes: T) -> u64 where T : IntoIterator<Item=&'a u8> {
|
||||
pub fn from_str_unchecked<'a, T>(bytes: T) -> u64
|
||||
where
|
||||
T: IntoIterator<Item = &'a u8>,
|
||||
{
|
||||
let mut result = 0;
|
||||
for &c in bytes {
|
||||
result = result * 10 + (c - b'0') as u64;
|
||||
@@ -61,14 +64,9 @@ pub fn digits_to_big(integral: &[u8], fractional: &[u8]) -> Big {
|
||||
pub fn to_u64(x: &Big) -> u64 {
|
||||
assert!(x.bit_length() < 64);
|
||||
let d = x.digits();
|
||||
if d.len() < 2 {
|
||||
d[0] as u64
|
||||
} else {
|
||||
(d[1] as u64) << 32 | d[0] as u64
|
||||
}
|
||||
if d.len() < 2 { d[0] as u64 } else { (d[1] as u64) << 32 | d[0] as u64 }
|
||||
}
|
||||
|
||||
|
||||
/// Extracts a range of bits.
|
||||
|
||||
/// Index 0 is the least significant bit and the range is half-open as usual.
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
//! modules rely on to not panic (or overflow) in turn.
|
||||
//! To make matters worse, all that happens in a single pass over the input.
|
||||
//! So, be careful when modifying anything, and double-check with the other modules.
|
||||
use self::ParseResult::{Invalid, ShortcutToInf, ShortcutToZero, Valid};
|
||||
use super::num;
|
||||
use self::ParseResult::{Valid, ShortcutToInf, ShortcutToZero, Invalid};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Sign {
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
//! Many functions in this module only handle normal numbers. The dec2flt routines conservatively
|
||||
//! take the universally-correct slow path (Algorithm M) for very small and very large numbers.
|
||||
//! That algorithm needs only next_float() which does handle subnormals and zeros.
|
||||
use crate::cmp::Ordering::{Less, Equal, Greater};
|
||||
use crate::cmp::Ordering::{Equal, Greater, Less};
|
||||
use crate::convert::{TryFrom, TryInto};
|
||||
use crate::ops::{Add, Mul, Div, Neg};
|
||||
use crate::fmt::{Debug, LowerExp};
|
||||
use crate::num::diy_float::Fp;
|
||||
use crate::num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
|
||||
use crate::num::FpCategory;
|
||||
use crate::num::dec2flt::num::{self, Big};
|
||||
use crate::num::dec2flt::table;
|
||||
use crate::num::diy_float::Fp;
|
||||
use crate::num::FpCategory;
|
||||
use crate::num::FpCategory::{Infinite, Nan, Normal, Subnormal, Zero};
|
||||
use crate::ops::{Add, Div, Mul, Neg};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Unpacked {
|
||||
@@ -44,13 +44,8 @@ impl Unpacked {
|
||||
/// See the parent module's doc comment for why this is necessary.
|
||||
///
|
||||
/// Should **never ever** be implemented for other types or be used outside the dec2flt module.
|
||||
pub trait RawFloat
|
||||
: Copy
|
||||
+ Debug
|
||||
+ LowerExp
|
||||
+ Mul<Output=Self>
|
||||
+ Div<Output=Self>
|
||||
+ Neg<Output=Self>
|
||||
pub trait RawFloat:
|
||||
Copy + Debug + LowerExp + Mul<Output = Self> + Div<Output = Self> + Neg<Output = Self>
|
||||
{
|
||||
const INFINITY: Self;
|
||||
const NAN: Self;
|
||||
@@ -144,7 +139,7 @@ macro_rules! other_constants {
|
||||
const INFINITY: Self = $crate::$type::INFINITY;
|
||||
const NAN: Self = $crate::$type::NAN;
|
||||
const ZERO: Self = 0.0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl RawFloat for f32 {
|
||||
@@ -163,11 +158,8 @@ impl RawFloat for f32 {
|
||||
let bits = self.to_bits();
|
||||
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
|
||||
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
||||
let mantissa = if exponent == 0 {
|
||||
(bits & 0x7fffff) << 1
|
||||
} else {
|
||||
(bits & 0x7fffff) | 0x800000
|
||||
};
|
||||
let mantissa =
|
||||
if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 };
|
||||
// Exponent bias + mantissa shift
|
||||
exponent -= 127 + 23;
|
||||
(mantissa as u64, exponent, sign)
|
||||
@@ -188,12 +180,17 @@ impl RawFloat for f32 {
|
||||
table::F32_SHORT_POWERS[e]
|
||||
}
|
||||
|
||||
fn classify(self) -> FpCategory { self.classify() }
|
||||
fn to_bits(self) -> Self::Bits { self.to_bits() }
|
||||
fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) }
|
||||
fn classify(self) -> FpCategory {
|
||||
self.classify()
|
||||
}
|
||||
fn to_bits(self) -> Self::Bits {
|
||||
self.to_bits()
|
||||
}
|
||||
fn from_bits(v: Self::Bits) -> Self {
|
||||
Self::from_bits(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl RawFloat for f64 {
|
||||
type Bits = u64;
|
||||
|
||||
@@ -235,9 +232,15 @@ impl RawFloat for f64 {
|
||||
table::F64_SHORT_POWERS[e]
|
||||
}
|
||||
|
||||
fn classify(self) -> FpCategory { self.classify() }
|
||||
fn to_bits(self) -> Self::Bits { self.to_bits() }
|
||||
fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) }
|
||||
fn classify(self) -> FpCategory {
|
||||
self.classify()
|
||||
}
|
||||
fn to_bits(self) -> Self::Bits {
|
||||
self.to_bits()
|
||||
}
|
||||
fn from_bits(v: Self::Bits) -> Self {
|
||||
Self::from_bits(v)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an `Fp` to the closest machine float type.
|
||||
@@ -248,7 +251,7 @@ pub fn fp_to_float<T: RawFloat>(x: Fp) -> T {
|
||||
let e = x.e + 63;
|
||||
if e > T::MAX_EXP {
|
||||
panic!("fp_to_float: exponent {} too large", e)
|
||||
} else if e > T::MIN_EXP {
|
||||
} else if e > T::MIN_EXP {
|
||||
encode_normal(round_normal::<T>(x))
|
||||
} else {
|
||||
panic!("fp_to_float: exponent {} too small", e)
|
||||
@@ -278,14 +281,15 @@ pub fn round_normal<T: RawFloat>(x: Fp) -> Unpacked {
|
||||
/// Inverse of `RawFloat::unpack()` for normalized numbers.
|
||||
/// Panics if the significand or exponent are not valid for normalized numbers.
|
||||
pub fn encode_normal<T: RawFloat>(x: Unpacked) -> T {
|
||||
debug_assert!(T::MIN_SIG <= x.sig && x.sig <= T::MAX_SIG,
|
||||
"encode_normal: significand not normalized");
|
||||
debug_assert!(
|
||||
T::MIN_SIG <= x.sig && x.sig <= T::MAX_SIG,
|
||||
"encode_normal: significand not normalized"
|
||||
);
|
||||
// Remove the hidden bit
|
||||
let sig_enc = x.sig & !(1 << T::EXPLICIT_SIG_BITS);
|
||||
// Adjust the exponent for exponent bias and mantissa shift
|
||||
let k_enc = x.k + T::MAX_EXP + T::EXPLICIT_SIG_BITS as i16;
|
||||
debug_assert!(k_enc != 0 && k_enc < T::MAX_ENCODED_EXP,
|
||||
"encode_normal: exponent out of range");
|
||||
debug_assert!(k_enc != 0 && k_enc < T::MAX_ENCODED_EXP, "encode_normal: exponent out of range");
|
||||
// Leave sign bit at 0 ("+"), our numbers are all positive
|
||||
let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc;
|
||||
T::from_bits(bits.try_into().unwrap_or_else(|_| unreachable!()))
|
||||
@@ -315,7 +319,7 @@ pub fn big_to_fp(f: &Big) -> Fp {
|
||||
Equal | Greater => match leading.checked_add(1) {
|
||||
Some(f) => Fp { f, e }.normalize(),
|
||||
None => Fp { f: 1 << 63, e: e + 1 },
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,8 +358,6 @@ pub fn next_float<T: RawFloat>(x: T) -> T {
|
||||
// want, and the mantissa bits become zero. Because of the hidden bit convention, this
|
||||
// too is exactly what we want!
|
||||
// Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY.
|
||||
Zero | Subnormal | Normal => {
|
||||
T::from_bits(x.to_bits() + T::Bits::from(1u8))
|
||||
}
|
||||
Zero | Subnormal | Normal => T::from_bits(x.to_bits() + T::Bits::from(1u8)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
// This module is only for dec2flt and flt2dec, and only public because of coretests.
|
||||
// It is not intended to ever be stabilized.
|
||||
#![doc(hidden)]
|
||||
#![unstable(feature = "core_private_diy_float",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0")]
|
||||
#![unstable(
|
||||
feature = "core_private_diy_float",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0"
|
||||
)]
|
||||
|
||||
/// A custom 64-bit floating point type, representing `f * 2^e`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@@ -74,9 +76,6 @@ impl Fp {
|
||||
assert!(edelta >= 0);
|
||||
let edelta = edelta as usize;
|
||||
assert_eq!(self.f << edelta >> edelta, self.f);
|
||||
Fp {
|
||||
f: self.f << edelta,
|
||||
e,
|
||||
}
|
||||
Fp { f: self.f << edelta, e }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Decodes a floating-point value into individual parts and error ranges.
|
||||
|
||||
use crate::{f32, f64};
|
||||
use crate::num::FpCategory;
|
||||
use crate::num::dec2flt::rawfp::RawFloat;
|
||||
use crate::num::FpCategory;
|
||||
use crate::{f32, f64};
|
||||
|
||||
/// Decoded unsigned finite value, such that:
|
||||
///
|
||||
@@ -47,11 +47,15 @@ pub trait DecodableFloat: RawFloat + Copy {
|
||||
}
|
||||
|
||||
impl DecodableFloat for f32 {
|
||||
fn min_pos_norm_value() -> Self { f32::MIN_POSITIVE }
|
||||
fn min_pos_norm_value() -> Self {
|
||||
f32::MIN_POSITIVE
|
||||
}
|
||||
}
|
||||
|
||||
impl DecodableFloat for f64 {
|
||||
fn min_pos_norm_value() -> Self { f64::MIN_POSITIVE }
|
||||
fn min_pos_norm_value() -> Self {
|
||||
f64::MIN_POSITIVE
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a sign (true when negative) and `FullDecoded` value
|
||||
@@ -67,20 +71,29 @@ pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) {
|
||||
// neighbors: (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, minus: 1, plus: 1,
|
||||
exp, inclusive: even })
|
||||
FullDecoded::Finite(Decoded { mant, minus: 1, plus: 1, exp, inclusive: even })
|
||||
}
|
||||
FpCategory::Normal => {
|
||||
let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode();
|
||||
if mant == minnorm.0 {
|
||||
// neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp)
|
||||
// where maxmant = minnormmant * 2 - 1
|
||||
FullDecoded::Finite(Decoded { mant: mant << 2, minus: 1, plus: 2,
|
||||
exp: exp - 2, inclusive: even })
|
||||
FullDecoded::Finite(Decoded {
|
||||
mant: mant << 2,
|
||||
minus: 1,
|
||||
plus: 2,
|
||||
exp: exp - 2,
|
||||
inclusive: even,
|
||||
})
|
||||
} else {
|
||||
// neighbors: (mant - 1, exp) -- (mant, exp) -- (mant + 1, exp)
|
||||
FullDecoded::Finite(Decoded { mant: mant << 1, minus: 1, plus: 1,
|
||||
exp: exp - 1, inclusive: even })
|
||||
FullDecoded::Finite(Decoded {
|
||||
mant: mant << 1,
|
||||
minus: 1,
|
||||
plus: 1,
|
||||
exp: exp - 1,
|
||||
inclusive: even,
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -116,15 +116,17 @@ functions.
|
||||
// while this is extensively documented, this is in principle private which is
|
||||
// only made public for testing. do not expose us.
|
||||
#![doc(hidden)]
|
||||
#![unstable(feature = "flt2dec",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0")]
|
||||
#![unstable(
|
||||
feature = "flt2dec",
|
||||
reason = "internal routines only exposed for testing",
|
||||
issue = "0"
|
||||
)]
|
||||
|
||||
pub use self::decoder::{decode, DecodableFloat, Decoded, FullDecoded};
|
||||
use crate::i16;
|
||||
pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded};
|
||||
|
||||
pub mod estimator;
|
||||
pub mod decoder;
|
||||
pub mod estimator;
|
||||
|
||||
/// Digit-generation algorithms.
|
||||
pub mod strategy {
|
||||
@@ -144,17 +146,24 @@ pub const MAX_SIG_DIGITS: usize = 17;
|
||||
#[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
|
||||
Some(i) => {
|
||||
// d[i+1..n] is all nines
|
||||
d[i] += 1;
|
||||
for j in i+1..n { d[j] = b'0'; }
|
||||
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
|
||||
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'; }
|
||||
for j in 1..n {
|
||||
d[j] = b'0';
|
||||
}
|
||||
Some(b'0')
|
||||
}
|
||||
None => { // an empty buffer rounds up (a bit strange but reasonable)
|
||||
None => {
|
||||
// an empty buffer rounds up (a bit strange but reasonable)
|
||||
Some(b'1')
|
||||
}
|
||||
}
|
||||
@@ -176,8 +185,19 @@ impl<'a> Part<'a> {
|
||||
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::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(),
|
||||
}
|
||||
}
|
||||
@@ -190,7 +210,9 @@ impl<'a> Part<'a> {
|
||||
if out.len() >= len {
|
||||
match *self {
|
||||
Part::Zero(nzeroes) => {
|
||||
for c in &mut out[..nzeroes] { *c = b'0'; }
|
||||
for c in &mut out[..nzeroes] {
|
||||
*c = b'0';
|
||||
}
|
||||
}
|
||||
Part::Num(mut v) => {
|
||||
for c in out[..len].iter_mut().rev() {
|
||||
@@ -234,7 +256,9 @@ impl<'a> Formatted<'a> {
|
||||
/// 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; }
|
||||
if out.len() < self.sign.len() {
|
||||
return None;
|
||||
}
|
||||
out[..self.sign.len()].copy_from_slice(self.sign);
|
||||
|
||||
let mut written = self.sign.len();
|
||||
@@ -254,8 +278,12 @@ impl<'a> Formatted<'a> {
|
||||
/// 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>] {
|
||||
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);
|
||||
@@ -322,8 +350,13 @@ fn digits_to_dec_str<'a>(buf: &'a [u8], exp: i16, frac_digits: usize,
|
||||
/// it will be ignored and full digits will be printed. It is only used to print
|
||||
/// additional zeroes after rendered digits. Thus, `min_digits == 0` means that
|
||||
/// it will only print the 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>] {
|
||||
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);
|
||||
@@ -359,11 +392,11 @@ fn digits_to_exp_str<'a>(buf: &'a [u8], exp: i16, min_ndigits: usize, upper: boo
|
||||
#[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
|
||||
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
|
||||
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
|
||||
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
|
||||
}
|
||||
@@ -374,11 +407,35 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static
|
||||
match (*decoded, sign) {
|
||||
(FullDecoded::Nan, _) => b"",
|
||||
(FullDecoded::Zero, Sign::Minus) => b"",
|
||||
(FullDecoded::Zero, Sign::MinusRaw) => if negative { b"-" } else { 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"+" },
|
||||
(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"+"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,10 +457,19 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static
|
||||
/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long.
|
||||
/// There should be at least 4 parts available, due to the worst case like
|
||||
/// `[+][0.][0000][2][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) {
|
||||
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);
|
||||
|
||||
@@ -419,7 +485,8 @@ pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T,
|
||||
Formatted { sign, parts: &parts[..1] }
|
||||
}
|
||||
FullDecoded::Zero => {
|
||||
if frac_digits > 0 { // [0.][0000]
|
||||
if frac_digits > 0 {
|
||||
// [0.][0000]
|
||||
parts[0] = Part::Copy(b"0.");
|
||||
parts[1] = Part::Zero(frac_digits);
|
||||
Formatted { sign, parts: &parts[..2] }
|
||||
@@ -430,8 +497,7 @@ pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T,
|
||||
}
|
||||
FullDecoded::Finite(ref decoded) => {
|
||||
let (len, exp) = format_shortest(decoded, buf);
|
||||
Formatted { sign,
|
||||
parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
|
||||
Formatted { sign, parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,10 +521,19 @@ pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T,
|
||||
/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long.
|
||||
/// There should be at least 6 parts available, due to the worst case like
|
||||
/// `[+][1][.][2345][e][-][6]`.
|
||||
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) {
|
||||
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);
|
||||
@@ -534,10 +609,19 @@ fn estimate_max_buf_len(exp: i16) -> usize {
|
||||
/// (The tipping point for `f64` is about 800, so 1000 bytes should be enough.)
|
||||
/// There should be at least 6 parts available, due to the worst case like
|
||||
/// `[+][1][.][2345][e][-][6]`.
|
||||
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) {
|
||||
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);
|
||||
|
||||
@@ -553,7 +637,8 @@ pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T,
|
||||
Formatted { sign, parts: &parts[..1] }
|
||||
}
|
||||
FullDecoded::Zero => {
|
||||
if ndigits > 1 { // [0.][0000][e0]
|
||||
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" });
|
||||
@@ -569,8 +654,7 @@ pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T,
|
||||
|
||||
let trunc = if ndigits < maxlen { ndigits } else { maxlen };
|
||||
let (len, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN);
|
||||
Formatted { sign,
|
||||
parts: digits_to_exp_str(&buf[..len], exp, ndigits, upper, parts) }
|
||||
Formatted { sign, parts: digits_to_exp_str(&buf[..len], exp, ndigits, upper, parts) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,10 +674,19 @@ pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T,
|
||||
/// (The tipping point for `f64` is about 800, and 1000 bytes should be enough.)
|
||||
/// There should be at least 4 parts available, due to the worst case like
|
||||
/// `[+][0.][0000][2][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) {
|
||||
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);
|
||||
@@ -608,7 +701,8 @@ pub fn to_exact_fixed_str<'a, T, F>(mut format_exact: F, v: T,
|
||||
Formatted { sign, parts: &parts[..1] }
|
||||
}
|
||||
FullDecoded::Zero => {
|
||||
if frac_digits > 0 { // [0.][0000]
|
||||
if frac_digits > 0 {
|
||||
// [0.][0000]
|
||||
parts[0] = Part::Copy(b"0.");
|
||||
parts[1] = Part::Zero(frac_digits);
|
||||
Formatted { sign, parts: &parts[..2] }
|
||||
@@ -631,7 +725,8 @@ pub fn to_exact_fixed_str<'a, T, F>(mut format_exact: F, v: T,
|
||||
// `exp` was. 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]
|
||||
if frac_digits > 0 {
|
||||
// [0.][0000]
|
||||
parts[0] = Part::Copy(b"0.");
|
||||
parts[1] = Part::Zero(frac_digits);
|
||||
Formatted { sign, parts: &parts[..2] }
|
||||
@@ -640,8 +735,7 @@ pub fn to_exact_fixed_str<'a, T, F>(mut format_exact: F, v: T,
|
||||
Formatted { sign, parts: &parts[..1] }
|
||||
}
|
||||
} else {
|
||||
Formatted { sign,
|
||||
parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
|
||||
Formatted { sign, parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,38 +6,54 @@
|
||||
|
||||
use crate::cmp::Ordering;
|
||||
|
||||
use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
|
||||
use crate::num::flt2dec::estimator::estimate_scaling_factor;
|
||||
use crate::num::bignum::Digit32 as Digit;
|
||||
use crate::num::bignum::Big32x40 as Big;
|
||||
use crate::num::bignum::Digit32 as Digit;
|
||||
use crate::num::flt2dec::estimator::estimate_scaling_factor;
|
||||
use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS};
|
||||
|
||||
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];
|
||||
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];
|
||||
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(x: &mut Big, n: usize) -> &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); }
|
||||
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
|
||||
}
|
||||
|
||||
@@ -52,13 +68,30 @@ fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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; }
|
||||
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)
|
||||
}
|
||||
@@ -85,7 +118,7 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp
|
||||
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};
|
||||
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.
|
||||
@@ -132,9 +165,12 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp
|
||||
}
|
||||
|
||||
// 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 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;
|
||||
@@ -186,7 +222,9 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp
|
||||
// - 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
|
||||
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,
|
||||
@@ -269,22 +307,40 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi
|
||||
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);
|
||||
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
|
||||
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'; }
|
||||
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; }
|
||||
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;
|
||||
@@ -296,8 +352,9 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi
|
||||
// if the following digits are exactly 5000..., check the prior digit and try to
|
||||
// round to even (i.e., avoid rounding up when the prior digit is even).
|
||||
let order = mant.cmp(scale.mul_small(5));
|
||||
if order == Ordering::Greater || (order == Ordering::Equal &&
|
||||
(len == 0 || buf[len-1] & 1 == 1)) {
|
||||
if order == Ordering::Greater
|
||||
|| (order == Ordering::Equal && (len == 0 || buf[len - 1] & 1 == 1))
|
||||
{
|
||||
// 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) {
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
//! accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243.
|
||||
|
||||
use crate::num::diy_float::Fp;
|
||||
use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
|
||||
|
||||
use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS};
|
||||
|
||||
// see the comments in `format_shortest_opt` for the rationale.
|
||||
#[doc(hidden)] pub const ALPHA: i16 = -60;
|
||||
#[doc(hidden)] pub const GAMMA: i16 = -32;
|
||||
#[doc(hidden)]
|
||||
pub const ALPHA: i16 = -60;
|
||||
#[doc(hidden)]
|
||||
pub const GAMMA: i16 = -32;
|
||||
|
||||
/*
|
||||
# the following Python code generates this table:
|
||||
@@ -24,92 +25,95 @@ for i in xrange(-308, 333, 8):
|
||||
*/
|
||||
|
||||
#[doc(hidden)]
|
||||
pub static CACHED_POW10: [(u64, i16, i16); 81] = [ // (f, e, k)
|
||||
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),
|
||||
(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 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) {
|
||||
@@ -128,30 +132,39 @@ 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;
|
||||
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)} }
|
||||
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)} }
|
||||
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)> {
|
||||
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);
|
||||
@@ -208,8 +221,8 @@ pub fn format_shortest_opt(d: &Decoded,
|
||||
// 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 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
|
||||
|
||||
@@ -235,14 +248,15 @@ pub fn format_shortest_opt(d: &Decoded,
|
||||
// (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 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`
|
||||
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`
|
||||
@@ -281,7 +295,8 @@ pub fn format_shortest_opt(d: &Decoded,
|
||||
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
|
||||
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`
|
||||
@@ -300,8 +315,15 @@ pub fn format_shortest_opt(d: &Decoded,
|
||||
|
||||
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);
|
||||
return round_and_weed(
|
||||
&mut buf[..i],
|
||||
exp,
|
||||
r,
|
||||
threshold,
|
||||
(plus1 - v.f) * ulp,
|
||||
ten_kappa,
|
||||
ulp,
|
||||
);
|
||||
}
|
||||
|
||||
// restore invariants
|
||||
@@ -325,8 +347,15 @@ pub fn format_shortest_opt(d: &Decoded,
|
||||
// - `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)> {
|
||||
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.
|
||||
@@ -381,10 +410,11 @@ pub fn format_shortest_opt(d: &Decoded,
|
||||
//
|
||||
// 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) {
|
||||
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;
|
||||
@@ -395,10 +425,11 @@ pub fn format_shortest_opt(d: &Decoded,
|
||||
//
|
||||
// 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) {
|
||||
if plus1w < plus1v_down
|
||||
&& threshold - plus1w >= ten_kappa
|
||||
&& (plus1w + ten_kappa < plus1v_down
|
||||
|| plus1v_down - plus1w >= plus1w + ten_kappa - plus1v_down)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -428,8 +459,11 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp
|
||||
/// 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)> {
|
||||
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());
|
||||
@@ -489,7 +523,8 @@ pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16)
|
||||
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
|
||||
loop {
|
||||
// we always have at least one digit to render
|
||||
// invariants:
|
||||
// - `remainder < 10^(kappa+1)`
|
||||
// - `vint = d[0..n-1] * 10^(kappa+1) + remainder`
|
||||
@@ -575,8 +610,15 @@ pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16)
|
||||
// - `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)> {
|
||||
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
|
||||
@@ -593,7 +635,9 @@ pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16)
|
||||
//
|
||||
// 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; }
|
||||
if ulp >= ten_kappa {
|
||||
return None;
|
||||
}
|
||||
|
||||
// 10^kappa
|
||||
// :<------->:
|
||||
@@ -607,7 +651,9 @@ pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16)
|
||||
// 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; }
|
||||
if ten_kappa - ulp <= ulp {
|
||||
return None;
|
||||
}
|
||||
|
||||
// remainder
|
||||
// :<->| :
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::ops::*;
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! sh_impl_signed {
|
||||
($t:ident, $f:ident) => (
|
||||
($t:ident, $f:ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Shl<$f> for Wrapping<$t> {
|
||||
type Output = Wrapping<$t>;
|
||||
@@ -19,7 +19,7 @@ macro_rules! sh_impl_signed {
|
||||
}
|
||||
}
|
||||
forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
impl ShlAssign<$f> for Wrapping<$t> {
|
||||
@@ -44,7 +44,7 @@ macro_rules! sh_impl_signed {
|
||||
}
|
||||
}
|
||||
forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
impl ShrAssign<$f> for Wrapping<$t> {
|
||||
@@ -54,11 +54,11 @@ macro_rules! sh_impl_signed {
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! sh_impl_unsigned {
|
||||
($t:ident, $f:ident) => (
|
||||
($t:ident, $f:ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Shl<$f> for Wrapping<$t> {
|
||||
type Output = Wrapping<$t>;
|
||||
@@ -69,7 +69,7 @@ macro_rules! sh_impl_unsigned {
|
||||
}
|
||||
}
|
||||
forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
impl ShlAssign<$f> for Wrapping<$t> {
|
||||
@@ -90,7 +90,7 @@ macro_rules! sh_impl_unsigned {
|
||||
}
|
||||
}
|
||||
forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
|
||||
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
impl ShrAssign<$f> for Wrapping<$t> {
|
||||
@@ -100,7 +100,7 @@ macro_rules! sh_impl_unsigned {
|
||||
}
|
||||
}
|
||||
forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME (#23545): uncomment the remaining impls
|
||||
|
||||
Reference in New Issue
Block a user