Skip to content

Commit

Permalink
Adds prelimary logic for #46.
Browse files Browse the repository at this point in the history
Adds the associated constants `BIGINT_LIMBS`, `BIGFLOAT_LIMBS`, and `EXPONENT_SIZE` to `Float`.
Adds the associated types `BigintStorage` and `BigfloatStorage` to `Float`.
Implements `Bigfloat` and `Bigint` in terms of `FloatType`, and the associated storage can differ depending on the float size.
  • Loading branch information
Alexhuszagh committed Apr 20, 2021
1 parent c037c7d commit 7b129e0
Show file tree
Hide file tree
Showing 12 changed files with 370 additions and 126 deletions.
6 changes: 3 additions & 3 deletions lexical-core/src/atof/algorithm/alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::errors::FloatErrors;
// TRAITS

/// Trait to simplify type signatures for atof.
pub(super) trait FloatType:
pub trait FloatType:
FloatRounding<u64> +
FloatRounding<u128> +
StablePower
Expand Down Expand Up @@ -40,8 +40,8 @@ impl MantissaType for u128 {
}

/// Trait for extended-float types.
pub(super) trait ExtendedFloatType<F: FloatType>:
ToBigfloat<F::Mantissa> +
pub trait ExtendedFloatType<F: FloatType>:
ToBigfloat<F> +
From<F>
{
// I really wish I had any other choice **other** than getters and setters,
Expand Down
15 changes: 8 additions & 7 deletions lexical-core/src/atof/algorithm/bhcomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ macro_rules! add_digits {
/// Parse the full mantissa into a big integer.
///
/// Max digits is the maximum number of digits plus one.
pub(super) fn parse_mantissa<'a, Data>(data: Data, radix: u32, max_digits: usize)
-> Bigint
where Data: SlowDataInterface<'a>
pub(super) fn parse_mantissa<'a, F, Data>(data: Data, radix: u32, max_digits: usize)
-> Bigint<F>
where F: FloatType,
Data: SlowDataInterface<'a>
{
let small_powers = Bigint::small_powers(radix);
let small_powers = Bigint::<F>::small_powers(radix);
let count = data.mantissa_digits();
let bits = count / integral_binary_factor(radix).as_usize();
let bytes = bits / <Limb as Integer>::BITS;
Expand All @@ -68,7 +69,7 @@ pub(super) fn parse_mantissa<'a, Data>(data: Data, radix: u32, max_digits: usize
let mut counter = 0;
let mut value: Limb = 0;
let mut i: usize = 0;
let mut result = Bigint::default();
let mut result = Bigint::<F>::default();
result.data.reserve(bytes);

// Iteratively process all the data in the mantissa.
Expand Down Expand Up @@ -333,7 +334,7 @@ pub(super) fn large_atof<'a, F, Data>(data: Data, radix: u32, max_digits: usize,
// Now, we can calculate the mantissa and the exponent from this.
// The binary exponent is the binary exponent for the mantissa
// shifted to the hidden bit.
let mut bigmant = parse_mantissa(data, radix, max_digits);
let mut bigmant = parse_mantissa::<F, Data>(data, radix, max_digits);
bigmant.imul_power(radix, exponent.as_u32());

// Get the exact representation of the float from the big integer.
Expand All @@ -355,7 +356,7 @@ pub(super) fn small_atof<'a, F, Data>(data: Data, radix: u32, max_digits: usize,
Data: SlowDataInterface<'a>
{
// Get the significant digits and radix exponent for the real digits.
let mut real_digits = parse_mantissa(data, radix, max_digits);
let mut real_digits = parse_mantissa::<F, Data>(data, radix, max_digits);
let real_exp = exponent;
debug_assert!(real_exp < 0);

Expand Down
40 changes: 22 additions & 18 deletions lexical-core/src/atof/algorithm/bigcomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,11 @@ perftools_inline!{
///
/// * `radix` - Radix for the number parsing.
/// * `sci_exponent` - Exponent of basen string in scientific notation.
pub fn scaling_factor(radix: u32, sci_exponent: u32)
-> Bigfloat
pub fn scaling_factor<F: FloatType>(radix: u32, sci_exponent: u32)
-> Bigfloat<F>
{
let mut factor = Bigfloat { data: arrvec![1], exp: 0 };
let mut factor: Bigfloat<F> = Bigfloat::default();
factor.data.push(1);
factor.imul_power(radix, sci_exponent);
factor
}}
Expand All @@ -130,22 +131,24 @@ pub fn scaling_factor(radix: u32, sci_exponent: u32)
/// * `radix` - Radix for the number parsing.
/// * `sci_exponent` - Exponent of basen string in scientific notation.
/// * `f` - Sub-halfway (`b`) float.
pub(super) fn make_ratio<F: Float>(radix: u32, sci_exponent: i32, f: F, kind: RoundingKind)
-> (Bigfloat, Bigfloat)
pub(super) fn make_ratio<F: FloatType>(radix: u32, sci_exponent: i32, f: F, kind: RoundingKind)
-> (Bigfloat<F>, Bigfloat<F>)
where F: FloatType
{
let theor = theoretical_float(f, kind).to_bigfloat();
let factor = scaling_factor(radix, sci_exponent.abs().as_u32());
let mut num: Bigfloat;
let mut den: Bigfloat;
let mut num: Bigfloat<F>;
let mut den: Bigfloat<F>;

if sci_exponent < 0 {
// Need to have the basen factor be the numerator, and the fp
// be the denominator. Since we assumed that theor was the numerator,
// if it's the denominator, we need to multiply it into the numerator.
num = factor;
num.imul_large(&theor);
den = Bigfloat { data: arrvec![1], exp: -theor.exp };
den = Bigfloat::default();
den.data.push(1);
den.exp = -theor.exp;
} else {
num = theor;
den = factor;
Expand Down Expand Up @@ -213,15 +216,16 @@ macro_rules! compare_digits {
/// * `radix` - Radix for the number parsing.
/// * `num` - Numerator for the fraction.
/// * `denm` - Denominator for the fraction.
pub(super) fn compare_digits<'a, Iter1, Iter2>(
pub(super) fn compare_digits<'a, F, Iter1, Iter2>(
integer: Iter1,
fraction: Iter2,
radix: u32,
mut num: Bigfloat,
den: Bigfloat
mut num: Bigfloat<F>,
den: Bigfloat<F>
)
-> cmp::Ordering
where Iter1: Iterator<Item=&'a u8>,
where F: FloatType,
Iter1: Iterator<Item=&'a u8>,
Iter2: Iterator<Item=&'a u8>
{
// Iterate until we get a difference in the generated digits.
Expand Down Expand Up @@ -303,9 +307,9 @@ mod tests {

#[test]
fn scaling_factor_test() {
assert_eq!(scaling_factor(10, 0), Bigfloat { data: deduce_from_u32(&[1]), exp: 0 });
assert_eq!(scaling_factor(10, 20), Bigfloat { data: deduce_from_u32(&[1977800241, 22204]), exp: 20 });
assert_eq!(scaling_factor(10, 300), Bigfloat { data: deduce_from_u32(&[2502905297, 773182544, 1122691908, 922368819, 2799959258, 2138784391, 2365897751, 2382789932, 3061508751, 1799019667, 3501640837, 269048281, 2748691596, 1866771432, 2228563347, 475471294, 278892994, 2258936920, 3352132269, 1505791508, 2147965370, 25052104]), exp: 300 });
assert_eq!(scaling_factor::<f64>(10, 0), Bigfloat { data: deduce_from_u32(&[1]), exp: 0 });
assert_eq!(scaling_factor::<f64>(10, 20), Bigfloat { data: deduce_from_u32(&[1977800241, 22204]), exp: 20 });
assert_eq!(scaling_factor::<f64>(10, 300), Bigfloat { data: deduce_from_u32(&[2502905297, 773182544, 1122691908, 922368819, 2799959258, 2138784391, 2365897751, 2382789932, 3061508751, 1799019667, 3501640837, 269048281, 2748691596, 1866771432, 2228563347, 475471294, 278892994, 2258936920, 3352132269, 1505791508, 2147965370, 25052104]), exp: 300 });
}

#[test]
Expand Down Expand Up @@ -340,7 +344,7 @@ mod tests {
#[test]
fn compare_digits_test() {
// 2^-1074
let num = Bigfloat { data: deduce_from_u32(&[1725370368, 1252154597, 1017462556, 675087593, 2805901938, 1401824593, 1124332496, 2380663002, 1612846757, 4128923878, 1492915356, 437569744, 2975325085, 3331531962, 3367627909, 730662168, 2699172281, 1440714968, 2778340312, 690527038, 1297115354, 763425880, 1453089653, 331561842]), exp: 312 };
let num = Bigfloat::<f64> { data: deduce_from_u32(&[1725370368, 1252154597, 1017462556, 675087593, 2805901938, 1401824593, 1124332496, 2380663002, 1612846757, 4128923878, 1492915356, 437569744, 2975325085, 3331531962, 3367627909, 730662168, 2699172281, 1440714968, 2778340312, 690527038, 1297115354, 763425880, 1453089653, 331561842]), exp: 312 };
let den = Bigfloat { data: deduce_from_u32(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134217728]), exp: 312 };

// Below halfway
Expand All @@ -357,7 +361,7 @@ mod tests {
assert_eq!(compare_digits(digits.iter(), empty.iter(), 10, num.clone(), den.clone()), cmp::Ordering::Greater);

// 2*2^-1074
let num = Bigfloat { data: deduce_from_u32(&[881143808, 3756463792, 3052387668, 2025262779, 4122738518, 4205473780, 3372997488, 2847021710, 543572976, 3796837043, 183778774, 1312709233, 336040663, 1404661296, 1512949137, 2191986506, 3802549547, 27177609, 4040053641, 2071581115, 3891346062, 2290277640, 64301663, 994685527]), exp: 312 };
let num = Bigfloat::<f64> { data: deduce_from_u32(&[881143808, 3756463792, 3052387668, 2025262779, 4122738518, 4205473780, 3372997488, 2847021710, 543572976, 3796837043, 183778774, 1312709233, 336040663, 1404661296, 1512949137, 2191986506, 3802549547, 27177609, 4040053641, 2071581115, 3891346062, 2290277640, 64301663, 994685527]), exp: 312 };
let den = Bigfloat { data: deduce_from_u32(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134217728]), exp: 312 };

// Below halfway
Expand All @@ -373,7 +377,7 @@ mod tests {
assert_eq!(compare_digits(digits.iter(), empty.iter(), 10, num.clone(), den.clone()), cmp::Ordering::Greater);

// 4503599627370496*2^971
let num = Bigfloat { data: deduce_from_u32(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1024, 2147483648]), exp: 288 };
let num = Bigfloat::<f64> { data: deduce_from_u32(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1024, 2147483648]), exp: 288 };
let den = Bigfloat { data: deduce_from_u32(&[1978138624, 2671552565, 2938166866, 3588566204, 1860064291, 2104472219, 2014975858, 2797301608, 462262832, 318515330, 1101517094, 1738264167, 3721375114, 414401884, 1406861075, 3053102637, 387329537, 2051556775, 1867945454, 3717689914, 1434550525, 1446648206, 238915486]), exp: 288 };

// Below halfway
Expand Down
109 changes: 50 additions & 59 deletions lexical-core/src/atof/algorithm/bignum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,10 @@

use crate::float::*;
use crate::util::*;
use super::alias::FloatType;
use super::math::*;

// DATA TYPE

// TODO(ahuszagh) Need to make a way for this to be specific to the
// integer size.
// Should probably change these sizes to the correct f32 and f64 size.

cfg_if! {
if #[cfg(feature = "radix")] {
// Enable dynamically allocated memory for the radix feature,
// since we have a theoretically infinite number of digits
// required for rounding accuracy.
use crate::lib::Vec;
type IntStorageType = Vec<Limb>;
} else {
// Maximum denominator is 767 mantissa digits + 324 exponent,
// or 1091 digits, or approximately 3600 bits (round up to 4k).
#[cfg(limb_width_32)]
type IntStorageType = arrayvec::ArrayVec<[Limb; 128]>;

#[cfg(limb_width_64)]
type IntStorageType = arrayvec::ArrayVec<[Limb; 64]>;
}} // cfg_if
// BINARY FACTOR

perftools_inline!{
/// Calculate the integral ceiling of the binary factor from a basen number.
Expand Down Expand Up @@ -103,22 +83,22 @@ pub(super) fn integral_binary_factor(radix: u32)
/// * `f128` - 16530
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(Debug))]
pub(crate) struct Bigint {
pub(crate) struct Bigint<F: Float> {
/// Internal storage for the Bigint, in little-endian order.
pub(crate) data: IntStorageType,
pub(crate) data: F::BigintStorage,
}

impl Default for Bigint {
impl<F: Float> Default for Bigint<F> {
fn default() -> Self {
// We want to avoid lower-order
let mut bigint = Bigint { data: IntStorageType::default() };
let mut bigint = Self { data: F::BigintStorage::default() };
bigint.data.reserve(20);
bigint
}
}

impl SharedOps for Bigint {
type StorageType = IntStorageType;
impl<F: Float> SharedOps for Bigint<F> {
type StorageType = F::BigintStorage;

perftools_inline_always!{
fn data<'a>(&'a self) -> &'a Self::StorageType {
Expand All @@ -131,24 +111,14 @@ impl SharedOps for Bigint {
}}
}

impl SmallOps for Bigint {
impl<F: Float> SmallOps for Bigint<F> {
}

impl LargeOps for Bigint {
impl<F: Float> LargeOps for Bigint<F> {
}

// BIGFLOAT

// Adjust the storage capacity for the underlying array.
// TODO(ahuszagh) This needs to differ based on
// the size of the float type.
cfg_if! {
if #[cfg(limb_width_64)] {
type FloatStorageType = arrayvec::ArrayVec<[Limb; 20]>;
} else {
type FloatStorageType = arrayvec::ArrayVec<[Limb; 36]>;
}} // cfg_if

/// Storage for a big floating-point type.
///
/// This is used for the bigcomp::atof algorithm, which crates a
Expand All @@ -163,29 +133,29 @@ if #[cfg(limb_width_64)] {
/// * `f128` - 11564
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(Debug))]
pub struct Bigfloat {
pub struct Bigfloat<F: Float> {
/// Internal storage for the Bigfloat, in little-endian order.
///
/// Enough storage for up to 10^345, which is 2^1146, or more than
/// the max for f64.
pub(crate) data: FloatStorageType,
pub(crate) data: F::BigfloatStorage,
/// It also makes sense to store an exponent, since this simplifies
/// normalizing and powers of 2.
pub(crate) exp: i32,
}

impl Default for Bigfloat {
impl<F: Float> Default for Bigfloat<F> {
perftools_inline!{
fn default() -> Self {
// We want to avoid lower-order
let mut bigfloat = Bigfloat { data: FloatStorageType::default(), exp: 0 };
let mut bigfloat = Self { data: F::BigfloatStorage::default(), exp: 0 };
bigfloat.data.reserve(10);
bigfloat
}}
}

impl SharedOps for Bigfloat {
type StorageType = FloatStorageType;
impl<F: Float> SharedOps for Bigfloat<F> {
type StorageType = F::BigfloatStorage;

perftools_inline_always!{
fn data<'a>(&'a self) -> &'a Self::StorageType {
Expand All @@ -198,46 +168,67 @@ impl SharedOps for Bigfloat {
}}
}

impl SmallOps for Bigfloat {
impl<F: Float> SmallOps for Bigfloat<F> {
perftools_inline!{
fn imul_pow2(&mut self, n: u32) {
// Increment exponent to simulate actual multiplication.
self.exp += n.as_i32();
}}
}

impl LargeOps for Bigfloat {
impl<F: Float> LargeOps for Bigfloat<F> {
}

// TO BIGFLOAT

/// Simple overloads to allow conversions of extended floats to big integers.
pub trait ToBigfloat<M: Mantissa> {
fn to_bigfloat(&self) -> Bigfloat;
pub trait ToBigfloat<F: FloatType> {
fn to_bigfloat(&self) -> Bigfloat<F>;
}

#[cfg(feature = "f16")]
impl ToBigfloat<f16> for ExtendedFloat<<f16 as FloatType>::Mantissa> {
perftools_inline!{
fn to_bigfloat(&self) -> Bigfloat<f16> {
let mut bigfloat = Bigfloat::<f16>::from_u32(self.mant);
bigfloat.exp = self.exp;
bigfloat
}}
}

#[cfg(feature = "f16")]
impl ToBigfloat<bf16> for ExtendedFloat<<bf16 as FloatType>::Mantissa> {
perftools_inline!{
fn to_bigfloat(&self) -> Bigfloat<bf16> {
let mut bigfloat = Bigfloat::<bf16>::from_u32(self.mant);
bigfloat.exp = self.exp;
bigfloat
}}
}

impl ToBigfloat<u32> for ExtendedFloat<u32> {
impl ToBigfloat<f32> for ExtendedFloat<<f32 as FloatType>::Mantissa> {
perftools_inline!{
fn to_bigfloat(&self) -> Bigfloat {
let mut bigfloat = Bigfloat::from_u32(self.mant);
fn to_bigfloat(&self) -> Bigfloat<f32> {
let mut bigfloat = Bigfloat::<f32>::from_u32(self.mant);
bigfloat.exp = self.exp;
bigfloat
}}
}

impl ToBigfloat<u64> for ExtendedFloat<u64> {
impl ToBigfloat<f64> for ExtendedFloat<<f64 as FloatType>::Mantissa> {
perftools_inline!{
fn to_bigfloat(&self) -> Bigfloat {
let mut bigfloat = Bigfloat::from_u64(self.mant);
fn to_bigfloat(&self) -> Bigfloat<f64> {
let mut bigfloat = Bigfloat::<f64>::from_u64(self.mant);
bigfloat.exp = self.exp;
bigfloat
}}
}

impl ToBigfloat<u128> for ExtendedFloat<u128> {
#[cfg(feature = "f128")]
impl ToBigfloat<f128> for ExtendedFloat<<f128 as FloatType>::Mantissa> {
perftools_inline!{
fn to_bigfloat(&self) -> Bigfloat {
let mut bigfloat = Bigfloat::from_u128(self.mant);
fn to_bigfloat(&self) -> Bigfloat<f128> {
let mut bigfloat = Bigfloat::<f128>::from_u64(self.mant);
bigfloat.exp = self.exp;
bigfloat
}}
Expand Down
2 changes: 1 addition & 1 deletion lexical-core/src/atof/algorithm/large_powers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! The larger powers are **quite** large (~3Kb per radix), so we'd rather
//! not include them in binaries unless necessary.

use super::math::Limb;
use crate::util::Limb;

#[cfg(limb_width_32)]
use super::large_powers_32::*;
Expand Down
Loading

0 comments on commit 7b129e0

Please sign in to comment.