Reorganize core::num internals

Move private bignum module to core::num, because it is not only used in flt2dec.
Extract private 80-bit soft-float into new core::num module for the same reason.
This commit is contained in:
Robin Kruppe 2015-09-20 18:34:33 +02:00
parent cff0411706
commit cd67ec306f
16 changed files with 106 additions and 79 deletions

View File

@ -19,6 +19,12 @@
//! 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.
// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
// It is not intended to ever be stabilized.
#![doc(hidden)]
#![unstable(feature = "core_private_bignum",
reason = "internal routines only exposed for testing",
issue = "0")]
#![macro_use]
use prelude::v1::*;
@ -194,7 +200,7 @@ macro_rules! define_bignum {
/// 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;
use num::bignum::FullOps;
let mut sz = cmp::max(self.size, other.size);
let mut carry = false;
@ -212,7 +218,7 @@ macro_rules! define_bignum {
}
pub fn add_small(&mut self, other: $ty) -> &mut $name {
use num::flt2dec::bignum::FullOps;
use num::bignum::FullOps;
let (mut carry, v) = self.base[0].full_add(other, false);
self.base[0] = v;
@ -232,7 +238,7 @@ macro_rules! define_bignum {
/// 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;
use num::bignum::FullOps;
let sz = cmp::max(self.size, other.size);
let mut noborrow = true;
@ -249,7 +255,7 @@ macro_rules! define_bignum {
/// Multiplies itself by a digit-sized `other` and returns its own
/// mutable reference.
pub fn mul_small(&mut self, other: $ty) -> &mut $name {
use num::flt2dec::bignum::FullOps;
use num::bignum::FullOps;
let mut sz = self.size;
let mut carry = 0;
@ -310,7 +316,7 @@ macro_rules! define_bignum {
/// Multiplies itself by `5^e` and returns its own mutable reference.
pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name {
use mem;
use num::flt2dec::bignum::SMALL_POW5;
use num::bignum::SMALL_POW5;
// There are exactly n trailing zeros on 2^n, and the only relevant digit sizes
// are consecutive powers of two, so this is well suited index for the table.
@ -341,7 +347,7 @@ macro_rules! define_bignum {
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;
use num::bignum::FullOps;
let mut retsz = 0;
for (i, &a) in aa.iter().enumerate() {
@ -378,7 +384,7 @@ macro_rules! define_bignum {
/// Divides itself by a digit-sized `other` and returns its own
/// mutable reference *and* the remainder.
pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) {
use num::flt2dec::bignum::FullOps;
use num::bignum::FullOps;
assert!(other > 0);

View File

@ -10,13 +10,13 @@
//! The various algorithms from the paper.
use num::flt2dec::strategy::grisu::Fp;
use prelude::v1::*;
use cmp::min;
use cmp::Ordering::{Less, Equal, Greater};
use super::table;
use super::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float};
use super::num::{self, Big};
use num::diy_float::Fp;
use num::dec2flt::table;
use num::dec2flt::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float};
use num::dec2flt::num::{self, Big};
/// Number of significand bits in Fp
const P: u32 = 64;

View File

@ -86,9 +86,6 @@
//! "such that the exponent +/- the number of decimal digits fits into a 64 bit integer".
//! Larger exponents are accepted, but we don't do arithmetic with them, they are immediately
//! turned into {positive,negative} {zero,infinity}.
//!
//! FIXME: this uses several things from core::num::flt2dec, which is nonsense. Those things
//! should be moved into core::num::<something else>.
#![doc(hidden)]
#![unstable(feature = "dec2flt",

View File

@ -14,9 +14,8 @@
use prelude::v1::*;
use cmp::Ordering::{self, Less, Equal, Greater};
use num::flt2dec::bignum::Big32x40;
pub type Big = Big32x40;
pub use num::bignum::Big32x40 as Big;
/// Test whether truncating all bits less significant than `ones_place` introduces
/// a relative error less, equal, or greater than 0.5 ULP.

View File

@ -33,10 +33,10 @@ use cmp::Ordering::{Less, Equal, Greater};
use ops::{Mul, Div, Neg};
use fmt::{Debug, LowerExp};
use mem::transmute;
use num::flt2dec::strategy::grisu::Fp;
use num::diy_float::Fp;
use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
use num::Float;
use super::num::{self, Big};
use num::dec2flt::num::{self, Big};
#[derive(Copy, Clone, Debug)]
pub struct Unpacked {

View File

@ -0,0 +1,71 @@
// 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.
//! Extended precision "soft float", for internal use only.
// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
// 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")]
/// 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`.
pub 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`.
pub 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).
pub 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 }
}
}

View File

@ -136,7 +136,6 @@ use slice::bytes;
pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded};
pub mod estimator;
pub mod bignum;
pub mod decoder;
/// Digit-generation algorithms.

View File

@ -21,8 +21,8 @@ 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::Big32x40 as Big;
use num::bignum::Digit32 as Digit;
use num::bignum::Big32x40 as Big;
static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000];

View File

@ -18,60 +18,9 @@ Rust adaptation of Grisu3 algorithm described in [1]. It uses about
use prelude::v1::*;
use num::diy_float::Fp;
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`.
pub 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`.
pub 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).
pub 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;

View File

@ -43,8 +43,12 @@ use slice::SliceExt;
pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
pub mod wrapping;
// All these modules are technically private and only exposed for libcoretest:
pub mod flt2dec;
pub mod dec2flt;
pub mod bignum;
pub mod diy_float;
/// Types that have a "zero" value.
///

View File

@ -15,6 +15,8 @@
#![feature(const_fn)]
#![feature(core)]
#![feature(core_float)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(dec2flt)]
#![feature(decode_utf16)]
#![feature(fixed_size_array)]

View File

@ -9,7 +9,7 @@
// except according to those terms.
use std::prelude::v1::*;
use core::num::flt2dec::bignum::tests::Big8x3 as Big;
use core::num::bignum::tests::Big8x3 as Big;
#[test]
#[should_panic]

View File

@ -9,14 +9,14 @@
// except according to those terms.
use std::f64;
use core::num::flt2dec::strategy::grisu::Fp;
use core::num::diy_float::Fp;
use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal};
#[test]
fn fp_to_float_half_to_even() {
fn is_normalized(sig: u64) -> bool {
// intentionally written without {min,max}_sig() as a sanity check
sig >> 52 == 1 && sig >> 53 == 0
// intentionally written without {min,max}_sig() as a sanity check
sig >> 52 == 1 && sig >> 53 == 0
}
fn conv(sig: u64) -> u64 {

View File

@ -23,7 +23,6 @@ use core::num::flt2dec::{to_shortest_str, to_shortest_exp_str,
pub use test::Bencher;
mod estimator;
mod bignum;
mod strategy {
mod dragon;
mod grisu;

View File

@ -12,7 +12,7 @@ use std::prelude::v1::*;
use std::{i16, f64};
use super::super::*;
use core::num::flt2dec::*;
use core::num::flt2dec::bignum::Big32x40 as Big;
use core::num::bignum::Big32x40 as Big;
use core::num::flt2dec::strategy::dragon::*;
#[test]

View File

@ -31,6 +31,7 @@ mod u64;
mod flt2dec;
mod dec2flt;
mod bignum;
/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T) where