Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,68 @@
#![cfg(any(feature = "compact", feature = "radix"))]
#![allow(dead_code)]
use lexical_parse_float::bellerophon::bellerophon;
use lexical_parse_float::float::{extended_to_float, ExtendedFloat80, RawFloat};
use lexical_parse_float::number::Number;
use lexical_util::format::STANDARD;
pub fn bellerophon_test<F: RawFloat, const FORMAT: u128>(
xmant: u64,
xexp: i32,
many_digits: bool,
ymant: u64,
yexp: i32,
) {
let num = Number {
exponent: xexp as i64,
mantissa: xmant,
is_negative: false,
many_digits,
integer: &[],
fraction: None,
};
let xfp = bellerophon::<F, FORMAT>(&num, false);
let yfp = ExtendedFloat80 {
mant: ymant,
exp: yexp,
};
// Given us useful error messages if the floats are valid.
if xfp.exp >= 0 && yfp.exp >= 0 {
assert!(
xfp == yfp,
"x != y, xfp={:?}, yfp={:?}, x={:?}, y={:?}",
xfp,
yfp,
extended_to_float::<F>(xfp),
extended_to_float::<F>(yfp)
);
} else {
assert_eq!(xfp, yfp);
}
}
pub fn compute_float32(q: i64, w: u64) -> (i32, u64) {
let num = Number {
exponent: q,
mantissa: w,
is_negative: false,
many_digits: false,
integer: &[],
fraction: None,
};
let fp = bellerophon::<f32, { STANDARD }>(&num, false);
(fp.exp, fp.mant)
}
pub fn compute_float64(q: i64, w: u64) -> (i32, u64) {
let num = Number {
exponent: q,
mantissa: w,
is_negative: false,
many_digits: false,
integer: &[],
fraction: None,
};
let fp = bellerophon::<f64, { STANDARD }>(&num, false);
(fp.exp, fp.mant)
}
@@ -0,0 +1,26 @@
#![cfg(feature = "radix")]
mod bellerophon;
use bellerophon::bellerophon_test;
use lexical_util::format::NumberFormatBuilder;
const BASE3: u128 = NumberFormatBuilder::from_radix(3);
#[test]
fn bellerophon_radix_test() {
// Checking the exact rounding of the digits close to 5e-324.
bellerophon_test::<f64, { BASE3 }>(5, -640, false, 4172256988254845, 10);
bellerophon_test::<f64, { BASE3 }>(2, -679, false, 0, 0);
bellerophon_test::<f64, { BASE3 }>(3, -679, false, 1, 0);
bellerophon_test::<f64, { BASE3 }>(6, -680, false, 0, 0);
bellerophon_test::<f64, { BASE3 }>(7, -680, false, 1, 0);
bellerophon_test::<f64, { BASE3 }>(20, -681, false, 0, 0);
bellerophon_test::<f64, { BASE3 }>(21, -681, false, 1, 0);
bellerophon_test::<f64, { BASE3 }>(61, -682, false, 0, 0);
bellerophon_test::<f64, { BASE3 }>(62, -682, false, 1, 0);
bellerophon_test::<f64, { BASE3 }>(184, -683, false, 0, 0);
bellerophon_test::<f64, { BASE3 }>(185, -683, false, 1, 0);
bellerophon_test::<f64, { BASE3 }>(554, -684, false, 0, 0);
bellerophon_test::<f64, { BASE3 }>(555, -684, false, 1, 0);
}
@@ -0,0 +1,250 @@
#![cfg(feature = "compact")]
mod bellerophon;
use bellerophon::{bellerophon_test, compute_float32, compute_float64};
use lexical_parse_float::shared::INVALID_FP;
use lexical_util::format::STANDARD;
#[test]
fn halfway_round_down_test() {
// Halfway, round-down tests
bellerophon_test::<f64, { STANDARD }>(9007199254740992, 0, false, 0, 1076);
bellerophon_test::<f64, { STANDARD }>(
9007199254740993,
0,
false,
9223372036854776832,
1065 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(9007199254740994, 0, false, 1, 1076);
bellerophon_test::<f64, { STANDARD }>(18014398509481984, 0, false, 0, 1077);
bellerophon_test::<f64, { STANDARD }>(
18014398509481986,
0,
false,
9223372036854776832,
1066 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(18014398509481988, 0, false, 1, 1077);
bellerophon_test::<f64, { STANDARD }>(9223372036854775808, 0, false, 0, 1086);
bellerophon_test::<f64, { STANDARD }>(
9223372036854776832,
0,
false,
9223372036854776832,
1075 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(9223372036854777856, 0, false, 1, 1086);
// Add a 0 but say we're truncated.
bellerophon_test::<f64, { STANDARD }>(9007199254740992000, -3, true, 0, 1076);
bellerophon_test::<f64, { STANDARD }>(
9007199254740993000,
-3,
true,
9223372036854776832,
1065 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(9007199254740994000, -3, true, 1, 1076);
}
#[test]
fn halfway_round_up_test() {
// Halfway, round-up tests
bellerophon_test::<f64, { STANDARD }>(9007199254740994, 0, false, 1, 1076);
bellerophon_test::<f64, { STANDARD }>(
9007199254740995,
0,
false,
9223372036854778880,
1065 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(9007199254740996, 0, false, 2, 1076);
bellerophon_test::<f64, { STANDARD }>(18014398509481988, 0, false, 1, 1077);
bellerophon_test::<f64, { STANDARD }>(
18014398509481990,
0,
false,
9223372036854778880,
1066 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(18014398509481992, 0, false, 2, 1077);
bellerophon_test::<f64, { STANDARD }>(9223372036854777856, 0, false, 1, 1086);
bellerophon_test::<f64, { STANDARD }>(
9223372036854778880,
0,
false,
9223372036854778880,
1075 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(9223372036854779904, 0, false, 2, 1086);
// Add a 0 but say we're truncated.
bellerophon_test::<f64, { STANDARD }>(9007199254740994000, -3, true, 1, 1076);
bellerophon_test::<f64, { STANDARD }>(
9007199254740994990,
-3,
true,
9223372036854778869,
1065 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(
9007199254740995000,
-3,
true,
9223372036854778879,
1065 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(
9007199254740995010,
-3,
true,
9223372036854778890,
1065 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(9007199254740995050, -3, true, 2, 1076);
bellerophon_test::<f64, { STANDARD }>(9007199254740996000, -3, true, 2, 1076);
}
#[test]
fn extremes_test() {
// Need to check we get proper results with rounding for near-infinity
// and near-zero and/or denormal floats.
bellerophon_test::<f64, { STANDARD }>(5, -324, false, 1, 0);
bellerophon_test::<f64, { STANDARD }>(10, -324, false, 2, 0);
// This is very close to 2.4703282292062327206e-342.
bellerophon_test::<f64, { STANDARD }>(
2470328229206232720,
-342,
false,
18446744073709551608,
-64 + INVALID_FP,
);
bellerophon_test::<f64, { STANDARD }>(
2470328229206232721,
-342,
false,
9223372036854775808,
-32831,
);
bellerophon_test::<f64, { STANDARD }>(
2470328229206232725,
-342,
false,
9223372036854775824,
-32831,
);
bellerophon_test::<f64, { STANDARD }>(2470328229206232726, -342, false, 1, 0);
bellerophon_test::<f64, { STANDARD }>(2470328229206232730, -342, false, 1, 0);
// Check very close to literal infinity.
// 17.976931348623155
// 1.797693134862315508561243283845062402343434371574593359244049e+308
// 1.797693134862315708145274237317043567980705675258449965989175e+308
bellerophon_test::<f64, { STANDARD }>(17976931348623155, 292, false, 4503599627370494, 2046);
bellerophon_test::<f64, { STANDARD }>(17976931348623156, 292, false, 4503599627370494, 2046);
bellerophon_test::<f64, { STANDARD }>(1797693134862315605, 290, false, 4503599627370494, 2046);
bellerophon_test::<f64, { STANDARD }>(1797693134862315607, 290, false, 4503599627370494, 2046);
bellerophon_test::<f64, { STANDARD }>(
1797693134862315608,
290,
false,
18446744073709548540,
-30733,
);
bellerophon_test::<f64, { STANDARD }>(
1797693134862315609,
290,
false,
18446744073709548550,
-30733,
);
bellerophon_test::<f64, { STANDARD }>(179769313486231561, 291, false, 4503599627370495, 2046);
bellerophon_test::<f64, { STANDARD }>(17976931348623157, 292, false, 4503599627370495, 2046);
// Check existing issues and underflow.
bellerophon_test::<f64, { STANDARD }>(2470328229206232726, -343, false, 0, 0);
bellerophon_test::<f64, { STANDARD }>(2470328229206232726, -342, false, 1, 0);
bellerophon_test::<f64, { STANDARD }>(1, -250, false, 1945308223406668, 192);
bellerophon_test::<f64, { STANDARD }>(1, -150, false, 2867420733609077, 524);
bellerophon_test::<f64, { STANDARD }>(1, -45, false, 1924152549665465, 873);
bellerophon_test::<f64, { STANDARD }>(1, -40, false, 400386103400348, 890);
bellerophon_test::<f64, { STANDARD }>(1, -20, false, 2142540351554083, 956);
bellerophon_test::<f64, { STANDARD }>(1, 0, false, 0, 1023);
bellerophon_test::<f64, { STANDARD }>(1, 20, false, 1599915997629504, 1089);
bellerophon_test::<f64, { STANDARD }>(1, 40, false, 3768206498159781, 1155);
bellerophon_test::<f64, { STANDARD }>(1, 150, false, 999684479948463, 1521);
bellerophon_test::<f64, { STANDARD }>(1, 250, false, 1786584717939204, 1853);
// Minimum positive normal float.
bellerophon_test::<f64, { STANDARD }>(22250738585072014, -324, false, 0, 1);
// Maximum positive subnormal float.
bellerophon_test::<f64, { STANDARD }>(2225073858507201, -323, false, 4503599627370495, 0);
// Next highest subnormal float.
bellerophon_test::<f64, { STANDARD }>(22250738585072004, -324, false, 4503599627370494, 0);
bellerophon_test::<f64, { STANDARD }>(22250738585072006, -324, false, 4503599627370494, 0);
bellerophon_test::<f64, { STANDARD }>(22250738585072007, -324, false, 4503599627370495, 0);
bellerophon_test::<f64, { STANDARD }>(222507385850720062, -325, false, 4503599627370494, 0);
bellerophon_test::<f64, { STANDARD }>(222507385850720063, -325, false, 4503599627370494, 0);
bellerophon_test::<f64, { STANDARD }>(222507385850720064, -325, false, 4503599627370494, 0);
bellerophon_test::<f64, { STANDARD }>(
2225073858507200641,
-326,
false,
18446744073709545462,
-32779,
);
bellerophon_test::<f64, { STANDARD }>(
2225073858507200642,
-326,
false,
18446744073709545472,
-32779,
);
bellerophon_test::<f64, { STANDARD }>(222507385850720065, -325, false, 4503599627370495, 0);
}
#[test]
fn compute_float_f32_test() {
// These test near-halfway cases for single-precision floats.
assert_eq!(compute_float32(0, 16777216), (151, 0));
assert_eq!(compute_float32(0, 16777217), (111 + INVALID_FP, 9223372586610589696));
assert_eq!(compute_float32(0, 16777218), (151, 1));
assert_eq!(compute_float32(0, 16777219), (111 + INVALID_FP, 9223373686122217472));
assert_eq!(compute_float32(0, 16777220), (151, 2));
// These are examples of the above tests, with
// digits from the exponent shifted to the mantissa.
assert_eq!(compute_float32(-10, 167772160000000000), (151, 0));
assert_eq!(compute_float32(-10, 167772170000000000), (111 + INVALID_FP, 9223372586610589696));
assert_eq!(compute_float32(-10, 167772180000000000), (151, 1));
// Let's check the lines to see if anything is different in table...
assert_eq!(compute_float32(-10, 167772190000000000), (111 + INVALID_FP, 9223373686122217472));
assert_eq!(compute_float32(-10, 167772200000000000), (151, 2));
}
#[test]
fn compute_float_f64_test() {
// These test near-halfway cases for double-precision floats.
assert_eq!(compute_float64(0, 9007199254740992), (1076, 0));
assert_eq!(compute_float64(0, 9007199254740993), (1065 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_float64(0, 9007199254740994), (1076, 1));
assert_eq!(compute_float64(0, 9007199254740995), (1065 + INVALID_FP, 9223372036854778880));
assert_eq!(compute_float64(0, 9007199254740996), (1076, 2));
assert_eq!(compute_float64(0, 18014398509481984), (1077, 0));
assert_eq!(compute_float64(0, 18014398509481986), (1066 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_float64(0, 18014398509481988), (1077, 1));
assert_eq!(compute_float64(0, 18014398509481990), (1066 + INVALID_FP, 9223372036854778880));
assert_eq!(compute_float64(0, 18014398509481992), (1077, 2));
// These are examples of the above tests, with
// digits from the exponent shifted to the mantissa.
assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0));
assert_eq!(compute_float64(-3, 9007199254740993000), (1065 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1));
assert_eq!(compute_float64(-3, 9007199254740995000), (1065 + INVALID_FP, 9223372036854778879));
assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2));
}
@@ -0,0 +1,63 @@
#![cfg(feature = "radix")]
mod stackvec;
use lexical_parse_float::bigint::{Bigfloat, Limb};
use lexical_parse_float::float::ExtendedFloat80;
use stackvec::vec_from_u32;
#[test]
fn simple_test() {
let x = Bigfloat::new();
assert_eq!(x.exp, 0);
let y = Bigfloat::from_float(ExtendedFloat80 {
mant: 1 << 63,
exp: -63,
});
assert_eq!(y.exp, -63);
let x = Bigfloat::from_u32(1);
assert_eq!(&*x.data, &[1]);
let mut x = Bigfloat::from_u64(1);
assert_eq!(&*x.data, &[1]);
x.pow(10, 10);
assert_eq!(&*x.data, &[9765625]);
assert_eq!(x.exp, 10);
x.shl_bits(1);
assert_eq!(&*x.data, &[19531250]);
assert_eq!(x.exp, 10);
x.shl_limbs(1);
assert_eq!(&*x.data, &[0, 19531250]);
assert_eq!(x.exp, 10);
assert_eq!(x.leading_zeros(), Limb::BITS - 25);
// y has a 0 for 32-bit limbs, no 0s for 64-bit limbs.
x *= &y;
let expected = if Limb::BITS == 32 {
vec_from_u32(&[0, 0, 0, 9765625])
} else {
vec_from_u32(&[0, 0, 0, 0, 9765625])
};
assert!(x.data == expected, "failed");
assert_eq!(x.exp, -53);
}
#[test]
fn leading_zeros_test() {
assert_eq!(Bigfloat::new().leading_zeros(), 0);
assert_eq!(Bigfloat::from_u32(0xFF).leading_zeros(), Limb::BITS - 8);
assert_eq!(Bigfloat::from_u64(0xFF00000000).leading_zeros(), 24);
assert_eq!(Bigfloat::from_u32(0xF).leading_zeros(), Limb::BITS - 4);
assert_eq!(Bigfloat::from_u64(0xF00000000).leading_zeros(), 28);
assert_eq!(Bigfloat::from_u32(0xF0).leading_zeros(), Limb::BITS - 8);
assert_eq!(Bigfloat::from_u64(0xF000000000).leading_zeros(), 24);
}
@@ -0,0 +1,26 @@
mod stackvec;
use lexical_parse_float::bigint::Bigint;
use stackvec::vec_from_u32;
#[test]
fn simple_test() {
let x = Bigint::new();
assert_eq!(x.hi64(), (0, false));
let x = Bigint::from_u32(1);
assert_eq!(&*x.data, &[1]);
let mut x = Bigint::from_u64(1);
assert_eq!(&*x.data, &[1]);
x.pow(10, 10);
let expected = vec_from_u32(&[1410065408, 2]);
assert!(x.data == expected, "failed");
assert_eq!(x.bit_length(), 34);
let y = Bigint::from_u64(5);
x *= &y;
let expected = vec_from_u32(&[2755359744, 11]);
assert!(x.data == expected, "failed");
}
@@ -0,0 +1,161 @@
#![cfg(feature = "power-of-two")]
use lexical_parse_float::binary::{binary, slow_binary};
use lexical_parse_float::number::Number;
use lexical_util::format::NumberFormatBuilder;
const BINARY: u128 = NumberFormatBuilder::from_radix(2);
const BASE4: u128 = NumberFormatBuilder::from_radix(4);
const OCTAL: u128 = NumberFormatBuilder::from_radix(8);
const HEX: u128 = NumberFormatBuilder::from_radix(16);
const BASE32: u128 = NumberFormatBuilder::from_radix(32);
fn compute_float32<const FORMAT: u128>(q: i64, w: u64, many_digits: bool) -> (i32, u64) {
let num = Number {
exponent: q,
mantissa: w,
is_negative: false,
many_digits,
integer: &[],
fraction: None,
};
let fp = binary::<f32, FORMAT>(&num, false);
(fp.exp, fp.mant)
}
fn compute_float64<const FORMAT: u128>(q: i64, w: u64, many_digits: bool) -> (i32, u64) {
let num = Number {
exponent: q,
mantissa: w,
is_negative: false,
many_digits,
integer: &[],
fraction: None,
};
let fp = binary::<f64, FORMAT>(&num, false);
(fp.exp, fp.mant)
}
#[test]
fn computef32_test() {
// Halfway, round-down tests
assert_eq!(compute_float32::<BINARY>(0, 16777216, false), (151, 0));
assert_eq!(compute_float32::<BINARY>(0, 16777217, false), (151, 0));
assert_eq!(compute_float32::<BINARY>(0, 16777218, false), (151, 1));
assert_eq!(compute_float32::<BINARY>(0, 33554432, false), (152, 0));
assert_eq!(compute_float32::<BINARY>(0, 33554434, false), (152, 0));
assert_eq!(compute_float32::<BINARY>(0, 33554436, false), (152, 1));
}
#[test]
fn halfway_round_down_test() {
// Halfway, round-down tests
assert_eq!(compute_float64::<BINARY>(0, 9007199254740992, false), (1076, 0));
assert_eq!(compute_float64::<BINARY>(0, 9007199254740993, false), (1076, 0));
assert_eq!(compute_float64::<BINARY>(0, 9007199254740994, false), (1076, 1));
assert_eq!(compute_float64::<BINARY>(0, 18014398509481984, false), (1077, 0));
assert_eq!(compute_float64::<BINARY>(0, 18014398509481986, false), (1077, 0));
assert_eq!(compute_float64::<BINARY>(0, 18014398509481988, false), (1077, 1));
assert_eq!(compute_float64::<BINARY>(0, 9223372036854775808, false), (1086, 0));
assert_eq!(compute_float64::<BINARY>(0, 9223372036854776832, false), (1086, 0));
assert_eq!(compute_float64::<BINARY>(0, 9223372036854777856, false), (1086, 1));
// Add a 0 but say we're truncated.
assert_eq!(compute_float64::<BINARY>(-10, 9223372036854775808, true), (1076, 0));
assert_eq!(
compute_float64::<BINARY>(-10, 9223372036854776832, true),
(-31703, 9223372036854776832)
);
assert_eq!(compute_float64::<BINARY>(-10, 9223372036854777856, true), (1076, 1));
// Check other bases.
assert_eq!(compute_float64::<BASE4>(-2, 144115188075855872, false), (1076, 0));
assert_eq!(compute_float64::<BASE4>(-2, 144115188075855888, false), (1076, 0));
assert_eq!(compute_float64::<BASE4>(-2, 144115188075855904, false), (1076, 1));
assert_eq!(compute_float64::<OCTAL>(-2, 576460752303423488, false), (1076, 0));
assert_eq!(compute_float64::<OCTAL>(-2, 576460752303423552, false), (1076, 0));
assert_eq!(compute_float64::<OCTAL>(-2, 576460752303423616, false), (1076, 1));
assert_eq!(compute_float64::<HEX>(-1, 144115188075855872, false), (1076, 0));
assert_eq!(compute_float64::<HEX>(-1, 144115188075855888, false), (1076, 0));
assert_eq!(compute_float64::<HEX>(-1, 144115188075855904, false), (1076, 1));
assert_eq!(compute_float64::<BASE32>(-1, 288230376151711744, false), (1076, 0));
assert_eq!(compute_float64::<BASE32>(-1, 288230376151711776, false), (1076, 0));
assert_eq!(compute_float64::<BASE32>(-1, 288230376151711808, false), (1076, 1));
}
#[test]
fn test_halfway_round_up() {
// Halfway, round-up tests
assert_eq!(compute_float64::<BINARY>(0, 9007199254740994, false), (1076, 1));
assert_eq!(compute_float64::<BINARY>(0, 9007199254740995, false), (1076, 2));
assert_eq!(compute_float64::<BINARY>(0, 9007199254740996, false), (1076, 2));
assert_eq!(compute_float64::<BINARY>(0, 18014398509481988, false), (1077, 1));
assert_eq!(compute_float64::<BINARY>(0, 18014398509481990, false), (1077, 2));
assert_eq!(compute_float64::<BINARY>(0, 18014398509481992, false), (1077, 2));
assert_eq!(compute_float64::<BINARY>(0, 9223372036854777856, false), (1086, 1));
assert_eq!(compute_float64::<BINARY>(0, 9223372036854778880, false), (1086, 2));
assert_eq!(compute_float64::<BINARY>(0, 9223372036854779904, false), (1086, 2));
// Add a 0 but say we're truncated.
assert_eq!(compute_float64::<BINARY>(-10, 9223372036854777856, true), (1076, 1));
assert_eq!(compute_float64::<BINARY>(-10, 9223372036854778879, true), (1076, 1));
assert_eq!(compute_float64::<BINARY>(-10, 9223372036854778880, true), (1076, 2));
assert_eq!(compute_float64::<BINARY>(-10, 9223372036854779904, true), (1076, 2));
// Check other bases.
assert_eq!(compute_float64::<BASE4>(-2, 144115188075855904, false), (1076, 1));
assert_eq!(compute_float64::<BASE4>(-2, 144115188075855920, false), (1076, 2));
assert_eq!(compute_float64::<BASE4>(-2, 144115188075855936, false), (1076, 2));
assert_eq!(compute_float64::<OCTAL>(-2, 576460752303423616, false), (1076, 1));
assert_eq!(compute_float64::<OCTAL>(-2, 576460752303423680, false), (1076, 2));
assert_eq!(compute_float64::<OCTAL>(-2, 576460752303423744, false), (1076, 2));
assert_eq!(compute_float64::<HEX>(-1, 144115188075855904, false), (1076, 1));
assert_eq!(compute_float64::<HEX>(-1, 144115188075855920, false), (1076, 2));
assert_eq!(compute_float64::<HEX>(-1, 144115188075855936, false), (1076, 2));
assert_eq!(compute_float64::<BASE32>(-1, 288230376151711808, false), (1076, 1));
assert_eq!(compute_float64::<BASE32>(-1, 288230376151711840, false), (1076, 2));
assert_eq!(compute_float64::<BASE32>(-1, 288230376151711872, false), (1076, 2));
}
fn compute_float64_slow<const FORMAT: u128>(
integer: &[u8],
fraction: Option<&[u8]>,
exponent: i64,
) -> (i32, u64) {
let num = Number {
exponent,
mantissa: 0,
is_negative: false,
many_digits: false,
integer,
fraction,
};
let fp = slow_binary::<f64, FORMAT>(num);
(fp.exp, fp.mant)
}
#[test]
fn test_slow() {
let i = b"100000000000000000000000000000000000000000000000000001";
let f = b"0000000000000";
assert_eq!(compute_float64_slow::<BINARY>(i, Some(f), -10), (1076, 0));
let i = b"100000000000000000000000000000000000000000000000000001";
let f = b"000000000000000000001";
assert_eq!(compute_float64_slow::<BINARY>(i, Some(f), -10), (1076, 1));
let i = b"100000000000000000000000000000000000000000000000000001";
let f = b"000000000000010000000";
assert_eq!(compute_float64_slow::<BINARY>(i, Some(f), -10), (1076, 1));
}
@@ -0,0 +1,165 @@
use lexical_parse_float::float::{self, RawFloat};
use lexical_parse_float::limits::ExactFloat;
use lexical_util::num::Float;
#[test]
fn exponent_fast_path_test() {
assert_eq!(f32::min_exponent_fast_path(10), -10);
assert_eq!(f32::max_exponent_fast_path(10), 10);
assert_eq!(f32::max_exponent_disguised_fast_path(10), 17);
assert_eq!(f64::min_exponent_fast_path(10), -22);
assert_eq!(f64::max_exponent_fast_path(10), 22);
assert_eq!(f64::max_exponent_disguised_fast_path(10), 37);
}
fn slow_f32_power(exponent: usize, radix: u32) -> f32 {
let mut value: f32 = 1.0;
for _ in 0..exponent {
value *= radix as f32;
}
value
}
fn slow_f64_power(exponent: usize, radix: u32) -> f64 {
let mut value: f64 = 1.0;
for _ in 0..exponent {
value *= radix as f64;
}
value
}
fn pow_fast_path(radix: u32) {
for exponent in 0..f32::exponent_limit(radix).1 + 1 {
let exponent = exponent as usize;
let actual = f32::pow_fast_path(exponent, radix);
assert_eq!(actual, slow_f32_power(exponent, radix));
}
for exponent in 0..f64::exponent_limit(radix).1 + 1 {
let exponent = exponent as usize;
let actual = f64::pow_fast_path(exponent, radix);
assert_eq!(actual, slow_f64_power(exponent, radix));
}
}
#[test]
#[cfg_attr(miri, ignore)]
fn pow_fast_path_test() {
pow_fast_path(10);
if cfg!(feature = "power-of-two") {
pow_fast_path(2);
pow_fast_path(4);
pow_fast_path(8);
pow_fast_path(16);
pow_fast_path(32);
}
if cfg!(feature = "radix") {
pow_fast_path(3);
pow_fast_path(5);
pow_fast_path(6);
pow_fast_path(7);
pow_fast_path(9);
pow_fast_path(11);
pow_fast_path(12);
pow_fast_path(13);
pow_fast_path(14);
pow_fast_path(15);
pow_fast_path(17);
pow_fast_path(18);
pow_fast_path(19);
pow_fast_path(20);
pow_fast_path(21);
pow_fast_path(22);
pow_fast_path(23);
pow_fast_path(24);
pow_fast_path(25);
pow_fast_path(26);
pow_fast_path(27);
pow_fast_path(28);
pow_fast_path(29);
pow_fast_path(30);
pow_fast_path(31);
pow_fast_path(33);
pow_fast_path(34);
pow_fast_path(35);
pow_fast_path(36);
}
}
fn slow_int_power(exponent: usize, radix: u32) -> u64 {
let mut value: u64 = 1;
for _ in 0..exponent {
value *= radix as u64;
}
value
}
fn int_pow_fast_path(radix: u32) {
for exponent in 0..f64::mantissa_limit(radix) {
let exponent = exponent as usize;
let actual = f64::int_pow_fast_path(exponent, radix);
assert_eq!(actual, slow_int_power(exponent, radix));
}
}
#[test]
fn int_pow_fast_path_test() {
int_pow_fast_path(10);
if cfg!(feature = "power-of-two") {
int_pow_fast_path(2);
int_pow_fast_path(4);
int_pow_fast_path(8);
int_pow_fast_path(16);
int_pow_fast_path(32);
}
if cfg!(feature = "radix") {
int_pow_fast_path(3);
int_pow_fast_path(5);
int_pow_fast_path(6);
int_pow_fast_path(7);
int_pow_fast_path(9);
int_pow_fast_path(11);
int_pow_fast_path(12);
int_pow_fast_path(13);
int_pow_fast_path(14);
int_pow_fast_path(15);
int_pow_fast_path(17);
int_pow_fast_path(18);
int_pow_fast_path(19);
int_pow_fast_path(20);
int_pow_fast_path(21);
int_pow_fast_path(22);
int_pow_fast_path(23);
int_pow_fast_path(24);
int_pow_fast_path(25);
int_pow_fast_path(26);
int_pow_fast_path(27);
int_pow_fast_path(28);
int_pow_fast_path(29);
int_pow_fast_path(30);
int_pow_fast_path(31);
int_pow_fast_path(33);
int_pow_fast_path(34);
int_pow_fast_path(35);
int_pow_fast_path(36);
}
}
fn extended_to_float<F: RawFloat>(mantissa: u64, exponent: i32, expected: F) {
let fp = float::ExtendedFloat80 {
mant: mantissa,
exp: exponent,
};
assert_eq!(float::extended_to_float::<F>(fp), expected);
}
#[test]
fn extended_to_float_test() {
let max_mant = (1 << f64::MANTISSA_SIZE) - 1;
let max_exp = f64::INFINITE_POWER - 1;
extended_to_float::<f64>(0, 0, 0.0);
extended_to_float::<f64>(1, 0, 5e-324);
extended_to_float::<f64>(max_mant, max_exp, f64::MAX);
extended_to_float::<f64>(0, 1076, 9007199254740992.0);
extended_to_float::<f64>(1, 1076, 9007199254740994.0);
}
@@ -0,0 +1,435 @@
#![cfg(feature = "format")]
use core::num;
use lexical_parse_float::{
Error,
FromLexical,
FromLexicalWithOptions,
NumberFormatBuilder,
Options,
};
use lexical_util::format::STANDARD;
#[test]
fn issue_96_test() {
const OPTS: Options = Options::new();
const NO_CONSECUTIVE: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(true)
.internal_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(false)
.build_strict();
const CONSECUTIVE: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(true)
.internal_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(true)
.build_strict();
const NO_LEADING: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(false)
.internal_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(true)
.build_strict();
let result = f64::from_lexical(b"_-1234");
assert_eq!(result, Err(Error::InvalidDigit(0)));
let result = f64::from_lexical_with_options::<NO_CONSECUTIVE>(b"_-1234", &OPTS);
assert_eq!(result, Err(Error::InvalidDigit(1)));
let result = f64::from_lexical_with_options::<NO_LEADING>(b"^-1234", &OPTS);
assert_eq!(result, Err(Error::InvalidDigit(0)));
// NOTE: This uis correct, since it's "trailing"
let result = f64::from_lexical_with_options::<NO_LEADING>(b"_-1234", &OPTS);
assert_eq!(result, Err(Error::InvalidDigit(1)));
let result = f64::from_lexical_with_options::<NO_LEADING>(b"_1234", &OPTS);
assert_eq!(result, Err(Error::InvalidDigit(0)));
let result = f64::from_lexical_with_options::<NO_LEADING>(b"X1234", &OPTS);
assert_eq!(result, Err(Error::InvalidDigit(0)));
let result = f64::from_lexical_with_options::<NO_CONSECUTIVE>(b"__1__234__", &OPTS);
assert_eq!(result, Err(Error::InvalidDigit(0)));
let result = f64::from_lexical_with_options::<CONSECUTIVE>(b"__1__234__", &OPTS);
assert_eq!(result, Ok(1234f64));
}
#[test]
fn issue_96_i_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.internal_digit_separator(true)
.consecutive_digit_separator(false)
.build_strict();
let result = f64::from_lexical_partial_with_options::<FMT>(b"", &OPTS);
assert_eq!(result, Err(Error::Empty(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1__1_23", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1", &OPTS);
assert_eq!(result, Ok((11f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1_23", &OPTS);
assert_eq!(result, Ok((1123f64, 6)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1__23", &OPTS);
assert_eq!(result, Ok((11f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1_23_", &OPTS);
assert_eq!(result, Ok((1123f64, 6)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1_23.", &OPTS);
assert_eq!(result, Ok((1123f64, 7)));
}
#[test]
fn issue_96_l_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(true)
.consecutive_digit_separator(false)
.build_strict();
let result = f64::from_lexical_partial_with_options::<FMT>(b"", &OPTS);
assert_eq!(result, Err(Error::Empty(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_", &OPTS);
assert_eq!(result, Err(Error::Empty(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_", &OPTS);
assert_eq!(result, Err(Error::Empty(2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_23", &OPTS);
assert_eq!(result, Ok((1f64, 2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_1_23", &OPTS);
assert_eq!(result, Ok((1f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1__1_23", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_+1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
}
#[test]
fn issue_96_t_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.trailing_digit_separator(true)
.consecutive_digit_separator(false)
.build_strict();
let result = f64::from_lexical_partial_with_options::<FMT>(b"", &OPTS);
assert_eq!(result, Err(Error::Empty(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_", &OPTS);
assert_eq!(result, Err(Error::Empty(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_", &OPTS);
assert_eq!(result, Err(Error::Empty(2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1__1_23", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_+1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123_", &OPTS);
assert_eq!(result, Ok((123f64, 5)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123__", &OPTS);
assert_eq!(result, Ok((123f64, 4)));
}
#[test]
fn issue_96_il_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.internal_digit_separator(true)
.leading_digit_separator(true)
.consecutive_digit_separator(false)
.build_strict();
let result = f64::from_lexical_partial_with_options::<FMT>(b"", &OPTS);
assert_eq!(result, Err(Error::Empty(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_", &OPTS);
assert_eq!(result, Err(Error::Empty(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_", &OPTS);
assert_eq!(result, Err(Error::Empty(2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_23", &OPTS);
assert_eq!(result, Ok((123f64, 5)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_1_23", &OPTS);
assert_eq!(result, Ok((123f64, 6)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1__1_23", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1", &OPTS);
assert_eq!(result, Ok((11f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1_", &OPTS);
assert_eq!(result, Ok((11f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_+1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123_", &OPTS);
assert_eq!(result, Ok((123f64, 4)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123__", &OPTS);
assert_eq!(result, Ok((123f64, 4)));
}
#[test]
fn issue_96_it_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.internal_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(false)
.build_strict();
let result = f64::from_lexical_partial_with_options::<FMT>(b"", &OPTS);
assert_eq!(result, Err(Error::Empty(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_", &OPTS);
assert_eq!(result, Err(Error::Empty(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_", &OPTS);
assert_eq!(result, Err(Error::Empty(2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(0)));
let result: Result<(f64, usize), Error> =
f64::from_lexical_partial_with_options::<FMT>(b"+_1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1__1_23", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1", &OPTS);
assert_eq!(result, Ok((11f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1_", &OPTS);
assert_eq!(result, Ok((11f64, 4)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_+1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123_", &OPTS);
assert_eq!(result, Ok((123f64, 5)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123__", &OPTS);
assert_eq!(result, Ok((123f64, 4)));
}
#[test]
fn issue_96_lt_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(false)
.build_strict();
let result = f64::from_lexical_partial_with_options::<FMT>(b"", &OPTS);
assert_eq!(result, Err(Error::Empty(0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_", &OPTS);
assert_eq!(result, Err(Error::Empty(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_", &OPTS);
assert_eq!(result, Err(Error::Empty(2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_23", &OPTS);
assert_eq!(result, Ok((1f64, 2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_1_23", &OPTS);
assert_eq!(result, Ok((1f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1__1_23", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1_", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_11_", &OPTS);
assert_eq!(result, Ok((11f64, 4)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_+1_23", &OPTS);
assert_eq!(result, Err(Error::EmptyMantissa(1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123_", &OPTS);
assert_eq!(result, Ok((123f64, 5)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123__", &OPTS);
assert_eq!(result, Ok((123f64, 4)));
}
#[test]
fn issue_96_no_required_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(false)
.required_digits(false)
.build_strict();
let result = f64::from_lexical_partial_with_options::<FMT>(b"", &OPTS);
assert_eq!(result, Ok((0f64, 0)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_", &OPTS);
assert_eq!(result, Ok((0f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_", &OPTS);
assert_eq!(result, Ok((0f64, 2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_1_23", &OPTS);
assert_eq!(result, Ok((1f64, 2)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+_1_23", &OPTS);
assert_eq!(result, Ok((1f64, 3)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1__1_23", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"1_1_", &OPTS);
assert_eq!(result, Ok((1f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_11_", &OPTS);
assert_eq!(result, Ok((11f64, 4)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"_+1_23", &OPTS);
assert_eq!(result, Ok((0f64, 1)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123_", &OPTS);
assert_eq!(result, Ok((123f64, 5)));
let result = f64::from_lexical_partial_with_options::<FMT>(b"+123__", &OPTS);
assert_eq!(result, Ok((123f64, 4)));
}
#[test]
fn issue_96_rounding_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(true)
.internal_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(true)
.build_strict();
let input = b"0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225073858507200889024586876085859887650423112240959465493524802562440009228235695178775888803759155264230978095043431208587738715835729182199302029437922422355981982750124204178896957131179108226104397197960400045489739193807919893608152561311337614984204327175103362739154978273159414382813627511383860409424946494228631669542910508020181592664213499660651780309507591305871984642390606863710200510872328278467884363194451586613504122347901479236958520832159762106637540161373658304419360371477835530668283453563400507407304013560296804637591858316312422452159926254649430083685186171942241764645513713542013221703137049658321015465406803539741790602258950302350193751977303094576317321085250729930508976158251915";
let result = f32::from_lexical_partial_with_options::<STANDARD>(input, &OPTS);
assert_eq!(result, Ok((0f32, input.len())));
let result = f32::from_lexical_partial_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok((0f32, input.len())));
let result = f64::from_lexical_partial_with_options::<STANDARD>(input, &OPTS);
assert_eq!(result, Ok((2.225073858507201e-308f64, input.len())));
let result = f64::from_lexical_partial_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok((2.225073858507201e-308f64, input.len())));
let input = b"_0e+___00";
let result = f32::from_lexical_partial_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok((0f32, input.len())));
let result = f32::from_lexical_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok(0f32));
let result = f64::from_lexical_partial_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok((0f64, input.len())));
let result = f64::from_lexical_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok(0f64));
let input = b"323081493377685546875e-297";
let result = f64::from_lexical_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok(3.2308149337768557e-277));
let input = b"32308_1493_3776_8554_6875e-297";
let result = f64::from_lexical_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok(3.2308149337768557e-277));
}
#[test]
fn issue_96_wuff_test() {
const OPTS: Options = Options::new();
const FMT: u128 = NumberFormatBuilder::new()
.digit_separator(num::NonZeroU8::new(b'_'))
.leading_digit_separator(true)
.internal_digit_separator(true)
.trailing_digit_separator(true)
.consecutive_digit_separator(true)
.build_strict();
let input = b"0.000061094760894775390625";
let result = f32::from_lexical_partial_with_options::<STANDARD>(input, &OPTS);
assert_eq!(result, Ok((6.109476e-5f32, input.len())));
let result = f64::from_lexical_partial_with_options::<STANDARD>(input, &OPTS);
assert_eq!(result, Ok((6.109476089477539e-5, input.len())));
let input = b"0_.0000610_9476_0894775390_625";
let result = f32::from_lexical_partial_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok((6.109476e-5f32, input.len())));
let result = f64::from_lexical_partial_with_options::<FMT>(input, &OPTS);
assert_eq!(result, Ok((6.109476089477539e-5, input.len())));
}
@@ -0,0 +1,67 @@
#![cfg(all(feature = "power-of-two", feature = "format"))]
use std::assert_eq;
use lexical_parse_float::FromLexicalWithOptions;
use lexical_parse_float::NumberFormatBuilder;
use lexical_parse_float::Options;
use lexical_util::error::Error;
#[test]
fn issue_98_test() {
const DECIMAL_FORMAT: u128 = NumberFormatBuilder::new()
.required_digits(true)
.no_positive_mantissa_sign(false)
.no_special(true)
.no_integer_leading_zeros(true)
.no_float_leading_zeros(true)
.build_strict();
let result = f64::from_lexical_with_options::<DECIMAL_FORMAT>(b"1.1.0", &Options::new());
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::InvalidDigit(3));
assert_eq!(
f64::from_lexical_partial_with_options::<DECIMAL_FORMAT>(b"1.1.0", &Options::new()),
Ok((1.1f64, 3))
);
assert_eq!(
f64::from_lexical_with_options::<DECIMAL_FORMAT>(b"1.1", &Options::new()),
Ok(1.1f64)
);
assert_eq!(
f64::from_lexical_partial_with_options::<DECIMAL_FORMAT>(b"1.1", &Options::new()),
Ok((1.1f64, 3))
);
let result = f64::from_lexical_with_options::<DECIMAL_FORMAT>(b"0.1.0", &Options::new());
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::InvalidDigit(3));
assert_eq!(
f64::from_lexical_partial_with_options::<DECIMAL_FORMAT>(b"0.1.0", &Options::new()),
Ok((0.1f64, 3))
);
assert_eq!(
f64::from_lexical_with_options::<DECIMAL_FORMAT>(b"0.1", &Options::new()),
Ok(0.1f64)
);
assert_eq!(
f64::from_lexical_partial_with_options::<DECIMAL_FORMAT>(b"0.1", &Options::new()),
Ok((0.1f64, 3))
);
let result = f64::from_lexical_with_options::<DECIMAL_FORMAT>(b"01.1.0", &Options::new());
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::InvalidLeadingZeros(0));
let result = f64::from_lexical_with_options::<DECIMAL_FORMAT>(b"00.1", &Options::new());
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::InvalidLeadingZeros(0));
assert_eq!(
f64::from_lexical_partial_with_options::<DECIMAL_FORMAT>(b"10.1", &Options::new()),
Ok((10.1, 4))
);
assert_eq!(
f64::from_lexical_partial_with_options::<DECIMAL_FORMAT>(b"11.1", &Options::new()),
Ok((11.1, 4))
);
}
@@ -0,0 +1,309 @@
//! These tests are adapted from the Rust core library's unittests.
#![cfg(not(feature = "compact"))]
use lexical_parse_float::lemire;
use lexical_parse_float::shared::INVALID_FP;
fn compute_error32(q: i64, w: u64) -> (i32, u64) {
let fp = lemire::compute_error::<f32>(q, w);
(fp.exp, fp.mant)
}
fn compute_error64(q: i64, w: u64) -> (i32, u64) {
let fp = lemire::compute_error::<f64>(q, w);
(fp.exp, fp.mant)
}
fn compute_error_scaled32(q: i64, w: u64, lz: i32) -> (i32, u64) {
let fp = lemire::compute_error_scaled::<f32>(q, w, lz);
(fp.exp, fp.mant)
}
fn compute_error_scaled64(q: i64, w: u64, lz: i32) -> (i32, u64) {
let fp = lemire::compute_error_scaled::<f64>(q, w, lz);
(fp.exp, fp.mant)
}
fn compute_float32(q: i64, w: u64) -> (i32, u64) {
let fp = lemire::compute_float::<f32>(q, w, false);
(fp.exp, fp.mant)
}
fn compute_float64(q: i64, w: u64) -> (i32, u64) {
let fp = lemire::compute_float::<f64>(q, w, false);
(fp.exp, fp.mant)
}
#[test]
fn compute_error32_test() {
// These test near-halfway cases for single-precision floats.
assert_eq!(compute_error32(0, 16777216), (111 + INVALID_FP, 9223372036854775808));
assert_eq!(compute_error32(0, 16777217), (111 + INVALID_FP, 9223372586610589696));
assert_eq!(compute_error32(0, 16777218), (111 + INVALID_FP, 9223373136366403584));
assert_eq!(compute_error32(0, 16777219), (111 + INVALID_FP, 9223373686122217472));
assert_eq!(compute_error32(0, 16777220), (111 + INVALID_FP, 9223374235878031360));
// These are examples of the above tests, with
// digits from the exponent shifted to the mantissa.
assert_eq!(compute_error32(-10, 167772160000000000), (111 + INVALID_FP, 9223372036854775808));
assert_eq!(compute_error32(-10, 167772170000000000), (111 + INVALID_FP, 9223372586610589696));
assert_eq!(compute_error32(-10, 167772180000000000), (111 + INVALID_FP, 9223373136366403584));
// Let's check the lines to see if anything is different in table...
assert_eq!(compute_error32(-10, 167772190000000000), (111 + INVALID_FP, 9223373686122217472));
assert_eq!(compute_error32(-10, 167772200000000000), (111 + INVALID_FP, 9223374235878031360));
}
#[test]
fn compute_error64_test() {
// These test near-halfway cases for double-precision floats.
assert_eq!(compute_error64(0, 9007199254740992), (1065 + INVALID_FP, 9223372036854775808));
assert_eq!(compute_error64(0, 9007199254740993), (1065 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_error64(0, 9007199254740994), (1065 + INVALID_FP, 9223372036854777856));
assert_eq!(compute_error64(0, 9007199254740995), (1065 + INVALID_FP, 9223372036854778880));
assert_eq!(compute_error64(0, 9007199254740996), (1065 + INVALID_FP, 9223372036854779904));
assert_eq!(compute_error64(0, 18014398509481984), (1066 + INVALID_FP, 9223372036854775808));
assert_eq!(compute_error64(0, 18014398509481986), (1066 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_error64(0, 18014398509481988), (1066 + INVALID_FP, 9223372036854777856));
assert_eq!(compute_error64(0, 18014398509481990), (1066 + INVALID_FP, 9223372036854778880));
assert_eq!(compute_error64(0, 18014398509481992), (1066 + INVALID_FP, 9223372036854779904));
// Test a much closer set of examples.
assert_eq!(compute_error64(0, 9007199254740991), (1064 + INVALID_FP, 18446744073709549568));
assert_eq!(compute_error64(0, 9223372036854776831), (1075 + INVALID_FP, 9223372036854776830));
assert_eq!(compute_error64(0, 9223372036854776832), (1075 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_error64(0, 9223372036854776833), (1075 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_error64(-42, 9123456727292927), (925 + INVALID_FP, 13021432563531497894));
assert_eq!(compute_error64(-43, 91234567272929275), (925 + INVALID_FP, 13021432563531498606));
assert_eq!(compute_error64(-42, 9123456727292928), (925 + INVALID_FP, 13021432563531499320));
// These are examples of the above tests, with
// digits from the exponent shifted to the mantissa.
assert_eq!(compute_error64(-3, 9007199254740992000), (1065 + INVALID_FP, 9223372036854775808));
assert_eq!(compute_error64(-3, 9007199254740993000), (1065 + INVALID_FP, 9223372036854776832));
assert_eq!(compute_error64(-3, 9007199254740994000), (1065 + INVALID_FP, 9223372036854777856));
assert_eq!(compute_error64(-3, 9007199254740995000), (1065 + INVALID_FP, 9223372036854778880));
assert_eq!(compute_error64(-3, 9007199254740996000), (1065 + INVALID_FP, 9223372036854779904));
// Test from errors in atof.
assert_eq!(compute_error64(-18, 1000000178813934326), (1012 + INVALID_FP, 9223373686122217470));
// Check edge-cases from previous errors.
assert_eq!(
compute_error64(-342, 2470328229206232720),
(-64 + INVALID_FP, 18446744073709551608)
);
}
#[test]
fn compute_error_scaled32_test() {
// These are the same examples above, just using pre-computed scaled values.
// These test near-halfway cases for single-precision floats.
assert_eq!(
compute_error_scaled32(0, 4611686018427387904, 39),
(111 + INVALID_FP, 9223372036854775808)
);
assert_eq!(
compute_error_scaled32(0, 4611686293305294848, 39),
(111 + INVALID_FP, 9223372586610589696)
);
assert_eq!(
compute_error_scaled32(0, 4611686568183201792, 39),
(111 + INVALID_FP, 9223373136366403584)
);
assert_eq!(
compute_error_scaled32(0, 4611686843061108736, 39),
(111 + INVALID_FP, 9223373686122217472)
);
assert_eq!(
compute_error_scaled32(0, 4611687117939015680, 39),
(111 + INVALID_FP, 9223374235878031360)
);
assert_eq!(
compute_error_scaled32(-10, 9223372036854775808, 6),
(111 + INVALID_FP, 9223372036854775808)
);
assert_eq!(
compute_error_scaled32(-10, 9223372586610589696, 6),
(111 + INVALID_FP, 9223372586610589696)
);
assert_eq!(
compute_error_scaled32(-10, 9223373136366403584, 6),
(111 + INVALID_FP, 9223373136366403584)
);
assert_eq!(
compute_error_scaled32(-10, 9223373686122217472, 6),
(111 + INVALID_FP, 9223373686122217472)
);
assert_eq!(
compute_error_scaled32(-10, 9223374235878031360, 6),
(111 + INVALID_FP, 9223374235878031360)
);
}
#[test]
fn compute_error_scaled64_test() {
// These are the same examples above, just using pre-computed scaled values.
// These test near-halfway cases for double-precision floats.
assert_eq!(
compute_error_scaled64(0, 4611686018427387904, 10),
(1065 + INVALID_FP, 9223372036854775808)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427388416, 10),
(1065 + INVALID_FP, 9223372036854776832)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427388928, 10),
(1065 + INVALID_FP, 9223372036854777856)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427389440, 10),
(1065 + INVALID_FP, 9223372036854778880)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427389952, 10),
(1065 + INVALID_FP, 9223372036854779904)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427387904, 9),
(1066 + INVALID_FP, 9223372036854775808)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427388416, 9),
(1066 + INVALID_FP, 9223372036854776832)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427388928, 9),
(1066 + INVALID_FP, 9223372036854777856)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427389440, 9),
(1066 + INVALID_FP, 9223372036854778880)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427389952, 9),
(1066 + INVALID_FP, 9223372036854779904)
);
// Test a much closer set of examples.
assert_eq!(
compute_error_scaled64(0, 9223372036854774784, 11),
(1064 + INVALID_FP, 18446744073709549568)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427388415, 0),
(1075 + INVALID_FP, 9223372036854776830)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427388416, 0),
(1075 + INVALID_FP, 9223372036854776832)
);
assert_eq!(
compute_error_scaled64(0, 4611686018427388416, 0),
(1075 + INVALID_FP, 9223372036854776832)
);
assert_eq!(
compute_error_scaled64(-42, 6510716281765748947, 10),
(925 + INVALID_FP, 13021432563531497894)
);
assert_eq!(
compute_error_scaled64(-43, 6510716281765749303, 7),
(925 + INVALID_FP, 13021432563531498606)
);
assert_eq!(
compute_error_scaled64(-42, 6510716281765749660, 10),
(925 + INVALID_FP, 13021432563531499320)
);
// These are examples of the above tests, with
// digits from the exponent shifted to the mantissa.
assert_eq!(
compute_error_scaled64(-3, 9223372036854775808, 1),
(1065 + INVALID_FP, 9223372036854775808)
);
assert_eq!(
compute_error_scaled64(-3, 9223372036854776832, 1),
(1065 + INVALID_FP, 9223372036854776832)
);
assert_eq!(
compute_error_scaled64(-3, 9223372036854777856, 1),
(1065 + INVALID_FP, 9223372036854777856)
);
assert_eq!(
compute_error_scaled64(-3, 9223372036854778880, 1),
(1065 + INVALID_FP, 9223372036854778880)
);
assert_eq!(
compute_error_scaled64(-3, 9223372036854779904, 1),
(1065 + INVALID_FP, 9223372036854779904)
);
// Test from errors in atof.
assert_eq!(
compute_error_scaled64(-18, 9223373686122217470, 4),
(1012 + INVALID_FP, 9223373686122217470)
);
// Check edge-cases from previous errors.
assert_eq!(
compute_error_scaled64(-342, 9223372036854775804, 2),
(-64 + INVALID_FP, 18446744073709551608)
);
}
#[test]
fn compute_float_f32_rounding() {
// These test near-halfway cases for single-precision floats.
assert_eq!(compute_float32(0, 16777216), (151, 0));
assert_eq!(compute_float32(0, 16777217), (151, 0));
assert_eq!(compute_float32(0, 16777218), (151, 1));
assert_eq!(compute_float32(0, 16777219), (151, 2));
assert_eq!(compute_float32(0, 16777220), (151, 2));
// These are examples of the above tests, with
// digits from the exponent shifted to the mantissa.
assert_eq!(compute_float32(-10, 167772160000000000), (151, 0));
assert_eq!(compute_float32(-10, 167772170000000000), (151, 0));
assert_eq!(compute_float32(-10, 167772180000000000), (151, 1));
// Let's check the lines to see if anything is different in table...
assert_eq!(compute_float32(-10, 167772190000000000), (151, 2));
assert_eq!(compute_float32(-10, 167772200000000000), (151, 2));
}
#[test]
fn compute_float_f64_rounding() {
// Also need to check halfway cases **inside** that exponent range.
// These test near-halfway cases for double-precision floats.
assert_eq!(compute_float64(0, 9007199254740992), (1076, 0));
assert_eq!(compute_float64(0, 9007199254740993), (1076, 0));
assert_eq!(compute_float64(0, 9007199254740994), (1076, 1));
assert_eq!(compute_float64(0, 9007199254740995), (1076, 2));
assert_eq!(compute_float64(0, 9007199254740996), (1076, 2));
assert_eq!(compute_float64(0, 18014398509481984), (1077, 0));
assert_eq!(compute_float64(0, 18014398509481986), (1077, 0));
assert_eq!(compute_float64(0, 18014398509481988), (1077, 1));
assert_eq!(compute_float64(0, 18014398509481990), (1077, 2));
assert_eq!(compute_float64(0, 18014398509481992), (1077, 2));
// Test a much closer set of examples.
assert_eq!(compute_float64(0, 9007199254740991), (1075, 4503599627370495));
assert_eq!(compute_float64(0, 9223372036854776831), (1086, 0));
assert_eq!(compute_float64(0, 9223372036854776832), (1086, 0));
assert_eq!(compute_float64(0, 9223372036854776833), (1086, 1));
assert_eq!(compute_float64(-42, 9123456727292927), (936, 1854521741541368));
assert_eq!(compute_float64(-43, 91234567272929275), (936, 1854521741541369));
assert_eq!(compute_float64(-42, 9123456727292928), (936, 1854521741541369));
// These are examples of the above tests, with
// digits from the exponent shifted to the mantissa.
assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0));
assert_eq!(compute_float64(-3, 9007199254740993000), (1076, 0));
assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1));
assert_eq!(compute_float64(-3, 9007199254740995000), (1076, 2));
assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2));
}
@@ -0,0 +1,292 @@
#![cfg(all(not(feature = "std"), feature = "compact"))]
// These are adapted from libm, a port of musl libc's libm to Rust.
// libm can be found online [here](https://github.com/rust-lang/libm),
// and is similarly licensed under an Apache2.0/MIT license
use core::f64;
use lexical_parse_float::libm;
#[test]
fn fabsf_sanity_test() {
assert_eq!(libm::fabsf(-1.0), 1.0);
assert_eq!(libm::fabsf(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn fabsf_spec_test() {
assert!(libm::fabsf(f32::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(libm::fabsf(f), 0.0);
}
for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() {
assert_eq!(libm::fabsf(f), f32::INFINITY);
}
}
#[test]
fn sqrtf_sanity_test() {
assert_eq!(libm::sqrtf(100.0), 10.0);
assert_eq!(libm::sqrtf(4.0), 2.0);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt
#[test]
fn sqrtf_spec_test() {
// Not Asserted: FE_INVALID exception is raised if argument is negative.
assert!(libm::sqrtf(-1.0).is_nan());
assert!(libm::sqrtf(f32::NAN).is_nan());
for f in [0.0, -0.0, f32::INFINITY].iter().copied() {
assert_eq!(libm::sqrtf(f), f);
}
}
const POS_ZERO: &[f64] = &[0.0];
const NEG_ZERO: &[f64] = &[-0.0];
const POS_ONE: &[f64] = &[1.0];
const NEG_ONE: &[f64] = &[-1.0];
const POS_FLOATS: &[f64] = &[99.0 / 70.0, f64::consts::E, f64::consts::PI];
const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -f64::consts::E, -f64::consts::PI];
const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON];
const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON];
const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX];
const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0];
const POS_ODDS: &[f64] = &[3.0, 7.0];
const NEG_ODDS: &[f64] = &[-7.0, -3.0];
const NANS: &[f64] = &[f64::NAN];
const POS_INF: &[f64] = &[f64::INFINITY];
const NEG_INF: &[f64] = &[f64::NEG_INFINITY];
const ALL: &[&[f64]] = &[
POS_ZERO,
NEG_ZERO,
NANS,
NEG_SMALL_FLOATS,
POS_SMALL_FLOATS,
NEG_FLOATS,
POS_FLOATS,
NEG_EVENS,
POS_EVENS,
NEG_ODDS,
POS_ODDS,
NEG_INF,
POS_INF,
NEG_ONE,
POS_ONE,
];
const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF];
const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF];
fn powd(base: f64, exponent: f64, expected: f64) {
let res = libm::powd(base, exponent);
assert!(
if expected.is_nan() {
res.is_nan()
} else {
libm::powd(base, exponent) == expected
},
"{} ** {} was {} instead of {}",
base,
exponent,
res,
expected
);
}
fn powd_test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) {
sets.iter().for_each(|s| s.iter().for_each(|val| powd(*val, exponent, expected)));
}
fn powd_test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) {
sets.iter().for_each(|s| s.iter().for_each(|val| powd(base, *val, expected)));
}
fn powd_test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) {
sets.iter().for_each(|s| {
s.iter().for_each(|val| {
let exp = expected(*val);
let res = computed(*val);
assert!(
if exp.is_nan() {
res.is_nan()
} else {
exp == res
},
"test for {} was {} instead of {}",
val,
res,
exp
);
})
});
}
#[test]
fn powd_zero_as_exponent() {
powd_test_sets_as_base(ALL, 0.0, 1.0);
powd_test_sets_as_base(ALL, -0.0, 1.0);
}
#[test]
fn powd_one_as_base() {
powd_test_sets_as_exponent(1.0, ALL, 1.0);
}
#[test]
fn powd_nan_inputs() {
// NAN as the base:
// (NAN ^ anything *but 0* should be NAN)
powd_test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN);
// NAN as the exponent:
// (anything *but 1* ^ NAN should be NAN)
powd_test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN);
}
#[test]
fn powd_infinity_as_base() {
// Positive Infinity as the base:
// (+Infinity ^ positive anything but 0 and NAN should be +Infinity)
powd_test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY);
// (+Infinity ^ negative anything except 0 and NAN should be 0.0)
powd_test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0);
// Negative Infinity as the base:
// (-Infinity ^ positive odd ints should be -Infinity)
powd_test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY);
// (-Infinity ^ anything but odd ints should be == -0 ^ (-anything))
// We can lump in pos/neg odd ints here because they don't seem to
// cause panics (div by zero) in release mode (I think).
powd_test_sets(ALL, &|v: f64| libm::powd(f64::NEG_INFINITY, v), &|v: f64| libm::powd(-0.0, -v));
}
#[test]
fn infinity_as_exponent() {
// Positive/Negative base greater than 1:
// (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the
// base)
powd_test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY);
// (pos/neg > 1 ^ -Infinity should be 0.0)
powd_test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0);
// Positive/Negative base less than 1:
let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS];
// (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base)
powd_test_sets_as_base(base_below_one, f64::INFINITY, 0.0);
// (pos/neg < 1 ^ -Infinity should be Infinity)
powd_test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY);
// Positive/Negative 1 as the base:
// (pos/neg 1 ^ Infinity should be 1)
powd_test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0);
// (pos/neg 1 ^ -Infinity should be 1)
powd_test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0);
}
#[test]
fn powd_zero_as_base() {
// Positive Zero as the base:
// (+0 ^ anything positive but 0 and NAN should be +0)
powd_test_sets_as_exponent(0.0, &POS[1..], 0.0);
// (+0 ^ anything negative but 0 and NAN should be Infinity)
// (this should panic because we're dividing by zero)
powd_test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY);
// Negative Zero as the base:
// (-0 ^ anything positive but 0, NAN, and odd ints should be +0)
powd_test_sets_as_exponent(-0.0, &POS[3..], 0.0);
// (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity)
// (should panic because of divide by zero)
powd_test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY);
// (-0 ^ positive odd ints should be -0)
powd_test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0);
// (-0 ^ negative odd ints should be -Infinity)
// (should panic because of divide by zero)
powd_test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY);
}
#[test]
fn special_cases() {
// One as the exponent:
// (anything ^ 1 should be anything - i.e. the base)
powd_test_sets(ALL, &|v: f64| libm::powd(v, 1.0), &|v: f64| v);
// Negative One as the exponent:
// (anything ^ -1 should be 1/anything)
powd_test_sets(ALL, &|v: f64| libm::powd(v, -1.0), &|v: f64| 1.0 / v);
// Factoring -1 out:
// (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^
// integer))
[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| {
int_set.iter().for_each(|int| {
powd_test_sets(ALL, &|v: f64| libm::powd(-v, *int), &|v: f64| {
libm::powd(-1.0, *int) * libm::powd(v, *int)
});
})
});
// Negative base (imaginary results):
// (-anything except 0 and Infinity ^ non-integer should be NAN)
NEG[1..(NEG.len() - 1)].iter().for_each(|set| {
set.iter().for_each(|val| {
powd_test_sets(&ALL[3..7], &|v: f64| libm::powd(*val, v), &|_| f64::NAN);
})
});
}
#[test]
fn normal_cases() {
assert_eq!(libm::powd(2.0, 20.0), (1 << 20) as f64);
assert_eq!(libm::powd(-1.0, 9.0), -1.0);
assert!(libm::powd(-1.0, 2.2).is_nan());
assert!(libm::powd(-1.0, -1.14).is_nan());
}
#[test]
fn fabsd_sanity_test() {
assert_eq!(libm::fabsd(-1.0), 1.0);
assert_eq!(libm::fabsd(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn fabsd_spec_test() {
assert!(libm::fabsd(f64::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(libm::fabsd(f), 0.0);
}
for f in [f64::INFINITY, f64::NEG_INFINITY].iter().copied() {
assert_eq!(libm::fabsd(f), f64::INFINITY);
}
}
#[test]
fn sqrtd_sanity_test() {
assert_eq!(libm::sqrtd(100.0), 10.0);
assert_eq!(libm::sqrtd(4.0), 2.0);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt
#[test]
fn sqrtd_spec_test() {
// Not Asserted: FE_INVALID exception is raised if argument is negative.
assert!(libm::sqrtd(-1.0).is_nan());
assert!(libm::sqrtd(f64::NAN).is_nan());
for f in [0.0, -0.0, f64::INFINITY].iter().copied() {
assert_eq!(libm::sqrtd(f), f);
}
}
@@ -0,0 +1,27 @@
use lexical_parse_float::limits::{self, ExactFloat, MaxDigits};
#[test]
fn mantissa_limit_test() {
assert_eq!(f32::mantissa_limit(10), 7);
assert_eq!(f64::mantissa_limit(10), 15);
}
#[test]
fn exponent_limit_test() {
assert_eq!(f32::exponent_limit(10), (-10, 10));
assert_eq!(f64::exponent_limit(10), (-22, 22));
}
#[test]
fn power_limit_test() {
assert_eq!(limits::u32_power_limit(5), 13);
assert_eq!(limits::u32_power_limit(10), 9);
assert_eq!(limits::u64_power_limit(5), 27);
assert_eq!(limits::u64_power_limit(10), 19);
}
#[test]
fn max_digit_test() {
assert_eq!(f32::max_digits(10), Some(114));
assert_eq!(f64::max_digits(10), Some(769));
}
@@ -0,0 +1,16 @@
use lexical_parse_float::mask;
#[test]
fn lower_n_mask_test() {
assert_eq!(mask::lower_n_mask(2), 0b11);
}
#[test]
fn lower_n_halfway_test() {
assert_eq!(mask::lower_n_halfway(2), 0b10);
}
#[test]
fn nth_bit_test() {
assert_eq!(mask::nth_bit(2), 0b100);
}
@@ -0,0 +1,95 @@
use lexical_parse_float::number::Number;
use lexical_util::format::STANDARD;
#[test]
fn is_fast_path_test() {
let mut number = Number {
exponent: -4,
mantissa: 12345,
is_negative: false,
many_digits: false,
integer: &[],
fraction: None,
};
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), true);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), true);
number.exponent = -15;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), true);
number.exponent = -25;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), false);
number.exponent = 25;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), true);
number.exponent = 36;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), true);
number.exponent = 38;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), false);
number.mantissa = 1 << 25;
number.exponent = 0;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), true);
number.mantissa = 1 << 54;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), false);
number.mantissa = 1 << 52;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), true);
number.many_digits = true;
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), false);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), false);
}
#[test]
fn try_fast_path_test() {
let mut number = Number {
exponent: -4,
mantissa: 12345,
is_negative: false,
many_digits: false,
integer: &[],
fraction: None,
};
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), Some(1.2345));
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), Some(1.2345));
number.exponent = -10;
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), Some(1.2345e-6));
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), Some(1.2345e-6));
number.exponent = -20;
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), None);
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), Some(1.2345e-16));
number.exponent = -25;
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), None);
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), None);
number.exponent = 12;
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), Some(1.2345e16));
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), Some(1.2345e16));
number.exponent = 25;
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), None);
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), Some(1.2345e29));
number.exponent = 32;
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), None);
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), Some(1.2345e36));
number.exponent = 36;
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), None);
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), None);
}
@@ -0,0 +1,135 @@
use lexical_parse_float::options::{Options, OptionsBuilder};
#[test]
fn invalid_exponent_test() {
let mut builder = OptionsBuilder::default();
builder = builder.exponent(b'\x00');
assert!(!builder.is_valid());
builder = builder.exponent(b'\x7f');
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.exponent(b'^');
assert!(builder.is_valid());
assert!(builder.build().is_ok());
}
#[test]
fn invalid_decimal_point_test() {
let mut builder = OptionsBuilder::default();
builder = builder.decimal_point(b'\x00');
assert!(!builder.is_valid());
builder = builder.decimal_point(b'\x7f');
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.decimal_point(b',');
assert!(builder.is_valid());
assert!(builder.build().is_ok());
}
#[test]
fn invalid_nan_test() {
let mut builder = OptionsBuilder::default();
builder = builder.nan_string(Some(b"naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaan"));
assert!(!builder.is_valid());
builder = builder.nan_string(Some(b"inf"));
assert!(!builder.is_valid());
builder = builder.nan_string(Some(b"na00n"));
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.nan_string(Some(b"nan"));
assert!(builder.is_valid());
assert!(builder.build().is_ok());
builder = builder.nan_string(None);
assert!(builder.is_valid());
}
#[test]
fn invalid_inf_test() {
let mut builder = OptionsBuilder::default();
builder = builder.inf_string(Some(b"innnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnf"));
assert!(!builder.is_valid());
builder = builder.inf_string(Some(b"nan"));
assert!(!builder.is_valid());
builder = builder.inf_string(Some(b"in00f"));
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.inf_string(Some(b"i"));
assert!(builder.is_valid());
builder = builder.inf_string(Some(b"inf"));
assert!(builder.is_valid());
assert!(builder.build().is_ok());
builder = builder.inf_string(None);
assert!(builder.is_valid());
builder = builder.infinity_string(None);
assert!(builder.is_valid());
}
#[test]
fn invalid_infinity_test() {
let mut builder = OptionsBuilder::default();
builder =
builder.infinity_string(Some(b"innnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnf"));
assert!(!builder.is_valid());
builder = builder.infinity_string(Some(b"nan"));
assert!(!builder.is_valid());
builder = builder.infinity_string(Some(b"i"));
assert!(!builder.is_valid());
builder = builder.inf_string(Some(b"infi000nity"));
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.inf_string(Some(b"i"));
assert!(builder.is_valid());
builder = builder.infinity_string(Some(b"infinity"));
assert!(builder.is_valid());
assert!(builder.build().is_ok());
builder = builder.infinity_string(None);
assert!(!builder.is_valid());
builder = builder.inf_string(None);
assert!(builder.is_valid());
}
#[test]
fn builder_test() {
let mut builder = OptionsBuilder::default();
builder = builder.lossy(true);
builder = builder.exponent(b'^');
builder = builder.decimal_point(b',');
builder = builder.nan_string(Some(b"nan"));
builder = builder.inf_string(Some(b"Infinity"));
builder = builder.infinity_string(Some(b"Infiniiiiiity"));
assert_eq!(builder.get_lossy(), true);
assert_eq!(builder.get_exponent(), b'^');
assert_eq!(builder.get_decimal_point(), b',');
assert_eq!(builder.get_nan_string(), Some("nan".as_bytes()));
assert_eq!(builder.get_inf_string(), Some("Infinity".as_bytes()));
assert_eq!(builder.get_infinity_string(), Some("Infiniiiiiity".as_bytes()));
assert!(builder.is_valid());
assert_eq!(builder.build(), Ok(builder.build_unchecked()));
}
#[test]
#[allow(deprecated)]
fn options_test() {
let mut opts = Options::new();
opts.set_lossy(true);
opts.set_exponent(b'^');
opts.set_decimal_point(b',');
opts.set_nan_string(Some(b"nan"));
opts.set_inf_string(Some(b"Infinity"));
opts.set_infinity_string(Some(b"Infiniiiiiity"));
assert_eq!(opts.lossy(), true);
assert_eq!(opts.exponent(), b'^');
assert_eq!(opts.decimal_point(), b',');
assert_eq!(opts.nan_string(), Some("nan".as_bytes()));
assert_eq!(opts.inf_string(), Some("Infinity".as_bytes()));
assert_eq!(opts.infinity_string(), Some("Infiniiiiiity".as_bytes()));
assert!(opts.is_valid());
assert_eq!(Options::builder(), OptionsBuilder::new());
assert_eq!(opts.rebuild().build(), Ok(opts));
}
@@ -0,0 +1,267 @@
use lexical_parse_float::options::Options;
use lexical_parse_float::parse;
use lexical_util::format::STANDARD;
use lexical_util::iterator::AsBytes;
use lexical_util::step::u64_step;
#[test]
fn parse_complete_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let string = b"1.2345e10";
let result = parse::parse_complete::<f64, FORMAT>(string, &OPTIONS);
assert_eq!(result, Ok(1.2345e10));
let string = b"1.2345e";
let result = parse::parse_complete::<f64, FORMAT>(string, &OPTIONS);
assert!(result.is_err());
let string = b"1.2345 ";
let result = parse::parse_complete::<f64, FORMAT>(string, &OPTIONS);
assert!(result.is_err());
}
#[test]
fn fast_path_complete_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let string = b"1.2345e10";
let result = parse::fast_path_complete::<f64, FORMAT>(string, &OPTIONS);
assert_eq!(result, Ok(1.2345e10));
let string = b"1.2345e";
let result = parse::fast_path_complete::<f64, FORMAT>(string, &OPTIONS);
assert!(result.is_err());
let string = b"1.2345 ";
let result = parse::fast_path_complete::<f64, FORMAT>(string, &OPTIONS);
assert!(result.is_err());
}
#[test]
fn parse_partial_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let string = b"1.2345e10";
let result = parse::parse_partial::<f64, FORMAT>(string, &OPTIONS);
assert_eq!(result, Ok((1.2345e10, 9)));
let string = b"1.2345e";
let result = parse::parse_partial::<f64, FORMAT>(string, &OPTIONS);
assert!(result.is_err());
let string = b"1.2345 ";
let result = parse::parse_partial::<f64, FORMAT>(string, &OPTIONS);
assert_eq!(result, Ok((1.2345, 6)));
}
#[test]
fn fast_path_partial_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let string = b"1.2345e10";
let result = parse::fast_path_partial::<f64, FORMAT>(string, &OPTIONS);
assert_eq!(result, Ok((1.2345e10, 9)));
let string = b"1.2345e";
let result = parse::fast_path_partial::<f64, FORMAT>(string, &OPTIONS);
assert!(result.is_err());
let string = b"1.2345 ";
let result = parse::fast_path_partial::<f64, FORMAT>(string, &OPTIONS);
assert_eq!(result, Ok((1.2345, 6)));
}
#[test]
fn parse_number_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let string = b"1.2345e10";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_complete_number(byte, false, &OPTIONS);
assert!(result.is_ok());
let num = result.unwrap();
assert_eq!(num.mantissa, 12345);
assert_eq!(num.exponent, 6);
assert_eq!(num.many_digits, false);
let string = b"1.2345e";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_complete_number(byte, false, &OPTIONS);
assert!(result.is_err());
let string = b"1.2345 ";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_complete_number(byte, false, &OPTIONS);
assert!(result.is_err());
}
#[test]
fn parse_partial_number_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let string = b"1.2345e10";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_partial_number(byte, false, &OPTIONS);
assert!(result.is_ok());
let (num, count) = result.unwrap();
assert_eq!(num.mantissa, 12345);
assert_eq!(num.exponent, 6);
assert_eq!(num.many_digits, false);
assert_eq!(count, 9);
let string = b"1.2345e";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_partial_number(byte, false, &OPTIONS);
assert!(result.is_err());
let string = b"1.2345 ";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_partial_number(byte, false, &OPTIONS);
assert!(result.is_ok());
let (num, count) = result.unwrap();
assert_eq!(num.mantissa, 12345);
assert_eq!(num.exponent, -4);
assert_eq!(num.many_digits, false);
assert_eq!(count, 6);
// Leading zeros
let string = b"00000000000000000000001.2345 ";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_partial_number(byte, false, &OPTIONS);
assert!(result.is_ok());
let (num, count) = result.unwrap();
assert_eq!(num.mantissa, 12345);
assert_eq!(num.exponent, -4);
assert_eq!(num.many_digits, false);
assert_eq!(count, 28);
// Leading zeros
let string = b"0.00000000000000000000012345 ";
let byte = string.bytes::<{ FORMAT }>();
let result = parse::parse_partial_number(byte, false, &OPTIONS);
assert!(result.is_ok());
let (num, count) = result.unwrap();
assert_eq!(num.mantissa, 12345);
assert_eq!(num.exponent, -26);
assert_eq!(num.many_digits, false);
assert_eq!(count, 28);
}
#[test]
fn parse_digits_test() {
const FORMAT: u128 = STANDARD;
let mut mantissa: u64 = 0;
let digits = b"1234567890123456789012345";
let mut byte = digits.bytes::<{ FORMAT }>();
parse::parse_digits(byte.integer_iter(), 10, |digit| {
mantissa = mantissa.wrapping_mul(10).wrapping_add(digit as _);
});
assert_eq!(mantissa, 1096246371337559929);
}
#[test]
#[cfg(not(feature = "compact"))]
fn parse_8digits_test() {
const FORMAT: u128 = STANDARD;
let mut mantissa: u64 = 0;
let digits = b"1234567890123456789012345";
let mut byte = digits.bytes::<{ FORMAT }>();
parse::parse_8digits::<_, FORMAT>(byte.integer_iter(), &mut mantissa);
// We don't check for overflow.
assert_eq!(mantissa, 11177671081359486962);
}
#[test]
fn parse_u64_digits_test() {
const FORMAT: u128 = STANDARD;
let mut mantissa: u64 = 0;
let mut step = u64_step(10);
let digits = b"1234567890123456789012345";
let mut byte = digits.bytes::<{ FORMAT }>();
parse::parse_u64_digits::<_, FORMAT>(byte.integer_iter(), &mut mantissa, &mut step);
assert_eq!(mantissa, 1234567890123456789);
assert_eq!(step, 0);
let mut mantissa: u64 = 0;
let mut step = u64_step(10);
let digits = b"1234567890123456789";
let mut byte = digits.bytes::<{ FORMAT }>();
parse::parse_u64_digits::<_, FORMAT>(byte.integer_iter(), &mut mantissa, &mut step);
assert_eq!(mantissa, 1234567890123456789);
assert_eq!(step, 0);
}
#[test]
fn is_special_eq_test() {
const FORMAT: u128 = STANDARD;
let digits = b"NaN";
let byte = digits.bytes::<{ FORMAT }>();
assert_eq!(parse::is_special_eq::<FORMAT>(byte.clone(), b"nan"), 3);
let byte = digits.bytes::<{ FORMAT }>();
assert_eq!(parse::is_special_eq::<FORMAT>(byte.clone(), b"NaN"), 3);
let byte = digits.bytes::<{ FORMAT }>();
assert_eq!(parse::is_special_eq::<FORMAT>(byte.clone(), b"inf"), 0);
}
#[test]
fn parse_positive_special_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let digits = b"NaN";
let byte = digits.bytes::<{ FORMAT }>();
let result = parse::parse_positive_special::<f64, FORMAT>(byte, &OPTIONS).unwrap();
assert_eq!(result.1, 3);
assert!(f64::is_nan(result.0));
let digits = b"NaN1";
let byte = digits.bytes::<{ FORMAT }>();
let result = parse::parse_positive_special::<f64, FORMAT>(byte, &OPTIONS).unwrap();
assert_eq!(result.1, 3);
assert!(f64::is_nan(result.0));
let digits = b"inf";
let byte = digits.bytes::<{ FORMAT }>();
let result = parse::parse_positive_special::<f64, FORMAT>(byte, &OPTIONS).unwrap();
assert_eq!(result.1, 3);
assert!(f64::is_infinite(result.0));
let digits = b"in";
let byte = digits.bytes::<{ FORMAT }>();
let result = parse::parse_positive_special::<f64, FORMAT>(byte, &OPTIONS);
assert_eq!(result, None);
}
#[test]
fn parse_partial_special_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let digits = b"NaN";
let byte = digits.bytes::<{ FORMAT }>();
let result = parse::parse_partial_special::<f64, FORMAT>(byte, true, &OPTIONS).unwrap();
assert_eq!(result.1, 3);
assert!(f64::is_nan(result.0));
assert!(f64::is_sign_negative(result.0));
}
#[test]
fn parse_parse_special_test() {
const FORMAT: u128 = STANDARD;
const OPTIONS: Options = Options::new();
let digits = b"NaN";
let byte = digits.bytes::<{ FORMAT }>();
let result = parse::parse_special::<f64, FORMAT>(byte, true, &OPTIONS).unwrap();
assert!(f64::is_nan(result));
assert!(f64::is_sign_negative(result));
let digits = b"NaN1";
let byte = digits.bytes::<{ FORMAT }>();
let result = parse::parse_special::<f64, FORMAT>(byte, true, &OPTIONS);
assert_eq!(result, None);
}
@@ -0,0 +1,110 @@
use lexical_parse_float::float::ExtendedFloat80;
use lexical_parse_float::shared;
#[cfg(feature = "power-of-two")]
use lexical_util::format::NumberFormatBuilder;
#[test]
fn calculate_shift_test() {
assert_eq!(shared::calculate_shift::<f64>(-63), 64);
assert_eq!(shared::calculate_shift::<f64>(-15), 16);
assert_eq!(shared::calculate_shift::<f64>(-8), 11);
assert_eq!(shared::calculate_shift::<f64>(0), 11);
assert_eq!(shared::calculate_shift::<f64>(50), 11);
}
#[test]
#[cfg(feature = "power-of-two")]
fn calculate_power2_test() {
const BASE4: u128 = NumberFormatBuilder::from_radix(4);
assert_eq!(shared::calculate_power2::<f64, BASE4>(-63, 5), 944);
assert_eq!(shared::calculate_power2::<f64, BASE4>(-15, 5), 1040);
assert_eq!(shared::calculate_power2::<f64, BASE4>(-8, 0), 1059);
assert_eq!(shared::calculate_power2::<f64, BASE4>(-8, 5), 1054);
assert_eq!(shared::calculate_power2::<f64, BASE4>(0, 5), 1070);
assert_eq!(shared::calculate_power2::<f64, BASE4>(50, 5), 1170);
}
#[test]
fn log2_test() {
assert_eq!(shared::log2(2), 1);
assert_eq!(shared::log2(4), 2);
assert_eq!(shared::log2(10), 1);
}
#[test]
fn starts_with_test() {
assert_eq!(shared::starts_with(b"NaN".iter(), b"nAN".iter()), false);
assert_eq!(shared::starts_with(b"nAN".iter(), b"nAN".iter()), true);
assert_eq!(shared::starts_with(b"nAN1".iter(), b"nAN".iter()), true);
assert_eq!(shared::starts_with(b"nAN1".iter(), b"nAN12".iter()), false);
}
#[test]
fn starts_with_uncased_test() {
assert_eq!(shared::starts_with_uncased(b"NaN".iter(), b"nAN".iter()), true);
assert_eq!(shared::starts_with_uncased(b"nAN".iter(), b"nAN".iter()), true);
assert_eq!(shared::starts_with_uncased(b"nAN1".iter(), b"nAN".iter()), true);
assert_eq!(shared::starts_with_uncased(b"nAN1".iter(), b"nAN12".iter()), false);
}
#[test]
fn round_test() {
let mut fp = ExtendedFloat80 {
mant: 9223372036854776832,
exp: -10,
};
shared::round::<f64, _>(&mut fp, |f, s| {
f.mant >>= s;
f.exp += s;
});
assert_eq!(fp.mant, 0);
assert_eq!(fp.exp, 1);
let mut fp = ExtendedFloat80 {
mant: 9223372036854776832,
exp: -10,
};
shared::round::<f64, _>(&mut fp, |f, s| {
f.mant >>= s;
f.exp += s;
// Round-up.
f.mant += 1;
});
assert_eq!(fp.mant, 1);
assert_eq!(fp.exp, 1);
// Round-down
let mut fp = ExtendedFloat80 {
mant: 9223372036854776832,
exp: -10,
};
shared::round::<f64, _>(&mut fp, |f, s| {
shared::round_nearest_tie_even(f, s, |is_odd, is_halfway, is_above| {
is_above || (is_odd && is_halfway)
});
});
assert_eq!(fp.mant, 0);
assert_eq!(fp.exp, 1);
// Round up
let mut fp = ExtendedFloat80 {
mant: 9223372036854778880,
exp: -10,
};
shared::round::<f64, _>(&mut fp, |f, s| {
shared::round_nearest_tie_even(f, s, |is_odd, is_halfway, is_above| {
is_above || (is_odd && is_halfway)
});
});
assert_eq!(fp.mant, 2);
assert_eq!(fp.exp, 1);
// Round down
let mut fp = ExtendedFloat80 {
mant: 9223372036854778880,
exp: -10,
};
shared::round::<f64, _>(&mut fp, shared::round_down);
assert_eq!(fp.mant, 1);
assert_eq!(fp.exp, 1);
}
@@ -0,0 +1,695 @@
mod stackvec;
#[cfg(feature = "radix")]
use core::cmp;
#[cfg(feature = "radix")]
use lexical_parse_float::bigint::Bigfloat;
use lexical_parse_float::bigint::Bigint;
use lexical_parse_float::float::{ExtendedFloat80, RawFloat};
use lexical_parse_float::limits::MaxDigits;
use lexical_parse_float::number::Number;
use lexical_parse_float::slow;
use lexical_util::format::STANDARD;
use stackvec::vec_from_u32;
fn b<F: RawFloat>(float: F) -> (u64, i32) {
let fp = slow::b(float);
(fp.mant, fp.exp)
}
fn bh<F: RawFloat>(float: F) -> (u64, i32) {
let fp = slow::bh(float);
(fp.mant, fp.exp)
}
#[test]
fn b_test() {
assert_eq!(b(1e-45_f32), (1, -149));
assert_eq!(b(5e-324_f64), (1, -1074));
assert_eq!(b(1e-323_f64), (2, -1074));
assert_eq!(b(2e-323_f64), (4, -1074));
assert_eq!(b(3e-323_f64), (6, -1074));
assert_eq!(b(4e-323_f64), (8, -1074));
assert_eq!(b(5e-323_f64), (10, -1074));
assert_eq!(b(6e-323_f64), (12, -1074));
assert_eq!(b(7e-323_f64), (14, -1074));
assert_eq!(b(8e-323_f64), (16, -1074));
assert_eq!(b(9e-323_f64), (18, -1074));
assert_eq!(b(1_f32), (8388608, -23));
assert_eq!(b(1_f64), (4503599627370496, -52));
assert_eq!(b(1e38_f32), (9860761, 103));
assert_eq!(b(1e308_f64), (5010420900022432, 971));
}
#[test]
fn bh_test() {
assert_eq!(bh(1e-45_f32), (3, -150));
assert_eq!(bh(5e-324_f64), (3, -1075));
assert_eq!(bh(1_f32), (16777217, -24));
assert_eq!(bh(1_f64), (9007199254740993, -53));
assert_eq!(bh(1e38_f32), (19721523, 102));
assert_eq!(bh(1e308_f64), (10020841800044865, 970));
}
#[test]
fn slow_radix_test() {
const FORMAT: u128 = STANDARD;
// 5e-324, round-down.
let mut num = Number {
mantissa: 2470328229206232720,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"2",
fraction: Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999"),
};
let fp = ExtendedFloat80 {
mant: 1 << 63,
exp: -63,
};
let result = slow::slow_radix::<f64, FORMAT>(num.clone(), fp);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 0);
// 5e-324, round-up.
num.fraction = Some(b"47032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251");
let result = slow::slow_radix::<f64, FORMAT>(num.clone(), fp);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 0);
// 8.98846567431158e+307
let mut num = Number {
mantissa: 8988465674311580536,
exponent: 289,
is_negative: false,
many_digits: true,
integer: b"8",
fraction: Some(b"9884656743115805365666807213050294962762414131308158973971342756154045415486693752413698006024096935349884403114202125541629105369684531108613657287705365884742938136589844238179474556051429647415148697857438797685859063890851407391008830874765563025951597582513936655578157348020066364210154316532161708032"),
};
let fp = ExtendedFloat80 {
mant: 9223372036854776832,
exp: 2035,
};
let result = slow::slow_radix::<f64, FORMAT>(num.clone(), fp);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 2046);
// 8.988465674311582e+307
num.fraction = Some(b"98846567431158053656668072130502949627624141313081589739713427561540454154866937524136980060240969353498844031142021255416291053696845311086136572877053658847429381365898442381794745560514296474151486978574387976858590638908514073910088308747655630259515975825139366555781573480200663642101543165321617080321");
let result = slow::slow_radix::<f64, FORMAT>(num.clone(), fp);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 2046);
}
#[test]
fn digit_comp_test() {
const FORMAT: u128 = STANDARD;
let max_digits = f64::max_digits(10).unwrap();
// 5e-324, round-down.
let num = Number {
mantissa: 2470328229206232720,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"2",
fraction: Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999"),
};
let fp = ExtendedFloat80 {
mant: 1 << 63,
exp: -63,
};
let result = slow::digit_comp::<f64, FORMAT>(num.clone(), fp, -324, max_digits);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 0);
// 1e-323, round-up.
let num = Number {
mantissa: 7410984687618698162,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"7",
fraction: Some(b"4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375"),
};
let fp = ExtendedFloat80 {
mant: 1 << 63,
exp: -62,
};
let result = slow::digit_comp::<f64, FORMAT>(num.clone(), fp, -324, max_digits);
assert_eq!(result.mant, 2);
assert_eq!(result.exp, 0);
// 8.98846567431158e+307
let mut num = Number {
mantissa: 8988465674311580536,
exponent: 289,
is_negative: false,
many_digits: true,
integer: b"8",
fraction: Some(b"9884656743115805365666807213050294962762414131308158973971342756154045415486693752413698006024096935349884403114202125541629105369684531108613657287705365884742938136589844238179474556051429647415148697857438797685859063890851407391008830874765563025951597582513936655578157348020066364210154316532161708032"),
};
let fp = ExtendedFloat80 {
mant: 9223372036854776832,
exp: 2035,
};
let result = slow::digit_comp::<f64, FORMAT>(num.clone(), fp, 307, max_digits);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 2046);
// 8.988465674311582e+307
num.fraction = Some(b"98846567431158053656668072130502949627624141313081589739713427561540454154866937524136980060240969353498844031142021255416291053696845311086136572877053658847429381365898442381794745560514296474151486978574387976858590638908514073910088308747655630259515975825139366555781573480200663642101543165321617080321");
let result = slow::digit_comp::<f64, FORMAT>(num.clone(), fp, 307, max_digits);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 2046);
}
#[test]
fn positive_digit_comp_test() {
const FORMAT: u128 = STANDARD;
// 8.98846567431158e+307
let bigmant = Bigint {
data: vec_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, 0, 0, 0, 0, 0, 0,
0, 1024, 2147483648,
]),
};
let exponent = 307 + 1 - 308;
let result = slow::positive_digit_comp::<f64, FORMAT>(bigmant, exponent);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 2046);
// 8.988465674311582e+307
let bigmant = Bigint {
data: vec_from_u32(&[
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1024, 2147483648,
]),
};
let exponent = 307 + 1 - 308;
let result = slow::positive_digit_comp::<f64, FORMAT>(bigmant, exponent);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 2046);
}
#[test]
fn negative_digit_comp_test() {
const FORMAT: u128 = STANDARD;
// 5e-324, below halfway, round-down to 0.0.
let bigmant = Bigint {
data: vec_from_u32(&[
1727738439, 330069557, 3509095598, 686205316, 156923684, 750687444, 2688855918,
28211928, 1887482096, 3222998811, 913348873, 1652282845, 1600735541, 1664240266,
84454144, 1487769792, 1855966778, 2832488299, 507030148, 1410055467, 2513359584,
3453963205, 779237894, 3456088326, 3671009895, 3094451696, 1250165638, 2682979794,
357925323, 1713890438, 3271046672, 3485897285, 3934710962, 1813530592, 199705026,
976390839, 2805488572, 2194288220, 2094065006, 2592523639, 3798974617, 586957244,
1409218821, 3442050171, 3789534764, 1380190380, 2055222457, 3535299831, 429482276,
389342206, 133558576, 721875297, 3013586570, 540178306, 2389746866, 2313334501,
422440635, 1288499129, 864978311, 842263325, 3016323856, 2282442263, 1440906063,
3931458696, 3511314276, 1884879882, 946366824, 4260548261, 1073379659, 1732329252,
3828972211, 1915607049, 3665440937, 1844358779, 3735281178, 2646335050, 1457460927,
2940016422, 1051,
]),
};
let fp = ExtendedFloat80 {
mant: 1 << 63,
exp: -63,
};
let exponent = -324 + 1 - 755;
let result = slow::negative_digit_comp::<f64, FORMAT>(bigmant, fp, exponent);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 0);
// 5e-324, halfway, round-down to 0.0.
let bigmant = Bigint {
data: vec_from_u32(&[
2084786877, 507136210, 2666388819, 3110242527, 3178432722, 541916566, 208847286,
3092404665, 83491860, 2893735989, 3973758097, 2600107496, 147629623, 1754010897,
4226332273, 2587058081, 942453804, 88731834, 1319061990, 173208747, 1982493283,
3808794987, 3874839738, 1854586992, 3508364323, 2021729080, 1899625710, 2420749567,
816401711, 3059730605, 1570934109, 3138812023, 1756281367, 3205859133, 2985201975,
1014588672, 3799556578, 577719905, 4052248225, 3649019757, 398935965, 56421532,
976366795, 1876047791, 3147705595, 4025764546, 1097271882, 1910500779, 2397021233,
1340419138, 2753207595, 3067328524, 2210626776, 1280440432, 3940874757, 4172726578,
1035509558, 1062145421, 1465448826, 2990139501, 1785427751, 2093931515, 4055890033,
3388365687, 2245484242, 3609657408, 3527114516, 1013577862, 2389075196, 426934091,
3237939346, 1071362463, 4070999470, 250952461, 2280067948, 1097862995, 2226250520,
221983348, 1,
]),
};
let exponent = -324 + 1 - 752;
let result = slow::negative_digit_comp::<f64, FORMAT>(bigmant, fp, exponent);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 0);
// 5e-324, above halfway, round-up to 5e-324.
let bigmant = Bigint {
data: vec_from_u32(&[
3667999587, 776394808, 894084415, 1037654204, 1719556155, 1124198371, 2088472861,
859275578, 834918607, 3167556114, 1082875312, 231271193, 1476296236, 360239786,
3608617070, 100777043, 834603454, 887318342, 305718012, 1732087473, 2645063646,
3728211506, 93691724, 1366000745, 723904866, 3037421624, 1816387920, 2732659194,
3869049819, 532534979, 2824439209, 1323349161, 382944493, 1993820262, 4082215981,
1555952134, 3635827414, 1482231762, 1867776587, 2130459211, 3989359658, 564215320,
1173733358, 1580608728, 1412284882, 1602939803, 2382784237, 1925138608, 2495375854,
519289497, 1762272177, 608514174, 631431287, 4214469733, 754041908, 3072560125,
1765160997, 2031519620, 1769586374, 4131591237, 674408332, 3759445970, 1904194670,
3818885807, 980005947, 1736835717, 911406800, 1545844036, 2415915482, 4269340915,
2314622388, 2123690045, 2055289038, 2509524619, 1325843000, 2388695363, 787668722,
2219833485, 10,
]),
};
let exponent = -324 + 1 - 753;
let result = slow::negative_digit_comp::<f64, FORMAT>(bigmant, fp, exponent);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 0);
// 1e-323, below halfway, round-down to 5e-324.
let bigmant = Bigint {
data: vec_from_u32(&[
888248023, 990208672, 1937352202, 2058615950, 470771052, 2252062332, 3771600458,
84635785, 1367478992, 1079061842, 2740046621, 661881239, 507239328, 697753503,
253362433, 168342080, 1272933039, 4202497602, 1521090445, 4230166401, 3245111456,
1771955024, 2337713684, 1778330386, 2423095095, 693420498, 3750496916, 3753972086,
1073775970, 846704018, 1223205425, 1867757265, 3214198296, 1145624482, 599115079,
2929172517, 4121498420, 2287897365, 1987227723, 3482603622, 2806989260, 1760871734,
4227656463, 1736215921, 2778669702, 4140571142, 1870700075, 2015964902, 1288446830,
1168026618, 400675728, 2165625891, 450825118, 1620534920, 2874273302, 2645036208,
1267321906, 3865497387, 2594934933, 2526789975, 459036976, 2552359495, 27750894,
3204441497, 1944008238, 1359672352, 2839100473, 4191710191, 3220138979, 902020460,
2896982042, 1451853853, 2406388220, 1238109043, 2615908943, 3644037856, 77415486,
230114675, 3155,
]),
};
let fp = ExtendedFloat80 {
mant: 1 << 63,
exp: -62,
};
let exponent = -324 + 1 - 755;
let result = slow::negative_digit_comp::<f64, FORMAT>(bigmant, fp, exponent);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 0);
// 1e-323, halfway, round-up to 1e-323.
let bigmant = Bigint {
data: vec_from_u32(&[
1959393335, 1521408631, 3704199161, 740792990, 945363576, 1625749700, 626541858,
687279403, 250475582, 91273375, 3331339701, 3505355194, 442888870, 967065395,
4089062228, 3466206949, 2827361413, 266195502, 3957185970, 519626241, 1652512553,
2836450370, 3034584624, 1268793682, 1935158378, 1770219946, 1403909835, 2967281406,
2449205134, 589257223, 417835033, 826501478, 973876807, 1027642808, 365671335,
3043766018, 2808735142, 1733159717, 3566810083, 2357124681, 1196807897, 169264596,
2929100385, 1333176077, 853182194, 3487359048, 3291815648, 1436535041, 2896096404,
4021257415, 3964655489, 612050981, 2336913034, 3841321297, 3232689679, 3928245144,
3106528676, 3186436263, 101379182, 380483912, 1061315959, 1986827250, 3577735508,
1575162471, 2441485432, 2239037633, 1991408958, 3040733588, 2872258292, 1280802274,
1123883446, 3214087391, 3623063818, 752857385, 2545236548, 3293588986, 2383784264,
665950045, 3,
]),
};
let exponent = -324 + 1 - 752;
let result = slow::negative_digit_comp::<f64, FORMAT>(bigmant, fp, exponent);
assert_eq!(result.mant, 2);
assert_eq!(result.exp, 0);
// 1e-323, above halfway, round-up to 1e-323.
let bigmant = Bigint {
data: vec_from_u32(&[
2414064167, 2329184426, 2682253245, 3112962612, 863701169, 3372595114, 1970451287,
2577826735, 2504755821, 912733750, 3248625938, 693813579, 133921412, 1080719359,
2235916618, 302331131, 2503810362, 2661955026, 917154036, 901295123, 3640223643,
2594699927, 281075174, 4098002235, 2171714598, 522330280, 1154196466, 3903010287,
3017214866, 1597604939, 4178350331, 3970047484, 1148833479, 1686493490, 3656713352,
372889108, 2317547651, 151727992, 1308362466, 2096410338, 3378144383, 1692645962,
3521200074, 446858888, 4236854647, 513852113, 2853385416, 1480448529, 3191160267,
1557868492, 991849235, 1825542523, 1894293861, 4053474607, 2262125726, 627745783,
1000515697, 1799591565, 1013791827, 3804839120, 2023224998, 2688403318, 1417616716,
2866722830, 2940017843, 915539855, 2734220401, 342564812, 2952779151, 4218088154,
2648899870, 2076102840, 1870899819, 3233606562, 3977529001, 2871118793, 2363006167,
2364533159, 31,
]),
};
let exponent = -324 + 1 - 753;
let result = slow::negative_digit_comp::<f64, FORMAT>(bigmant, fp, exponent);
assert_eq!(result.mant, 2);
assert_eq!(result.exp, 0);
}
#[test]
fn parse_mantissa_test() {
const FORMAT: u128 = STANDARD;
let max_digits = f64::max_digits(10).unwrap();
// Large number of digits.
let mut num = Number {
mantissa: 2470328229206232720,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"2",
fraction: Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999"),
};
let (bigmant, count) = slow::parse_mantissa::<FORMAT>(num.clone(), max_digits);
let expected = vec_from_u32::<100>(&[
1727738439, 330069557, 3509095598, 686205316, 156923684, 750687444, 2688855918, 28211928,
1887482096, 3222998811, 913348873, 1652282845, 1600735541, 1664240266, 84454144,
1487769792, 1855966778, 2832488299, 507030148, 1410055467, 2513359584, 3453963205,
779237894, 3456088326, 3671009895, 3094451696, 1250165638, 2682979794, 357925323,
1713890438, 3271046672, 3485897285, 3934710962, 1813530592, 199705026, 976390839,
2805488572, 2194288220, 2094065006, 2592523639, 3798974617, 586957244, 1409218821,
3442050171, 3789534764, 1380190380, 2055222457, 3535299831, 429482276, 389342206,
133558576, 721875297, 3013586570, 540178306, 2389746866, 2313334501, 422440635, 1288499129,
864978311, 842263325, 3016323856, 2282442263, 1440906063, 3931458696, 3511314276,
1884879882, 946366824, 4260548261, 1073379659, 1732329252, 3828972211, 1915607049,
3665440937, 1844358779, 3735281178, 2646335050, 1457460927, 2940016422, 1051,
]);
assert_eq!(&*bigmant.data, &*expected);
assert_eq!(count, 755);
// Leading zeros
num.integer = b"0000000002";
let (bigmant, count) = slow::parse_mantissa::<FORMAT>(num.clone(), max_digits);
assert_eq!(&*bigmant.data, &*expected);
assert_eq!(count, 755);
// Truncation.
let mut num = Number {
mantissa: 7410984687618698162,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"7",
fraction: Some(b"4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375332669816033062329967789262837"),
};
let (bigmant, count) = slow::parse_mantissa::<FORMAT>(num.clone(), max_digits);
let expected = vec_from_u32::<100>(&[
983641521, 2202462645, 4170685875, 1591772364, 529830014, 803977727, 126733331, 1695971390,
4089590927, 1532849076, 2705586665, 4046282448, 4076195232, 3230469892, 3059053929,
79035789, 744229654, 2026438108, 3570486781, 2818088662, 3485839733, 3653138023,
2857937689, 602717004, 3689362390, 283607819, 1783392475, 2053068939, 1888214698,
550023429, 296880187, 1046779059, 1285361259, 84614934, 1627922685, 2023868765, 1987523901,
743493573, 3897769089, 2210613570, 2261081349, 3015057659, 3949711644, 3346092916,
2433639051, 36411806, 1050442, 269209477, 2649742673, 1494221829, 2763524503, 2514491481,
2325312415, 1741242814, 2479923579, 1098250122, 2416211509, 3612906464, 403420662,
3663250314, 1993722098, 365907183, 4270226312, 3962131185, 432952495, 2963635838,
2996289227, 3200289391, 2753231690, 2780286109, 884373163, 1418533204, 3382415762,
499541562, 3369625401, 3421327641, 3526770155, 3109983188, 1157439767, 734593155,
]);
assert_eq!(&*bigmant.data, &*expected);
assert_eq!(count, max_digits + 1);
// No fraction digits.
num.integer = b"74109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375332669816033062329967789262837";
num.fraction = None;
let (bigmant, count) = slow::parse_mantissa::<FORMAT>(num.clone(), max_digits);
assert_eq!(&*bigmant.data, &*expected);
assert_eq!(count, max_digits + 1);
// Multiple of step (check we add our temporary correctly).
num.integer = b"7410984687618698162648531893023320585475897039214871466383785237510132609053131277979497545424539885696948470431685765963899850655339096945981621940161728171894510697854671067917687257517734731555330779540854980960845750095811137303474765809687100959097544227100475730780971111893578483867565399878350301522805593404659373979179073872386829939581848166016912201945649993128979841136206248449867871357218035220901702390328579173252022052897402080290685402160661237554998340267130003581248647904138574340187552090159017259254714629617513415977493871857473787096164563890871811984127167305601704549300470526959016576377688490826798697257336652176556794107250876433756084600398490497214911746308553955635418864151316847843631308023759629577398300170898437533266981";
num.fraction = None;
let (bigmant, count) = slow::parse_mantissa::<FORMAT>(num.clone(), max_digits);
let expected = vec_from_u32::<100>(&[
617018405, 396211401, 2130402383, 3812547827, 4263683770, 3918012496, 1787721490,
2493014694, 435464626, 3720854431, 2928509507, 2677932436, 369049650, 3606588290,
231237141, 2231172875, 3358152367, 95217925, 2777810007, 1016185079, 596681915, 2331711780,
593487272, 4212730845, 339602972, 4097829793, 262427536, 4182115035, 3414687403,
3711518952, 4168896929, 483727327, 1657080031, 2785588628, 1009114769, 482126749,
485376744, 1123705337, 3225501941, 2939050108, 1338451005, 2104263947, 3425461126,
1834224928, 4061025704, 792093815, 2707019125, 3610271203, 4254101529, 1026215278,
4117890107, 1748110416, 2535111606, 80965120, 3823822115, 2354910057, 590658512,
2682089507, 159300272, 1776569442, 3382166479, 3222978591, 540586210, 934713382,
2014123057, 1455555790, 4119131465, 3685912982, 3019947291, 3437891678, 2660105801,
2605860762, 394373515, 4177081532, 1616198650, 1580399082, 2017617452, 3327697130,
315505357,
]);
assert_eq!(&*bigmant.data, &*expected);
assert_eq!(count, 760);
}
#[test]
#[cfg(feature = "radix")]
fn byte_comp_test() {
const FORMAT: u128 = STANDARD;
// 5e-324
let mut num = Number {
mantissa: 2470328229206232720,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"2",
fraction: Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999"),
};
let fp = ExtendedFloat80 {
mant: 1 << 63,
exp: -63,
};
let result = slow::byte_comp::<f64, FORMAT>(num.clone(), fp, -324);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 0);
// 5e-324, equal, round-down
num.fraction = Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125");
let result = slow::byte_comp::<f64, FORMAT>(num.clone(), fp, -324);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 0);
// 5e-324, equal, round-down, many 0s
num.fraction = Some(b"47032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281250000000");
let result = slow::byte_comp::<f64, FORMAT>(num.clone(), fp, -324);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 0);
// 5e-324, above, round-up
num.fraction = Some(b"47032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251");
let result = slow::byte_comp::<f64, FORMAT>(num.clone(), fp, -324);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 0);
// 8.98846567431158e+307
let mut num = Number {
mantissa: 8988465674311580536,
exponent: 289,
is_negative: false,
many_digits: true,
integer: b"8",
fraction: Some(b"9884656743115805365666807213050294962762414131308158973971342756154045415486693752413698006024096935349884403114202125541629105369684531108613657287705365884742938136589844238179474556051429647415148697857438797685859063890851407391008830874765563025951597582513936655578157348020066364210154316532161708032"),
};
let fp = ExtendedFloat80 {
mant: 9223372036854776832,
exp: 960 + 1075,
};
let result = slow::byte_comp::<f64, FORMAT>(num.clone(), fp, 307);
assert_eq!(result.mant, 0);
assert_eq!(result.exp, 2046);
// 8.988465674311582e+307
num.fraction = Some(b"98846567431158053656668072130502949627624141313081589739713427561540454154866937524136980060240969353498844031142021255416291053696845311086136572877053658847429381365898442381794745560514296474151486978574387976858590638908514073910088308747655630259515975825139366555781573480200663642101543165321617080321");
let result = slow::byte_comp::<f64, FORMAT>(num.clone(), fp, 307);
assert_eq!(result.mant, 1);
assert_eq!(result.exp, 2046);
}
#[test]
#[cfg(feature = "radix")]
fn compare_bytes_test() {
const FORMAT: u128 = STANDARD;
// 2^-1074
let num = Bigfloat {
data: vec_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: vec_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
let mut number = Number {
mantissa: 2470328229206232720,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"2",
fraction: Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999"),
};
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Less
);
// Exactly halfway.
number.fraction = Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Equal
);
// Above halfway.
number.fraction = Some(b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Greater
);
// 2*2^-1074
let num = Bigfloat {
data: vec_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: vec_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
let mut number = Number {
mantissa: 7410984687618698162,
exponent: -342,
is_negative: false,
many_digits: true,
integer: b"7",
fraction: Some(b"4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999"),
};
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Less
);
// Exactly halfway.
number.fraction = Some(b"4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Equal
);
// Above halfway.
number.fraction = Some(b"4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Greater
);
// 4503599627370496*2^971
let num = Bigfloat {
data: vec_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: vec_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
let mut number = Number {
mantissa: 8988465674311580536,
exponent: 289,
is_negative: false,
many_digits: true,
integer: b"8",
fraction: Some(b"9884656743115805365666807213050294962762414131308158973971342756154045415486693752413698006024096935349884403114202125541629105369684531108613657287705365884742938136589844238179474556051429647415148697857438797685859063890851407391008830874765563025951597582513936655578157348020066364210154316532161708031999"),
};
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Less
);
// Exactly halfway.
number.fraction = Some(b"9884656743115805365666807213050294962762414131308158973971342756154045415486693752413698006024096935349884403114202125541629105369684531108613657287705365884742938136589844238179474556051429647415148697857438797685859063890851407391008830874765563025951597582513936655578157348020066364210154316532161708032");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Equal
);
// Above halfway.
number.fraction = Some(b"9884656743115805365666807213050294962762414131308158973971342756154045415486693752413698006024096935349884403114202125541629105369684531108613657287705365884742938136589844238179474556051429648741514697857438797685859063890851407391008830874765563025951597582513936655578157348020066364210154316532161708032001");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Greater
);
// Ensure leading and trailing zeros are ignored.
// Below halfway
number.integer = b"000008";
number.fraction = Some(b"98846567431158053656668072130502949627624141313081589739713427561540454154866937524136980060240969353498844031142021255416291053696845311086136572877053658847429381365898442381794745560514296474151486978574387976858590638908514073910088308747655630259515975825139366555781573480200663642101543165321617080319990000");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Less
);
// Exactly halfway.
number.integer = b"000008";
number.fraction = Some(b"98846567431158053656668072130502949627624141313081589739713427561540454154866937524136980060240969353498844031142021255416291053696845311086136572877053658847429381365898442381794745560514296474151486978574387976858590638908514073910088308747655630259515975825139366555781573480200663642101543165321617080320000");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Equal
);
// Above halfway.
number.integer = b"000008";
number.fraction = Some(b"98846567431158053656668072130502949627624141313081589739713427561540454154866937524136980060240969353498844031142021255416291053696845311086136572877053658847429381365898442381794745560514296487415146978574387976858590638908514073910088308747655630259515975825139366555781573480200663642101543165321617080320010000");
assert_eq!(
slow::compare_bytes::<FORMAT>(number.clone(), num.clone(), den.clone()),
cmp::Ordering::Greater
);
}
#[test]
fn scientific_exponent_test() {
let mut number = Number {
exponent: -4,
mantissa: 12345,
is_negative: false,
many_digits: false,
integer: &[],
fraction: None,
};
assert_eq!(slow::scientific_exponent::<{ STANDARD }>(&number), 0);
number.exponent = -15;
assert_eq!(slow::scientific_exponent::<{ STANDARD }>(&number), -11);
number.mantissa = 1234567890123456;
assert_eq!(slow::scientific_exponent::<{ STANDARD }>(&number), 0);
}
#[test]
#[cfg(feature = "radix")]
fn integral_binary_factor_test() {
const TABLE: [u32; 35] = [
0, 2, 0, 3, 3, 3, 0, 4, 4, 4, 4, 4, 4, 4, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
0, 6, 6, 6, 6,
];
for (index, radix) in (2..37).enumerate() {
assert_eq!(slow::integral_binary_factor(radix), TABLE[index]);
}
}
@@ -0,0 +1,28 @@
use lexical_parse_float::bigint::{Limb, StackVec};
pub fn vec_from_u32<const SIZE: usize>(x: &[u32]) -> StackVec<SIZE> {
let mut vec = StackVec::<SIZE>::new();
#[cfg(not(all(target_pointer_width = "64", not(target_arch = "sparc"))))]
{
for &xi in x {
vec.try_push(xi as Limb).unwrap();
}
}
#[cfg(all(target_pointer_width = "64", not(target_arch = "sparc")))]
{
for xi in x.chunks(2) {
match xi.len() {
1 => vec.try_push(xi[0] as Limb).unwrap(),
2 => {
let xi0 = xi[0] as Limb;
let xi1 = xi[1] as Limb;
vec.try_push((xi1 << 32) | xi0).unwrap()
},
_ => unreachable!(),
}
}
}
vec
}
@@ -0,0 +1,472 @@
mod stackvec;
use core::cmp;
use lexical_parse_float::bigint::{self, Limb, StackVec};
use stackvec::vec_from_u32;
const SIZE: usize = 50;
type VecType = StackVec<SIZE>;
#[test]
fn simple_test() {
// Test the simple properties of the stack vector.
let mut x = VecType::from_u32(1);
assert_eq!(x.len(), 1);
assert_eq!(x.is_empty(), false);
assert_eq!(x.capacity(), SIZE);
x.try_push(5).unwrap();
assert_eq!(x.len(), 2);
assert_eq!(x.pop(), Some(5));
assert_eq!(x.len(), 1);
assert_eq!(&*x, &[1]);
x.try_extend(&[2, 3, 4]).unwrap();
assert_eq!(x.len(), 4);
assert_eq!(&*x, &[1, 2, 3, 4]);
x.try_resize(6, 0).unwrap();
assert_eq!(x.len(), 6);
assert_eq!(&*x, &[1, 2, 3, 4, 0, 0]);
x.try_resize(0, 0).unwrap();
assert_eq!(x.len(), 0);
assert_eq!(x.is_empty(), true);
let x = VecType::try_from(&[5, 1]).unwrap();
assert_eq!(x.len(), 2);
assert_eq!(x.is_empty(), false);
assert_eq!(x.hi16(), (0x8000, true));
if Limb::BITS == 32 {
assert_eq!(x.hi32(), (0x80000002, true));
assert_eq!(x.hi64(), (0x8000000280000000, false));
} else {
assert_eq!(x.hi32(), (0x80000000, true));
assert_eq!(x.hi64(), (0x8000000000000002, true));
}
let rview = x.rview();
assert_eq!(x[0], 5);
assert_eq!(x[1], 1);
assert_eq!(rview[0], 1);
assert_eq!(rview[1], 5);
assert_eq!(rview.get(1), Some(&5));
assert_eq!(rview.get(2), None);
assert_eq!(VecType::from_u16(u16::MAX).hi16(), (u16::MAX, false));
assert_eq!(VecType::from_u32(u32::MAX).hi32(), (u32::MAX, false));
assert_eq!(VecType::from_u64(u64::MAX).hi64(), (u64::MAX, false));
}
#[test]
fn bounds_test() {
type ShortVec = StackVec<2>;
let mut x = ShortVec::from_u32(1);
assert_eq!(x.try_push(2), Some(()));
assert_eq!(x.try_push(5), None);
assert_eq!(x.try_resize(0, 0), Some(()));
assert_eq!(x.try_resize(3, 0), None);
}
#[test]
fn hi32_test() {
assert_eq!(VecType::from_u16(0xA).hi32(), (0xA0000000, false));
assert_eq!(VecType::from_u32(0xAB).hi32(), (0xAB000000, false));
assert_eq!(VecType::from_u64(0xAB00000000).hi32(), (0xAB000000, false));
assert_eq!(VecType::from_u64(0xA23456789A).hi32(), (0xA2345678, true));
}
#[test]
fn hi64_test() {
assert_eq!(VecType::from_u16(0xA).hi64(), (0xA000000000000000, false));
assert_eq!(VecType::from_u32(0xAB).hi64(), (0xAB00000000000000, false));
assert_eq!(VecType::from_u64(0xAB00000000).hi64(), (0xAB00000000000000, false));
assert_eq!(VecType::from_u64(0xA23456789A).hi64(), (0xA23456789A000000, false));
}
#[test]
fn cmp_test() {
// Simple
let x = VecType::from_u32(1);
let y = VecType::from_u32(2);
assert_eq!(x.partial_cmp(&x), Some(cmp::Ordering::Equal));
assert_eq!(x.cmp(&x), cmp::Ordering::Equal);
assert_eq!(x.cmp(&y), cmp::Ordering::Less);
// Check asymmetric
let x = VecType::try_from(&[5, 1]).unwrap();
let y = VecType::from_u32(2);
assert_eq!(x.cmp(&x), cmp::Ordering::Equal);
assert_eq!(x.cmp(&y), cmp::Ordering::Greater);
// Check when we use reverse ordering properly.
let x = VecType::try_from(&[5, 1, 9]).unwrap();
let y = VecType::try_from(&[6, 2, 8]).unwrap();
assert_eq!(x.cmp(&x), cmp::Ordering::Equal);
assert_eq!(x.cmp(&y), cmp::Ordering::Greater);
// Complex scenario, check it properly uses reverse ordering.
let x = VecType::try_from(&[0, 1, 9]).unwrap();
let y = VecType::try_from(&[4294967295, 0, 9]).unwrap();
assert_eq!(x.cmp(&x), cmp::Ordering::Equal);
assert_eq!(x.cmp(&y), cmp::Ordering::Greater);
}
#[test]
fn math_test() {
let mut x = VecType::try_from(&[0, 1, 9]).unwrap();
assert_eq!(x.is_normalized(), true);
x.try_push(0).unwrap();
assert_eq!(&*x, &[0, 1, 9, 0]);
assert_eq!(x.is_normalized(), false);
x.normalize();
assert_eq!(&*x, &[0, 1, 9]);
assert_eq!(x.is_normalized(), true);
x.add_small(1);
assert_eq!(&*x, &[1, 1, 9]);
x.add_small(Limb::MAX);
assert_eq!(&*x, &[0, 2, 9]);
x.mul_small(3);
assert_eq!(&*x, &[0, 6, 27]);
x.mul_small(Limb::MAX);
let expected: VecType = if Limb::BITS == 32 {
vec_from_u32(&[0, 4294967290, 4294967274, 26])
} else {
vec_from_u32(&[0, 0, 4294967290, 4294967295, 4294967274, 4294967295, 26])
};
assert_eq!(&*x, &*expected);
#[cfg(feature = "radix")]
{
let mut x: VecType = vec_from_u32(&[0, 0, 0, 536870912]);
let y: VecType = vec_from_u32(&[3358091099, 2770363594, 2782716766, 217327764]);
assert_eq!(x.quorem(&y), 2);
let expected: VecType = vec_from_u32(&[1873752394, 3049207402, 3024501058, 102215382]);
assert_eq!(&*x, &*expected);
}
let mut x = VecType::from_u32(0xFFFFFFFF);
let y = VecType::from_u32(5);
x *= &y;
let expected: VecType = vec_from_u32(&[0xFFFFFFFB, 0x4]);
assert_eq!(&*x, &*expected);
// Test with carry
let mut x = VecType::from_u32(1);
assert_eq!(&*x, &[1]);
x.add_small(Limb::MAX);
assert_eq!(&*x, &[0, 1]);
}
#[test]
fn hi_test() {
assert_eq!(unsafe { bigint::nonzero(&[0, 0, 0], 0) }, false);
assert_eq!(unsafe { bigint::nonzero(&[1, 0, 0], 0) }, true);
assert_eq!(bigint::u32_to_hi16_1(1), (0x8000, false));
assert_eq!(bigint::u32_to_hi16_2(1, 4), (0x8000, true));
assert_eq!(bigint::u32_to_hi32_1(1), (0x80000000, false));
assert_eq!(bigint::u32_to_hi32_2(1, 4), (0x80000002, false));
assert_eq!(bigint::u32_to_hi64_1(1), (0x8000000000000000, false));
assert_eq!(bigint::u32_to_hi64_2(1, 4), (0x8000000200000000, false));
assert_eq!(bigint::u32_to_hi64_2(1, 5), (0x8000000280000000, false));
assert_eq!(bigint::u32_to_hi64_3(1, 5, 4), (0x8000000280000002, false));
assert_eq!(bigint::u32_to_hi64_3(1, 5, 5), (0x8000000280000002, true));
assert_eq!(bigint::u64_to_hi16_1(1), (0x8000, false));
assert_eq!(bigint::u64_to_hi16_2(1, 4), (0x8000, true));
assert_eq!(bigint::u64_to_hi32_1(1), (0x80000000, false));
assert_eq!(bigint::u64_to_hi32_2(1, 4), (0x80000000, true));
assert_eq!(bigint::u64_to_hi64_1(1), (0x8000000000000000, false));
assert_eq!(bigint::u64_to_hi64_2(1, 4), (0x8000000000000002, false));
assert_eq!(bigint::u64_to_hi64_2(1, 5), (0x8000000000000002, true));
}
#[test]
fn scalar_add_test() {
assert_eq!(bigint::scalar_add(5, 5), (10, false));
assert_eq!(bigint::scalar_add(Limb::MAX, 1), (0, true));
}
#[test]
fn scalar_mul_test() {
assert_eq!(bigint::scalar_mul(5, 5, 0), (25, 0));
assert_eq!(bigint::scalar_mul(5, 5, 1), (26, 0));
assert_eq!(bigint::scalar_mul(Limb::MAX, 2, 0), (Limb::MAX - 1, 1));
}
#[test]
fn small_add_test() {
let mut x = VecType::from_u32(4294967295);
bigint::small_add(&mut x, 5);
let expected: VecType = vec_from_u32(&[4, 1]);
assert_eq!(&*x, &*expected);
let mut x = VecType::from_u32(5);
bigint::small_add(&mut x, 7);
let expected = VecType::from_u32(12);
assert_eq!(&*x, &*expected);
// Single carry, internal overflow
let mut x = VecType::from_u64(0x80000000FFFFFFFF);
bigint::small_add(&mut x, 7);
let expected: VecType = vec_from_u32(&[6, 0x80000001]);
assert_eq!(&*x, &*expected);
// Double carry, overflow
let mut x = VecType::from_u64(0xFFFFFFFFFFFFFFFF);
bigint::small_add(&mut x, 7);
let expected: VecType = vec_from_u32(&[6, 0, 1]);
assert_eq!(&*x, &*expected);
}
#[test]
fn small_mul_test() {
// No overflow check, 1-int.
let mut x = VecType::from_u32(5);
bigint::small_mul(&mut x, 7);
let expected = VecType::from_u32(35);
assert_eq!(&*x, &*expected);
// No overflow check, 2-ints.
let mut x = VecType::from_u64(0x4000000040000);
bigint::small_mul(&mut x, 5);
let expected: VecType = vec_from_u32(&[0x00140000, 0x140000]);
assert_eq!(&*x, &*expected);
// Overflow, 1 carry.
let mut x = VecType::from_u32(0x33333334);
bigint::small_mul(&mut x, 5);
let expected: VecType = vec_from_u32(&[4, 1]);
assert_eq!(&*x, &*expected);
// Overflow, 1 carry, internal.
let mut x = VecType::from_u64(0x133333334);
bigint::small_mul(&mut x, 5);
let expected: VecType = vec_from_u32(&[4, 6]);
assert_eq!(&*x, &*expected);
// Overflow, 2 carries.
let mut x = VecType::from_u64(0x3333333333333334);
bigint::small_mul(&mut x, 5);
let expected: VecType = vec_from_u32(&[4, 0, 1]);
assert_eq!(&*x, &*expected);
}
#[test]
fn pow_test() {
let mut x = VecType::from_u32(1);
bigint::pow(&mut x, 5, 2);
let expected = VecType::from_u32(25);
assert_eq!(&*x, &*expected);
let mut x = VecType::from_u32(1);
bigint::pow(&mut x, 5, 15);
let expected: VecType = vec_from_u32(&[452807053, 7]);
assert_eq!(&*x, &*expected);
let mut x = VecType::from_u32(1);
bigint::pow(&mut x, 5, 16);
let expected: VecType = vec_from_u32(&[2264035265, 35]);
assert_eq!(&*x, &*expected);
let mut x = VecType::from_u32(1);
bigint::pow(&mut x, 5, 17);
let expected: VecType = vec_from_u32(&[2730241733, 177]);
assert_eq!(&*x, &*expected);
let mut x = VecType::from_u32(1);
bigint::pow(&mut x, 5, 302);
let expected: VecType = vec_from_u32(&[
2443090281, 2149694430, 2297493928, 1584384001, 1279504719, 1930002239, 3312868939,
3735173465, 3523274756, 2025818732, 1641675015, 2431239749, 4292780461, 3719612855,
4174476133, 3296847770, 2677357556, 638848153, 2198928114, 3285049351, 2159526706,
626302612,
]);
assert_eq!(&*x, &*expected);
}
#[test]
fn large_add_test() {
// Overflow, both single values
let mut x = VecType::from_u32(4294967295);
let y = VecType::from_u32(5);
bigint::large_add(&mut x, &y);
let expected: VecType = vec_from_u32(&[4, 1]);
assert_eq!(&*x, &*expected);
// No overflow, single value
let mut x = VecType::from_u32(5);
let y = VecType::from_u32(7);
bigint::large_add(&mut x, &y);
let expected = VecType::from_u32(12);
assert_eq!(&*x, &*expected);
// Single carry, internal overflow
let mut x = VecType::from_u64(0x80000000FFFFFFFF);
let y = VecType::from_u32(7);
bigint::large_add(&mut x, &y);
let expected: VecType = vec_from_u32(&[6, 0x80000001]);
assert_eq!(&*x, &*expected);
// 1st overflows, 2nd doesn't.
let mut x = VecType::from_u64(0x7FFFFFFFFFFFFFFF);
let y = VecType::from_u64(0x7FFFFFFFFFFFFFFF);
bigint::large_add(&mut x, &y);
let expected: VecType = vec_from_u32(&[0xFFFFFFFE, 0xFFFFFFFF]);
assert_eq!(&*x, &*expected);
// Both overflow.
let mut x = VecType::from_u64(0x8FFFFFFFFFFFFFFF);
let y = VecType::from_u64(0x7FFFFFFFFFFFFFFF);
bigint::large_add(&mut x, &y);
let expected: VecType = vec_from_u32(&[0xFFFFFFFE, 0x0FFFFFFF, 1]);
assert_eq!(&*x, &*expected);
}
#[test]
fn large_mul_test() {
// Test by empty
let mut x = VecType::from_u32(0xFFFFFFFF);
let y = VecType::new();
bigint::large_mul(&mut x, &y);
let expected = VecType::new();
assert_eq!(&*x, &*expected);
// Simple case
let mut x = VecType::from_u32(0xFFFFFFFF);
let y = VecType::from_u32(5);
bigint::large_mul(&mut x, &y);
let expected: VecType = vec_from_u32(&[0xFFFFFFFB, 0x4]);
assert_eq!(&*x, &*expected);
// Large u32, but still just as easy.
let mut x = VecType::from_u32(0xFFFFFFFF);
let y = VecType::from_u32(0xFFFFFFFE);
bigint::large_mul(&mut x, &y);
let expected: VecType = vec_from_u32(&[0x2, 0xFFFFFFFD]);
assert_eq!(&*x, &*expected);
// Let's multiply two large values together.
let mut x: VecType = vec_from_u32(&[0xFFFFFFFE, 0x0FFFFFFF, 1]);
let y: VecType = vec_from_u32(&[0x99999999, 0x99999999, 0xCCCD9999, 0xCCCC]);
bigint::large_mul(&mut x, &y);
let expected: VecType =
vec_from_u32(&[0xCCCCCCCE, 0x5CCCCCCC, 0x9997FFFF, 0x33319999, 0x999A7333, 0xD999]);
assert_eq!(&*x, &*expected);
}
#[test]
fn very_large_mul_test() {
// Test cases triggered to that would normally use `karatsuba_mul`.
// Karatsuba multiplication was ripped out, however, these are useful
// test cases.
let mut x: VecType = vec_from_u32(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let y: VecType = vec_from_u32(&[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]);
bigint::large_mul(&mut x, &y);
let expected: VecType = vec_from_u32(&[
4, 13, 28, 50, 80, 119, 168, 228, 300, 385, 484, 598, 728, 875, 1040, 1224, 1340, 1435,
1508, 1558, 1584, 1585, 1560, 1508, 1428, 1319, 1180, 1010, 808, 573, 304,
]);
assert_eq!(&*x, &*expected);
// Test cases triggered to that would normally use `karatsuba_uneven_mul`.
let mut x: VecType = vec_from_u32(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let y: VecType = vec_from_u32(&[
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
]);
bigint::large_mul(&mut x, &y);
let expected: VecType = vec_from_u32(&[
4, 13, 28, 50, 80, 119, 168, 228, 300, 385, 484, 598, 728, 875, 1040, 1224, 1360, 1496,
1632, 1768, 1904, 2040, 2176, 2312, 2448, 2584, 2720, 2856, 2992, 3128, 3264, 3400, 3536,
3672, 3770, 3829, 3848, 3826, 3762, 3655, 3504, 3308, 3066, 2777, 2440, 2054, 1618, 1131,
592,
]);
assert_eq!(&*x, &*expected);
}
#[test]
#[cfg(feature = "radix")]
fn quorem_test() {
let mut x: VecType = vec_from_u32(&[0, 0, 0, 536870912]);
let y: VecType = vec_from_u32(&[3358091099, 2770363594, 2782716766, 217327764]);
assert_eq!(bigint::large_quorem(&mut x, &y), 2);
let expected: VecType = vec_from_u32(&[1873752394, 3049207402, 3024501058, 102215382]);
assert_eq!(&*x, &*expected);
}
#[test]
fn bit_length_test() {
let x: VecType = vec_from_u32(&[0, 0, 0, 1]);
assert_eq!(bigint::bit_length(&x), 97);
let x: VecType = vec_from_u32(&[0, 0, 0, 3]);
assert_eq!(bigint::bit_length(&x), 98);
let x = VecType::from_u32(1 << 31);
assert_eq!(bigint::bit_length(&x), 32);
}
#[test]
fn shl_bits_test() {
let mut x = VecType::from_u32(0xD2210408);
bigint::shl_bits(&mut x, 5);
let expected: VecType = vec_from_u32(&[0x44208100, 0x1A]);
assert_eq!(&*x, &*expected);
}
#[test]
fn shl_limbs_test() {
let mut x = VecType::from_u32(0xD2210408);
bigint::shl_limbs(&mut x, 2);
let expected: VecType = if Limb::BITS == 32 {
vec_from_u32(&[0, 0, 0xD2210408])
} else {
vec_from_u32(&[0, 0, 0, 0, 0xD2210408])
};
assert_eq!(&*x, &*expected);
}
#[test]
fn shl_test() {
// Pattern generated via `''.join(["1" +"0"*i for i in range(20)])`
let mut x = VecType::from_u32(0xD2210408);
bigint::shl(&mut x, 5).unwrap();
let expected: VecType = vec_from_u32(&[0x44208100, 0x1A]);
assert_eq!(&*x, &*expected);
bigint::shl(&mut x, 32).unwrap();
let expected: VecType = vec_from_u32(&[0, 0x44208100, 0x1A]);
assert_eq!(&*x, &*expected);
bigint::shl(&mut x, 27).unwrap();
let expected: VecType = vec_from_u32(&[0, 0, 0xD2210408]);
assert_eq!(&*x, &*expected);
// 96-bits of previous pattern
let mut x: VecType = vec_from_u32(&[0x20020010, 0x8040100, 0xD2210408]);
bigint::shl(&mut x, 5).unwrap();
let expected: VecType = vec_from_u32(&[0x400200, 0x802004, 0x44208101, 0x1A]);
assert_eq!(&*x, &*expected);
bigint::shl(&mut x, 32).unwrap();
let expected: VecType = vec_from_u32(&[0, 0x400200, 0x802004, 0x44208101, 0x1A]);
assert_eq!(&*x, &*expected);
bigint::shl(&mut x, 27).unwrap();
let expected: VecType = vec_from_u32(&[0, 0, 0x20020010, 0x8040100, 0xD2210408]);
assert_eq!(&*x, &*expected);
}
#[test]
fn split_radix_test() {
assert_eq!(bigint::split_radix(10), (5, 1));
if cfg!(feature = "radix") {
assert_eq!(bigint::split_radix(2), (0, 1));
assert_eq!(bigint::split_radix(4), (0, 2));
assert_eq!(bigint::split_radix(8), (0, 3));
assert_eq!(bigint::split_radix(16), (0, 4));
assert_eq!(bigint::split_radix(32), (0, 5));
assert_eq!(bigint::split_radix(14), (7, 1));
}
}