summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minimal-lexical/tests
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/minimal-lexical/tests')
-rw-r--r--third_party/rust/minimal-lexical/tests/bellerophon.rs59
-rw-r--r--third_party/rust/minimal-lexical/tests/bellerophon_tests.rs231
-rw-r--r--third_party/rust/minimal-lexical/tests/integration_tests.rs228
-rw-r--r--third_party/rust/minimal-lexical/tests/lemire_tests.rs378
-rw-r--r--third_party/rust/minimal-lexical/tests/libm_tests.rs289
-rw-r--r--third_party/rust/minimal-lexical/tests/mask_tests.rs16
-rw-r--r--third_party/rust/minimal-lexical/tests/number_tests.rs88
-rw-r--r--third_party/rust/minimal-lexical/tests/parse_tests.rs189
-rw-r--r--third_party/rust/minimal-lexical/tests/rounding_tests.rs64
-rw-r--r--third_party/rust/minimal-lexical/tests/slow_tests.rs337
-rw-r--r--third_party/rust/minimal-lexical/tests/stackvec.rs32
-rw-r--r--third_party/rust/minimal-lexical/tests/vec_tests.rs395
12 files changed, 2306 insertions, 0 deletions
diff --git a/third_party/rust/minimal-lexical/tests/bellerophon.rs b/third_party/rust/minimal-lexical/tests/bellerophon.rs
new file mode 100644
index 0000000000..99cd89acfc
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/bellerophon.rs
@@ -0,0 +1,59 @@
+#![cfg(feature = "compact")]
+#![allow(dead_code)]
+
+use minimal_lexical::bellerophon::bellerophon;
+use minimal_lexical::extended_float::{extended_to_float, ExtendedFloat};
+use minimal_lexical::num::Float;
+use minimal_lexical::number::Number;
+
+pub fn bellerophon_test<F: Float + core::fmt::Debug>(
+ xmant: u64,
+ xexp: i32,
+ many_digits: bool,
+ ymant: u64,
+ yexp: i32,
+) {
+ let num = Number {
+ exponent: xexp,
+ mantissa: xmant,
+ many_digits,
+ };
+ let xfp = bellerophon::<F>(&num);
+ let yfp = ExtendedFloat {
+ 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: i32, w: u64) -> (i32, u64) {
+ let num = Number {
+ exponent: q,
+ mantissa: w,
+ many_digits: false,
+ };
+ let fp = bellerophon::<f32>(&num);
+ (fp.exp, fp.mant)
+}
+
+pub fn compute_float64(q: i32, w: u64) -> (i32, u64) {
+ let num = Number {
+ exponent: q,
+ mantissa: w,
+ many_digits: false,
+ };
+ let fp = bellerophon::<f64>(&num);
+ (fp.exp, fp.mant)
+}
diff --git a/third_party/rust/minimal-lexical/tests/bellerophon_tests.rs b/third_party/rust/minimal-lexical/tests/bellerophon_tests.rs
new file mode 100644
index 0000000000..f5826c615d
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/bellerophon_tests.rs
@@ -0,0 +1,231 @@
+#![cfg(feature = "compact")]
+
+mod bellerophon;
+
+use bellerophon::{bellerophon_test, compute_float32, compute_float64};
+use minimal_lexical::num::Float;
+
+#[test]
+fn halfway_round_down_test() {
+ // Halfway, round-down tests
+ bellerophon_test::<f64>(9007199254740992, 0, false, 0, 1076);
+ bellerophon_test::<f64>(
+ 9007199254740993,
+ 0,
+ false,
+ 9223372036854776832,
+ 1065 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(9007199254740994, 0, false, 1, 1076);
+
+ bellerophon_test::<f64>(18014398509481984, 0, false, 0, 1077);
+ bellerophon_test::<f64>(
+ 18014398509481986,
+ 0,
+ false,
+ 9223372036854776832,
+ 1066 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(18014398509481988, 0, false, 1, 1077);
+
+ bellerophon_test::<f64>(9223372036854775808, 0, false, 0, 1086);
+ bellerophon_test::<f64>(
+ 9223372036854776832,
+ 0,
+ false,
+ 9223372036854776832,
+ 1075 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(9223372036854777856, 0, false, 1, 1086);
+
+ // Add a 0 but say we're truncated.
+ bellerophon_test::<f64>(9007199254740992000, -3, true, 0, 1076);
+ bellerophon_test::<f64>(
+ 9007199254740993000,
+ -3,
+ true,
+ 9223372036854776832,
+ 1065 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(9007199254740994000, -3, true, 1, 1076);
+}
+
+#[test]
+fn halfway_round_up_test() {
+ // Halfway, round-up tests
+ bellerophon_test::<f64>(9007199254740994, 0, false, 1, 1076);
+ bellerophon_test::<f64>(
+ 9007199254740995,
+ 0,
+ false,
+ 9223372036854778880,
+ 1065 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(9007199254740996, 0, false, 2, 1076);
+
+ bellerophon_test::<f64>(18014398509481988, 0, false, 1, 1077);
+ bellerophon_test::<f64>(
+ 18014398509481990,
+ 0,
+ false,
+ 9223372036854778880,
+ 1066 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(18014398509481992, 0, false, 2, 1077);
+
+ bellerophon_test::<f64>(9223372036854777856, 0, false, 1, 1086);
+ bellerophon_test::<f64>(
+ 9223372036854778880,
+ 0,
+ false,
+ 9223372036854778880,
+ 1075 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(9223372036854779904, 0, false, 2, 1086);
+
+ // Add a 0 but say we're truncated.
+ bellerophon_test::<f64>(9007199254740994000, -3, true, 1, 1076);
+ bellerophon_test::<f64>(
+ 9007199254740994990,
+ -3,
+ true,
+ 9223372036854778869,
+ 1065 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(
+ 9007199254740995000,
+ -3,
+ true,
+ 9223372036854778879,
+ 1065 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(
+ 9007199254740995010,
+ -3,
+ true,
+ 9223372036854778890,
+ 1065 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(9007199254740995050, -3, true, 2, 1076);
+ bellerophon_test::<f64>(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>(5, -324, false, 1, 0);
+ bellerophon_test::<f64>(10, -324, false, 2, 0);
+ // This is very close to 2.4703282292062327206e-342.
+ bellerophon_test::<f64>(
+ 2470328229206232720,
+ -342,
+ false,
+ 18446744073709551608,
+ -64 + f64::INVALID_FP,
+ );
+ bellerophon_test::<f64>(2470328229206232721, -342, false, 9223372036854775808, -32831);
+ bellerophon_test::<f64>(2470328229206232725, -342, false, 9223372036854775824, -32831);
+ bellerophon_test::<f64>(2470328229206232726, -342, false, 1, 0);
+ bellerophon_test::<f64>(2470328229206232730, -342, false, 1, 0);
+ // Check very close to literal infinity.
+ // 17.976931348623155
+ // 1.797693134862315508561243283845062402343434371574593359244049e+308
+ // 1.797693134862315708145274237317043567980705675258449965989175e+308
+ bellerophon_test::<f64>(17976931348623155, 292, false, 4503599627370494, 2046);
+ bellerophon_test::<f64>(17976931348623156, 292, false, 4503599627370494, 2046);
+ bellerophon_test::<f64>(1797693134862315605, 290, false, 4503599627370494, 2046);
+ bellerophon_test::<f64>(1797693134862315607, 290, false, 4503599627370494, 2046);
+ bellerophon_test::<f64>(1797693134862315608, 290, false, 18446744073709548540, -30733);
+ bellerophon_test::<f64>(1797693134862315609, 290, false, 18446744073709548550, -30733);
+ bellerophon_test::<f64>(179769313486231561, 291, false, 4503599627370495, 2046);
+ bellerophon_test::<f64>(17976931348623157, 292, false, 4503599627370495, 2046);
+
+ // Check existing issues and underflow.
+ bellerophon_test::<f64>(2470328229206232726, -343, false, 0, 0);
+ bellerophon_test::<f64>(2470328229206232726, -342, false, 1, 0);
+ bellerophon_test::<f64>(1, -250, false, 1945308223406668, 192);
+ bellerophon_test::<f64>(1, -150, false, 2867420733609077, 524);
+ bellerophon_test::<f64>(1, -45, false, 1924152549665465, 873);
+ bellerophon_test::<f64>(1, -40, false, 400386103400348, 890);
+ bellerophon_test::<f64>(1, -20, false, 2142540351554083, 956);
+ bellerophon_test::<f64>(1, 0, false, 0, 1023);
+ bellerophon_test::<f64>(1, 20, false, 1599915997629504, 1089);
+ bellerophon_test::<f64>(1, 40, false, 3768206498159781, 1155);
+ bellerophon_test::<f64>(1, 150, false, 999684479948463, 1521);
+ bellerophon_test::<f64>(1, 250, false, 1786584717939204, 1853);
+ // Minimum positive normal float.
+ bellerophon_test::<f64>(22250738585072014, -324, false, 0, 1);
+ // Maximum positive subnormal float.
+ bellerophon_test::<f64>(2225073858507201, -323, false, 4503599627370495, 0);
+ // Next highest subnormal float.
+ bellerophon_test::<f64>(22250738585072004, -324, false, 4503599627370494, 0);
+ bellerophon_test::<f64>(22250738585072006, -324, false, 4503599627370494, 0);
+ bellerophon_test::<f64>(22250738585072007, -324, false, 4503599627370495, 0);
+ bellerophon_test::<f64>(222507385850720062, -325, false, 4503599627370494, 0);
+ bellerophon_test::<f64>(222507385850720063, -325, false, 4503599627370494, 0);
+ bellerophon_test::<f64>(222507385850720064, -325, false, 4503599627370494, 0);
+ bellerophon_test::<f64>(2225073858507200641, -326, false, 18446744073709545462, -32779);
+ bellerophon_test::<f64>(2225073858507200642, -326, false, 18446744073709545472, -32779);
+ bellerophon_test::<f64>(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 + f32::INVALID_FP, 9223372586610589696));
+ assert_eq!(compute_float32(0, 16777218), (151, 1));
+ assert_eq!(compute_float32(0, 16777219), (111 + f32::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 + f32::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 + f32::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 + f64::INVALID_FP, 9223372036854776832));
+ assert_eq!(compute_float64(0, 9007199254740994), (1076, 1));
+ assert_eq!(compute_float64(0, 9007199254740995), (1065 + f64::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 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(compute_float64(0, 18014398509481988), (1077, 1));
+ assert_eq!(
+ compute_float64(0, 18014398509481990),
+ (1066 + f64::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 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1));
+ assert_eq!(
+ compute_float64(-3, 9007199254740995000),
+ (1065 + f64::INVALID_FP, 9223372036854778879)
+ );
+ assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2));
+}
diff --git a/third_party/rust/minimal-lexical/tests/integration_tests.rs b/third_party/rust/minimal-lexical/tests/integration_tests.rs
new file mode 100644
index 0000000000..a8f2ff8a0e
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/integration_tests.rs
@@ -0,0 +1,228 @@
+/// Find and parse sign and get remaining bytes.
+#[inline]
+fn parse_sign<'a>(bytes: &'a [u8]) -> (bool, &'a [u8]) {
+ match bytes.get(0) {
+ Some(&b'+') => (true, &bytes[1..]),
+ Some(&b'-') => (false, &bytes[1..]),
+ _ => (true, bytes),
+ }
+}
+
+// Convert u8 to digit.
+#[inline]
+fn to_digit(c: u8) -> Option<u32> {
+ (c as char).to_digit(10)
+}
+
+// Add digit from exponent.
+#[inline]
+fn add_digit_i32(value: i32, digit: u32) -> Option<i32> {
+ return value.checked_mul(10)?.checked_add(digit as i32);
+}
+
+// Subtract digit from exponent.
+#[inline]
+fn sub_digit_i32(value: i32, digit: u32) -> Option<i32> {
+ return value.checked_mul(10)?.checked_sub(digit as i32);
+}
+
+// Convert character to digit.
+#[inline]
+fn is_digit(c: u8) -> bool {
+ to_digit(c).is_some()
+}
+
+// Split buffer at index.
+#[inline]
+fn split_at_index<'a>(digits: &'a [u8], index: usize) -> (&'a [u8], &'a [u8]) {
+ (&digits[..index], &digits[index..])
+}
+
+/// Consume until a an invalid digit is found.
+///
+/// - `digits` - Slice containing 0 or more digits.
+#[inline]
+fn consume_digits<'a>(digits: &'a [u8]) -> (&'a [u8], &'a [u8]) {
+ // Consume all digits.
+ let mut index = 0;
+ while index < digits.len() && is_digit(digits[index]) {
+ index += 1;
+ }
+ split_at_index(digits, index)
+}
+
+// Trim leading 0s.
+#[inline]
+fn ltrim_zero<'a>(bytes: &'a [u8]) -> &'a [u8] {
+ let count = bytes.iter().take_while(|&&si| si == b'0').count();
+ &bytes[count..]
+}
+
+// Trim trailing 0s.
+#[inline]
+fn rtrim_zero<'a>(bytes: &'a [u8]) -> &'a [u8] {
+ let count = bytes.iter().rev().take_while(|&&si| si == b'0').count();
+ let index = bytes.len() - count;
+ &bytes[..index]
+}
+
+// PARSERS
+// -------
+
+/// Parse the exponent of the float.
+///
+/// * `exponent` - Slice containing the exponent digits.
+/// * `is_positive` - If the exponent sign is positive.
+fn parse_exponent(exponent: &[u8], is_positive: bool) -> i32 {
+ // Parse the sign bit or current data.
+ let mut value: i32 = 0;
+ match is_positive {
+ true => {
+ for c in exponent {
+ value = match add_digit_i32(value, to_digit(*c).unwrap()) {
+ Some(v) => v,
+ None => return i32::max_value(),
+ };
+ }
+ },
+ false => {
+ for c in exponent {
+ value = match sub_digit_i32(value, to_digit(*c).unwrap()) {
+ Some(v) => v,
+ None => return i32::min_value(),
+ };
+ }
+ },
+ }
+
+ value
+}
+
+pub fn case_insensitive_starts_with<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool
+where
+ Iter1: Iterator<Item = &'a u8>,
+ Iter2: Iterator<Item = &'b u8>,
+{
+ // We use a faster optimization here for ASCII letters, which NaN
+ // and infinite strings **must** be. [A-Z] is 0x41-0x5A, while
+ // [a-z] is 0x61-0x7A. Therefore, the xor must be 0 or 32 if they
+ // are case-insensitive equal, but only if at least 1 of the inputs
+ // is an ASCII letter.
+ loop {
+ let yi = y.next();
+ if yi.is_none() {
+ return true;
+ }
+ let yi = *yi.unwrap();
+ let is_not_equal = x.next().map_or(true, |&xi| {
+ let xor = xi ^ yi;
+ xor != 0 && xor != 0x20
+ });
+ if is_not_equal {
+ return false;
+ }
+ }
+}
+
+/// Parse float from input bytes, returning the float and the remaining bytes.
+///
+/// * `bytes` - Array of bytes leading with float-data.
+pub fn parse_float<'a, F>(bytes: &'a [u8]) -> (F, &'a [u8])
+where
+ F: minimal_lexical::Float,
+{
+ let start = bytes;
+
+ // Parse the sign.
+ let (is_positive, bytes) = parse_sign(bytes);
+
+ // Check NaN, Inf, Infinity
+ if case_insensitive_starts_with(bytes.iter(), b"NaN".iter()) {
+ let mut float = F::from_bits(F::EXPONENT_MASK | (F::HIDDEN_BIT_MASK >> 1));
+ if !is_positive {
+ float = -float;
+ }
+ return (float, &bytes[3..]);
+ } else if case_insensitive_starts_with(bytes.iter(), b"Infinity".iter()) {
+ let mut float = F::from_bits(F::EXPONENT_MASK);
+ if !is_positive {
+ float = -float;
+ }
+ return (float, &bytes[8..]);
+ } else if case_insensitive_starts_with(bytes.iter(), b"inf".iter()) {
+ let mut float = F::from_bits(F::EXPONENT_MASK);
+ if !is_positive {
+ float = -float;
+ }
+ return (float, &bytes[3..]);
+ }
+
+ // Extract and parse the float components:
+ // 1. Integer
+ // 2. Fraction
+ // 3. Exponent
+ let (integer_slc, bytes) = consume_digits(bytes);
+ let (fraction_slc, bytes) = match bytes.first() {
+ Some(&b'.') => consume_digits(&bytes[1..]),
+ _ => (&bytes[..0], bytes),
+ };
+ let (exponent, bytes) = match bytes.first() {
+ Some(&b'e') | Some(&b'E') => {
+ // Extract and parse the exponent.
+ let (is_positive, bytes) = parse_sign(&bytes[1..]);
+ let (exponent, bytes) = consume_digits(bytes);
+ (parse_exponent(exponent, is_positive), bytes)
+ },
+ _ => (0, bytes),
+ };
+
+ if bytes.len() == start.len() {
+ return (F::from_u64(0), bytes);
+ }
+
+ // Note: You may want to check and validate the float data here:
+ // 1). Many floats require integer or fraction digits, if a fraction
+ // is present.
+ // 2). All floats require either integer or fraction digits.
+ // 3). Some floats do not allow a '+' sign before the significant digits.
+ // 4). Many floats require exponent digits after the exponent symbol.
+ // 5). Some floats do not allow a '+' sign before the exponent.
+
+ // We now need to trim leading and trailing 0s from the integer
+ // and fraction, respectively. This is required to make the
+ // fast and moderate paths more efficient, and for the slow
+ // path.
+ let integer_slc = ltrim_zero(integer_slc);
+ let fraction_slc = rtrim_zero(fraction_slc);
+
+ // Create the float and return our data.
+ let mut float: F =
+ minimal_lexical::parse_float(integer_slc.iter(), fraction_slc.iter(), exponent);
+ if !is_positive {
+ float = -float;
+ }
+
+ (float, bytes)
+}
+
+macro_rules! b {
+ ($x:literal) => {
+ $x.as_bytes()
+ };
+}
+
+#[test]
+fn f32_test() {
+ assert_eq!(
+ (184467440000000000000.0, b!("\x00\x00006")),
+ parse_float::<f32>(b"000184467440737095516150\x00\x00006")
+ );
+}
+
+#[test]
+fn f64_test() {
+ assert_eq!(
+ (184467440737095500000.0, b!("\x00\x00006")),
+ parse_float::<f64>(b"000184467440737095516150\x00\x00006")
+ );
+}
diff --git a/third_party/rust/minimal-lexical/tests/lemire_tests.rs b/third_party/rust/minimal-lexical/tests/lemire_tests.rs
new file mode 100644
index 0000000000..0523ca5b2a
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/lemire_tests.rs
@@ -0,0 +1,378 @@
+//! These tests are adapted from the Rust core library's unittests.
+
+#![cfg(not(feature = "compact"))]
+
+use minimal_lexical::lemire;
+use minimal_lexical::num::Float;
+
+fn compute_error32(q: i32, w: u64) -> (i32, u64) {
+ let fp = lemire::compute_error::<f32>(q, w);
+ (fp.exp, fp.mant)
+}
+
+fn compute_error64(q: i32, w: u64) -> (i32, u64) {
+ let fp = lemire::compute_error::<f64>(q, w);
+ (fp.exp, fp.mant)
+}
+
+fn compute_error_scaled32(q: i32, 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: i32, w: u64, lz: i32) -> (i32, u64) {
+ let fp = lemire::compute_error_scaled::<f64>(q, w, lz);
+ (fp.exp, fp.mant)
+}
+
+fn compute_float32(q: i32, w: u64) -> (i32, u64) {
+ let fp = lemire::compute_float::<f32>(q, w);
+ (fp.exp, fp.mant)
+}
+
+fn compute_float64(q: i32, w: u64) -> (i32, u64) {
+ let fp = lemire::compute_float::<f64>(q, w);
+ (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 + f32::INVALID_FP, 9223372036854775808));
+ assert_eq!(compute_error32(0, 16777217), (111 + f32::INVALID_FP, 9223372586610589696));
+ assert_eq!(compute_error32(0, 16777218), (111 + f32::INVALID_FP, 9223373136366403584));
+ assert_eq!(compute_error32(0, 16777219), (111 + f32::INVALID_FP, 9223373686122217472));
+ assert_eq!(compute_error32(0, 16777220), (111 + f32::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 + f32::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error32(-10, 167772170000000000),
+ (111 + f32::INVALID_FP, 9223372586610589696)
+ );
+ assert_eq!(
+ compute_error32(-10, 167772180000000000),
+ (111 + f32::INVALID_FP, 9223373136366403584)
+ );
+ // Let's check the lines to see if anything is different in table...
+ assert_eq!(
+ compute_error32(-10, 167772190000000000),
+ (111 + f32::INVALID_FP, 9223373686122217472)
+ );
+ assert_eq!(
+ compute_error32(-10, 167772200000000000),
+ (111 + f32::INVALID_FP, 9223374235878031360)
+ );
+}
+
+#[test]
+fn compute_error64_test() {
+ // These test near-halfway cases for double-precision floats.
+ assert_eq!(compute_error64(0, 9007199254740992), (1065 + f64::INVALID_FP, 9223372036854775808));
+ assert_eq!(compute_error64(0, 9007199254740993), (1065 + f64::INVALID_FP, 9223372036854776832));
+ assert_eq!(compute_error64(0, 9007199254740994), (1065 + f64::INVALID_FP, 9223372036854777856));
+ assert_eq!(compute_error64(0, 9007199254740995), (1065 + f64::INVALID_FP, 9223372036854778880));
+ assert_eq!(compute_error64(0, 9007199254740996), (1065 + f64::INVALID_FP, 9223372036854779904));
+ assert_eq!(
+ compute_error64(0, 18014398509481984),
+ (1066 + f64::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error64(0, 18014398509481986),
+ (1066 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error64(0, 18014398509481988),
+ (1066 + f64::INVALID_FP, 9223372036854777856)
+ );
+ assert_eq!(
+ compute_error64(0, 18014398509481990),
+ (1066 + f64::INVALID_FP, 9223372036854778880)
+ );
+ assert_eq!(
+ compute_error64(0, 18014398509481992),
+ (1066 + f64::INVALID_FP, 9223372036854779904)
+ );
+
+ // Test a much closer set of examples.
+ assert_eq!(
+ compute_error64(0, 9007199254740991),
+ (1064 + f64::INVALID_FP, 18446744073709549568)
+ );
+ assert_eq!(
+ compute_error64(0, 9223372036854776831),
+ (1075 + f64::INVALID_FP, 9223372036854776830)
+ );
+ assert_eq!(
+ compute_error64(0, 9223372036854776832),
+ (1075 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error64(0, 9223372036854776833),
+ (1075 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error64(-42, 9123456727292927),
+ (925 + f64::INVALID_FP, 13021432563531497894)
+ );
+ assert_eq!(
+ compute_error64(-43, 91234567272929275),
+ (925 + f64::INVALID_FP, 13021432563531498606)
+ );
+ assert_eq!(
+ compute_error64(-42, 9123456727292928),
+ (925 + f64::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 + f64::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error64(-3, 9007199254740993000),
+ (1065 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error64(-3, 9007199254740994000),
+ (1065 + f64::INVALID_FP, 9223372036854777856)
+ );
+ assert_eq!(
+ compute_error64(-3, 9007199254740995000),
+ (1065 + f64::INVALID_FP, 9223372036854778880)
+ );
+ assert_eq!(
+ compute_error64(-3, 9007199254740996000),
+ (1065 + f64::INVALID_FP, 9223372036854779904)
+ );
+
+ // Test from errors in atof.
+ assert_eq!(
+ compute_error64(-18, 1000000178813934326),
+ (1012 + f64::INVALID_FP, 9223373686122217470)
+ );
+
+ // Check edge-cases from previous errors.
+ assert_eq!(
+ compute_error64(-342, 2470328229206232720),
+ (-64 + f64::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 + f32::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error_scaled32(0, 4611686293305294848, 39),
+ (111 + f32::INVALID_FP, 9223372586610589696)
+ );
+ assert_eq!(
+ compute_error_scaled32(0, 4611686568183201792, 39),
+ (111 + f32::INVALID_FP, 9223373136366403584)
+ );
+ assert_eq!(
+ compute_error_scaled32(0, 4611686843061108736, 39),
+ (111 + f32::INVALID_FP, 9223373686122217472)
+ );
+ assert_eq!(
+ compute_error_scaled32(0, 4611687117939015680, 39),
+ (111 + f32::INVALID_FP, 9223374235878031360)
+ );
+
+ assert_eq!(
+ compute_error_scaled32(-10, 9223372036854775808, 6),
+ (111 + f32::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error_scaled32(-10, 9223372586610589696, 6),
+ (111 + f32::INVALID_FP, 9223372586610589696)
+ );
+ assert_eq!(
+ compute_error_scaled32(-10, 9223373136366403584, 6),
+ (111 + f32::INVALID_FP, 9223373136366403584)
+ );
+ assert_eq!(
+ compute_error_scaled32(-10, 9223373686122217472, 6),
+ (111 + f32::INVALID_FP, 9223373686122217472)
+ );
+ assert_eq!(
+ compute_error_scaled32(-10, 9223374235878031360, 6),
+ (111 + f32::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 + f64::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427388416, 10),
+ (1065 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427388928, 10),
+ (1065 + f64::INVALID_FP, 9223372036854777856)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427389440, 10),
+ (1065 + f64::INVALID_FP, 9223372036854778880)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427389952, 10),
+ (1065 + f64::INVALID_FP, 9223372036854779904)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427387904, 9),
+ (1066 + f64::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427388416, 9),
+ (1066 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427388928, 9),
+ (1066 + f64::INVALID_FP, 9223372036854777856)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427389440, 9),
+ (1066 + f64::INVALID_FP, 9223372036854778880)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427389952, 9),
+ (1066 + f64::INVALID_FP, 9223372036854779904)
+ );
+
+ // Test a much closer set of examples.
+ assert_eq!(
+ compute_error_scaled64(0, 9223372036854774784, 11),
+ (1064 + f64::INVALID_FP, 18446744073709549568)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427388415, 0),
+ (1075 + f64::INVALID_FP, 9223372036854776830)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427388416, 0),
+ (1075 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error_scaled64(0, 4611686018427388416, 0),
+ (1075 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error_scaled64(-42, 6510716281765748947, 10),
+ (925 + f64::INVALID_FP, 13021432563531497894)
+ );
+ assert_eq!(
+ compute_error_scaled64(-43, 6510716281765749303, 7),
+ (925 + f64::INVALID_FP, 13021432563531498606)
+ );
+ assert_eq!(
+ compute_error_scaled64(-42, 6510716281765749660, 10),
+ (925 + f64::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 + f64::INVALID_FP, 9223372036854775808)
+ );
+ assert_eq!(
+ compute_error_scaled64(-3, 9223372036854776832, 1),
+ (1065 + f64::INVALID_FP, 9223372036854776832)
+ );
+ assert_eq!(
+ compute_error_scaled64(-3, 9223372036854777856, 1),
+ (1065 + f64::INVALID_FP, 9223372036854777856)
+ );
+ assert_eq!(
+ compute_error_scaled64(-3, 9223372036854778880, 1),
+ (1065 + f64::INVALID_FP, 9223372036854778880)
+ );
+ assert_eq!(
+ compute_error_scaled64(-3, 9223372036854779904, 1),
+ (1065 + f64::INVALID_FP, 9223372036854779904)
+ );
+
+ // Test from errors in atof.
+ assert_eq!(
+ compute_error_scaled64(-18, 9223373686122217470, 4),
+ (1012 + f64::INVALID_FP, 9223373686122217470)
+ );
+
+ // Check edge-cases from previous errors.
+ assert_eq!(
+ compute_error_scaled64(-342, 9223372036854775804, 2),
+ (-64 + f64::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));
+}
diff --git a/third_party/rust/minimal-lexical/tests/libm_tests.rs b/third_party/rust/minimal-lexical/tests/libm_tests.rs
new file mode 100644
index 0000000000..7f5352e193
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/libm_tests.rs
@@ -0,0 +1,289 @@
+#![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 minimal_lexical::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);
+ }
+}
diff --git a/third_party/rust/minimal-lexical/tests/mask_tests.rs b/third_party/rust/minimal-lexical/tests/mask_tests.rs
new file mode 100644
index 0000000000..97e70a72b8
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/mask_tests.rs
@@ -0,0 +1,16 @@
+use minimal_lexical::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);
+}
diff --git a/third_party/rust/minimal-lexical/tests/number_tests.rs b/third_party/rust/minimal-lexical/tests/number_tests.rs
new file mode 100644
index 0000000000..947be394c9
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/number_tests.rs
@@ -0,0 +1,88 @@
+use minimal_lexical::number::Number;
+
+#[test]
+fn is_fast_path_test() {
+ let mut number = Number {
+ exponent: -4,
+ mantissa: 12345,
+ many_digits: false,
+ };
+ assert_eq!(number.is_fast_path::<f32>(), true);
+ assert_eq!(number.is_fast_path::<f64>(), true);
+
+ number.exponent = -15;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), true);
+
+ number.exponent = -25;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), false);
+
+ number.exponent = 25;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), true);
+
+ number.exponent = 36;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), true);
+
+ number.exponent = 38;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), false);
+
+ number.mantissa = 1 << 25;
+ number.exponent = 0;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), true);
+
+ number.mantissa = 1 << 54;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), false);
+
+ number.mantissa = 1 << 52;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), true);
+
+ number.many_digits = true;
+ assert_eq!(number.is_fast_path::<f32>(), false);
+ assert_eq!(number.is_fast_path::<f64>(), false);
+}
+
+#[test]
+fn try_fast_path_test() {
+ let mut number = Number {
+ exponent: -4,
+ mantissa: 12345,
+ many_digits: false,
+ };
+ assert_eq!(number.try_fast_path::<f32>(), Some(1.2345));
+ assert_eq!(number.try_fast_path::<f64>(), Some(1.2345));
+
+ number.exponent = -10;
+ assert_eq!(number.try_fast_path::<f32>(), Some(1.2345e-6));
+ assert_eq!(number.try_fast_path::<f64>(), Some(1.2345e-6));
+
+ number.exponent = -20;
+ assert_eq!(number.try_fast_path::<f32>(), None);
+ assert_eq!(number.try_fast_path::<f64>(), Some(1.2345e-16));
+
+ number.exponent = -25;
+ assert_eq!(number.try_fast_path::<f32>(), None);
+ assert_eq!(number.try_fast_path::<f64>(), None);
+
+ number.exponent = 12;
+ assert_eq!(number.try_fast_path::<f32>(), Some(1.2345e16));
+ assert_eq!(number.try_fast_path::<f64>(), Some(1.2345e16));
+
+ number.exponent = 25;
+ assert_eq!(number.try_fast_path::<f32>(), None);
+ assert_eq!(number.try_fast_path::<f64>(), Some(1.2345e29));
+
+ number.exponent = 32;
+ assert_eq!(number.try_fast_path::<f32>(), None);
+ assert_eq!(number.try_fast_path::<f64>(), Some(1.2345e36));
+
+ number.exponent = 36;
+ assert_eq!(number.try_fast_path::<f32>(), None);
+ assert_eq!(number.try_fast_path::<f64>(), None);
+}
diff --git a/third_party/rust/minimal-lexical/tests/parse_tests.rs b/third_party/rust/minimal-lexical/tests/parse_tests.rs
new file mode 100644
index 0000000000..48856fd1cc
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/parse_tests.rs
@@ -0,0 +1,189 @@
+use core::f64;
+use minimal_lexical::{num, parse};
+
+fn check_parse_float<F: num::Float>(integer: &str, fraction: &str, exponent: i32, expected: F) {
+ let integer = integer.as_bytes().iter();
+ let fraction = fraction.as_bytes().iter();
+ assert!(expected == parse::parse_float::<F, _, _>(integer, fraction, exponent));
+}
+
+#[test]
+fn parse_f32_test() {
+ check_parse_float("", "", 0, 0.0_f32);
+ check_parse_float("1", "2345", 0, 1.2345_f32);
+ check_parse_float("12", "345", 0, 12.345_f32);
+ check_parse_float("12345", "6789", 0, 12345.6789_f32);
+ check_parse_float("1", "2345", 10, 1.2345e10_f32);
+ check_parse_float("1", "2345", -38, 1.2345e-38_f32);
+
+ // Check expected rounding, using borderline cases.
+ // Round-down, halfway
+ check_parse_float("16777216", "", 0, 16777216.0_f32);
+ check_parse_float("16777217", "", 0, 16777216.0_f32);
+ check_parse_float("16777218", "", 0, 16777218.0_f32);
+ check_parse_float("33554432", "", 0, 33554432.0_f32);
+ check_parse_float("33554434", "", 0, 33554432.0_f32);
+ check_parse_float("33554436", "", 0, 33554436.0_f32);
+ check_parse_float("17179869184", "", 0, 17179869184.0_f32);
+ check_parse_float("17179870208", "", 0, 17179869184.0_f32);
+ check_parse_float("17179871232", "", 0, 17179871232.0_f32);
+
+ // Round-up, halfway
+ check_parse_float("16777218", "", 0, 16777218.0_f32);
+ check_parse_float("16777219", "", 0, 16777220.0_f32);
+ check_parse_float("16777220", "", 0, 16777220.0_f32);
+
+ check_parse_float("33554436", "", 0, 33554436.0_f32);
+ check_parse_float("33554438", "", 0, 33554440.0_f32);
+ check_parse_float("33554440", "", 0, 33554440.0_f32);
+
+ check_parse_float("17179871232", "", 0, 17179871232.0_f32);
+ check_parse_float("17179872256", "", 0, 17179873280.0_f32);
+ check_parse_float("17179873280", "", 0, 17179873280.0_f32);
+
+ // Round-up, above halfway
+ check_parse_float("33554435", "", 0, 33554436.0_f32);
+ check_parse_float("17179870209", "", 0, 17179871232.0_f32);
+
+ // Check exactly halfway, round-up at halfway
+ check_parse_float("1", "00000017881393432617187499", 0, 1.0000001_f32);
+ check_parse_float("1", "000000178813934326171875", 0, 1.0000002_f32);
+ check_parse_float("1", "00000017881393432617187501", 0, 1.0000002_f32);
+
+ check_parse_float("", "000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625", 0, 1.1754943508222875e-38f32);
+}
+
+#[test]
+fn parse_f64_test() {
+ check_parse_float("", "", 0, 0.0_f64);
+ check_parse_float("1", "2345", 0, 1.2345_f64);
+ check_parse_float("12", "345", 0, 12.345_f64);
+ check_parse_float("12345", "6789", 0, 12345.6789_f64);
+ check_parse_float("1", "2345", 10, 1.2345e10_f64);
+ check_parse_float("1", "2345", -308, 1.2345e-308_f64);
+
+ // Check expected rounding, using borderline cases.
+ // Round-down, halfway
+ check_parse_float("9007199254740992", "", 0, 9007199254740992.0_f64);
+ check_parse_float("9007199254740993", "", 0, 9007199254740992.0_f64);
+ check_parse_float("9007199254740994", "", 0, 9007199254740994.0_f64);
+
+ check_parse_float("18014398509481984", "", 0, 18014398509481984.0_f64);
+ check_parse_float("18014398509481986", "", 0, 18014398509481984.0_f64);
+ check_parse_float("18014398509481988", "", 0, 18014398509481988.0_f64);
+
+ check_parse_float("9223372036854775808", "", 0, 9223372036854775808.0_f64);
+ check_parse_float("9223372036854776832", "", 0, 9223372036854775808.0_f64);
+ check_parse_float("9223372036854777856", "", 0, 9223372036854777856.0_f64);
+
+ check_parse_float(
+ "11417981541647679048466287755595961091061972992",
+ "",
+ 0,
+ 11417981541647679048466287755595961091061972992.0_f64,
+ );
+ check_parse_float(
+ "11417981541647680316116887983825362587765178368",
+ "",
+ 0,
+ 11417981541647679048466287755595961091061972992.0_f64,
+ );
+ check_parse_float(
+ "11417981541647681583767488212054764084468383744",
+ "",
+ 0,
+ 11417981541647681583767488212054764084468383744.0_f64,
+ );
+
+ // Round-up, halfway
+ check_parse_float("9007199254740994", "", 0, 9007199254740994.0_f64);
+ check_parse_float("9007199254740995", "", 0, 9007199254740996.0_f64);
+ check_parse_float("9007199254740996", "", 0, 9007199254740996.0_f64);
+
+ check_parse_float("18014398509481988", "", 0, 18014398509481988.0_f64);
+ check_parse_float("18014398509481990", "", 0, 18014398509481992.0_f64);
+ check_parse_float("18014398509481992", "", 0, 18014398509481992.0_f64);
+
+ check_parse_float("9223372036854777856", "", 0, 9223372036854777856.0_f64);
+ check_parse_float("9223372036854778880", "", 0, 9223372036854779904.0_f64);
+ check_parse_float("9223372036854779904", "", 0, 9223372036854779904.0_f64);
+
+ check_parse_float(
+ "11417981541647681583767488212054764084468383744",
+ "",
+ 0,
+ 11417981541647681583767488212054764084468383744.0_f64,
+ );
+ check_parse_float(
+ "11417981541647682851418088440284165581171589120",
+ "",
+ 0,
+ 11417981541647684119068688668513567077874794496.0_f64,
+ );
+ check_parse_float(
+ "11417981541647684119068688668513567077874794496",
+ "",
+ 0,
+ 11417981541647684119068688668513567077874794496.0_f64,
+ );
+
+ // Round-up, above halfway
+ check_parse_float("9223372036854776833", "", 0, 9223372036854777856.0_f64);
+ check_parse_float(
+ "11417981541647680316116887983825362587765178369",
+ "",
+ 0,
+ 11417981541647681583767488212054764084468383744.0_f64,
+ );
+
+ // Rounding error
+ // Adapted from failures in strtod.
+ check_parse_float("2", "2250738585072014", -308, 2.2250738585072014e-308_f64);
+ check_parse_float("2", "2250738585072011360574097967091319759348195463516456480234261097248222220210769455165295239081350879141491589130396211068700864386945946455276572074078206217433799881410632673292535522868813721490129811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306666559949382757725720157630626906633326475653000092458883164330377797918696120494973903778297049050510806099407302629371289589500035837999672072543043602840788957717961509455167482434710307026091446215722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844239002654981983854879482922068947216898310996983658468140228542433306603398508864458040010349339704275671864433837704860378616227717385456230658746790140867233276367187499", -308, 2.225073858507201e-308_f64);
+ check_parse_float("2", "22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875", -308, 2.2250738585072014e-308_f64);
+ check_parse_float("2", "2250738585072011360574097967091319759348195463516456480234261097248222220210769455165295239081350879141491589130396211068700864386945946455276572074078206217433799881410632673292535522868813721490129811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306666559949382757725720157630626906633326475653000092458883164330377797918696120494973903778297049050510806099407302629371289589500035837999672072543043602840788957717961509455167482434710307026091446215722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844239002654981983854879482922068947216898310996983658468140228542433306603398508864458040010349339704275671864433837704860378616227717385456230658746790140867233276367187501", -308, 2.2250738585072014e-308_f64);
+ check_parse_float("179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791", "9999999999999999999999999999999999999999999999999999999999999999999999", 0, 1.7976931348623157e+308_f64);
+ check_parse_float("7", "4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999", -324, 5.0e-324_f64);
+ check_parse_float("7", "4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375", -324, 1.0e-323_f64);
+ check_parse_float("7", "4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001", -324, 1.0e-323_f64);
+ check_parse_float("", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125", 0, 0.0_f64);
+
+ // Rounding error
+ // Adapted from:
+ // https://www.exploringbinary.com/how-glibc-strtod-works/
+ check_parse_float("", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375", 0, 2.2250738585072011e-308_f64);
+
+ // Rounding error
+ // Adapted from test-parse-random failures.
+ check_parse_float("1009", "", -31, 1.009e-28_f64);
+ check_parse_float("18294", "", 304, f64::INFINITY);
+
+ // Rounding error
+ // Adapted from a @dangrabcad's issue #20.
+ check_parse_float("7", "689539722041643", 164, 7.689539722041643e164_f64);
+ check_parse_float("768953972204164300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "", 0, 7.689539722041643e164_f64);
+ check_parse_float("768953972204164300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 7.689539722041643e164_f64);
+
+ // Check other cases similar to @dangrabcad's issue #20.
+ check_parse_float("9223372036854776833", "0", 0, 9223372036854777856.0_f64);
+ check_parse_float(
+ "11417981541647680316116887983825362587765178369",
+ "0",
+ 0,
+ 11417981541647681583767488212054764084468383744.0_f64,
+ );
+ check_parse_float("9007199254740995", "0", 0, 9007199254740996.0_f64);
+ check_parse_float("18014398509481990", "0", 0, 18014398509481992.0_f64);
+ check_parse_float("9223372036854778880", "0", 0, 9223372036854779904.0_f64);
+ check_parse_float(
+ "11417981541647682851418088440284165581171589120",
+ "0",
+ 0,
+ 11417981541647684119068688668513567077874794496.0_f64,
+ );
+
+ // Check other cases ostensibly identified via proptest.
+ check_parse_float("71610528364411830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 71610528364411830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0_f64);
+ check_parse_float("126769393745745060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 126769393745745060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0_f64);
+ check_parse_float("38652960461239320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 38652960461239320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0_f64);
+}
diff --git a/third_party/rust/minimal-lexical/tests/rounding_tests.rs b/third_party/rust/minimal-lexical/tests/rounding_tests.rs
new file mode 100644
index 0000000000..794d696fb8
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/rounding_tests.rs
@@ -0,0 +1,64 @@
+use minimal_lexical::extended_float::ExtendedFloat;
+use minimal_lexical::rounding;
+
+#[test]
+fn round_test() {
+ let mut fp = ExtendedFloat {
+ mant: 9223372036854776832,
+ exp: -10,
+ };
+ rounding::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 = ExtendedFloat {
+ mant: 9223372036854776832,
+ exp: -10,
+ };
+ rounding::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 = ExtendedFloat {
+ mant: 9223372036854776832,
+ exp: -10,
+ };
+ rounding::round::<f64, _>(&mut fp, |f, s| {
+ rounding::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 = ExtendedFloat {
+ mant: 9223372036854778880,
+ exp: -10,
+ };
+ rounding::round::<f64, _>(&mut fp, |f, s| {
+ rounding::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 = ExtendedFloat {
+ mant: 9223372036854778880,
+ exp: -10,
+ };
+ rounding::round::<f64, _>(&mut fp, rounding::round_down);
+ assert_eq!(fp.mant, 1);
+ assert_eq!(fp.exp, 1);
+}
diff --git a/third_party/rust/minimal-lexical/tests/slow_tests.rs b/third_party/rust/minimal-lexical/tests/slow_tests.rs
new file mode 100644
index 0000000000..2afea69e90
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/slow_tests.rs
@@ -0,0 +1,337 @@
+mod stackvec;
+
+use minimal_lexical::bigint::Bigint;
+use minimal_lexical::extended_float::ExtendedFloat;
+use minimal_lexical::num::Float;
+use minimal_lexical::number::Number;
+use minimal_lexical::slow;
+use stackvec::vec_from_u32;
+
+fn b<F: Float>(float: F) -> (u64, i32) {
+ let fp = slow::b(float);
+ (fp.mant, fp.exp)
+}
+
+fn bh<F: Float>(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_test() {
+ // 5e-324, round-down.
+ let integer = b"2";
+ let fraction = b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999";
+ let num = Number {
+ mantissa: 2470328229206232720,
+ exponent: -342,
+ many_digits: true,
+ };
+ let fp = ExtendedFloat {
+ mant: 1 << 63,
+ exp: -63,
+ };
+ let result = slow::slow::<f64, _, _>(num.clone(), fp, integer.iter(), fraction.iter());
+ assert_eq!(result.mant, 0);
+ assert_eq!(result.exp, 0);
+
+ // 5e-324, round-up.
+ let fraction = b"47032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251";
+ let result = slow::slow::<f64, _, _>(num.clone(), fp, integer.iter(), fraction.iter());
+ assert_eq!(result.mant, 1);
+ assert_eq!(result.exp, 0);
+
+ // 8.98846567431158e+307
+ let integer = b"8";
+ let fraction = b"9884656743115805365666807213050294962762414131308158973971342756154045415486693752413698006024096935349884403114202125541629105369684531108613657287705365884742938136589844238179474556051429647415148697857438797685859063890851407391008830874765563025951597582513936655578157348020066364210154316532161708032";
+ let num = Number {
+ mantissa: 8988465674311580536,
+ exponent: 289,
+ many_digits: true,
+ };
+ let fp = ExtendedFloat {
+ mant: 9223372036854776832,
+ exp: 2035,
+ };
+ let result = slow::slow::<f64, _, _>(num.clone(), fp, integer.iter(), fraction.iter());
+ assert_eq!(result.mant, 0);
+ assert_eq!(result.exp, 2046);
+
+ // 8.988465674311582e+307
+ let fraction = b"98846567431158053656668072130502949627624141313081589739713427561540454154866937524136980060240969353498844031142021255416291053696845311086136572877053658847429381365898442381794745560514296474151486978574387976858590638908514073910088308747655630259515975825139366555781573480200663642101543165321617080321";
+ let result = slow::slow::<f64, _, _>(num.clone(), fp, integer.iter(), fraction.iter());
+ assert_eq!(result.mant, 1);
+ assert_eq!(result.exp, 2046);
+}
+
+#[test]
+fn positive_digit_comp_test() {
+ // 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>(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>(bigmant, exponent);
+ assert_eq!(result.mant, 1);
+ assert_eq!(result.exp, 2046);
+}
+
+#[test]
+fn negative_digit_comp_test() {
+ // 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 = ExtendedFloat {
+ mant: 1 << 63,
+ exp: -63,
+ };
+ let exponent = -324 + 1 - 755;
+ let result = slow::negative_digit_comp::<f64>(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>(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>(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 = ExtendedFloat {
+ mant: 1 << 63,
+ exp: -62,
+ };
+ let exponent = -324 + 1 - 755;
+ let result = slow::negative_digit_comp::<f64>(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>(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>(bigmant, fp, exponent);
+ assert_eq!(result.mant, 2);
+ assert_eq!(result.exp, 0);
+}
+
+#[test]
+fn parse_mantissa_test() {
+ let max_digits = f64::MAX_DIGITS;
+
+ // Large number of digits.
+ let integer = b"2";
+ let fraction = b"4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999";
+ let (bigmant, count) = slow::parse_mantissa(integer.iter(), fraction.iter(), max_digits);
+ let expected = 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,
+ ]);
+ assert_eq!(&*bigmant.data, &*expected);
+ assert_eq!(count, 755);
+
+ // Truncation.
+ let integer = b"7";
+ let fraction = b"4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375332669816033062329967789262837";
+ let (bigmant, count) = slow::parse_mantissa(integer.iter(), fraction.iter(), max_digits);
+ let expected = vec_from_u32(&[
+ 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.
+ let integer = b"74109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375332669816033062329967789262837";
+ let fraction = b"";
+ let (bigmant, count) = slow::parse_mantissa(integer.iter(), fraction.iter(), max_digits);
+ assert_eq!(&*bigmant.data, &*expected);
+ assert_eq!(count, max_digits + 1);
+
+ // Multiple of step (check we add our temporary correctly).
+ let integer = b"7410984687618698162648531893023320585475897039214871466383785237510132609053131277979497545424539885696948470431685765963899850655339096945981621940161728171894510697854671067917687257517734731555330779540854980960845750095811137303474765809687100959097544227100475730780971111893578483867565399878350301522805593404659373979179073872386829939581848166016912201945649993128979841136206248449867871357218035220901702390328579173252022052897402080290685402160661237554998340267130003581248647904138574340187552090159017259254714629617513415977493871857473787096164563890871811984127167305601704549300470526959016576377688490826798697257336652176556794107250876433756084600398490497214911746308553955635418864151316847843631308023759629577398300170898437533266981";
+ let fraction = b"";
+ let (bigmant, count) = slow::parse_mantissa(integer.iter(), fraction.iter(), max_digits);
+ let expected = vec_from_u32(&[
+ 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);
+}
diff --git a/third_party/rust/minimal-lexical/tests/stackvec.rs b/third_party/rust/minimal-lexical/tests/stackvec.rs
new file mode 100644
index 0000000000..d5587f23f8
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/stackvec.rs
@@ -0,0 +1,32 @@
+use minimal_lexical::bigint;
+#[cfg(feature = "alloc")]
+pub use minimal_lexical::heapvec::HeapVec as VecType;
+#[cfg(not(feature = "alloc"))]
+pub use minimal_lexical::stackvec::StackVec as VecType;
+
+pub fn vec_from_u32(x: &[u32]) -> VecType {
+ let mut vec = VecType::new();
+ #[cfg(not(all(target_pointer_width = "64", not(target_arch = "sparc"))))]
+ {
+ for &xi in x {
+ vec.try_push(xi as bigint::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 bigint::Limb).unwrap(),
+ 2 => {
+ let xi0 = xi[0] as bigint::Limb;
+ let xi1 = xi[1] as bigint::Limb;
+ vec.try_push((xi1 << 32) | xi0).unwrap()
+ },
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ vec
+}
diff --git a/third_party/rust/minimal-lexical/tests/vec_tests.rs b/third_party/rust/minimal-lexical/tests/vec_tests.rs
new file mode 100644
index 0000000000..3a5f5886ad
--- /dev/null
+++ b/third_party/rust/minimal-lexical/tests/vec_tests.rs
@@ -0,0 +1,395 @@
+mod stackvec;
+
+use core::cmp;
+use minimal_lexical::bigint;
+use stackvec::{vec_from_u32, VecType};
+
+// u64::MAX and Limb::MAX for older Rustc versions.
+const U64_MAX: u64 = 0xffff_ffff_ffff_ffff;
+// LIMB_MAX
+#[cfg(all(target_pointer_width = "64", not(target_arch = "sparc")))]
+const LIMB_MAX: u64 = U64_MAX;
+#[cfg(not(all(target_pointer_width = "64", not(target_arch = "sparc"))))]
+const LIMB_MAX: u32 = 0xffff_ffff;
+
+#[test]
+fn simple_test() {
+ // Test the simple properties of the stack vector.
+ let mut x = VecType::from_u64(1);
+ assert_eq!(x.len(), 1);
+ assert_eq!(x.is_empty(), false);
+ assert_eq!(x.capacity(), bigint::BIGINT_LIMBS);
+ 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);
+ if bigint::LIMB_BITS == 32 {
+ assert_eq!(x.hi64(), (0x8000000280000000, false));
+ } else {
+ assert_eq!(x.hi64(), (0x8000000000000002, true));
+ }
+ let rview = bigint::rview(&x);
+ assert_eq!(x[0], 5);
+ assert_eq!(x[1], 1);
+ assert_eq!(rview[0], 1);
+ assert_eq!(rview[1], 5);
+ assert_eq!(x.len(), 2);
+
+ assert_eq!(VecType::from_u64(U64_MAX).hi64(), (U64_MAX, false));
+}
+
+#[test]
+fn hi64_test() {
+ assert_eq!(VecType::from_u64(0xA).hi64(), (0xA000000000000000, false));
+ assert_eq!(VecType::from_u64(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_u64(1);
+ let y = VecType::from_u64(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_u64(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 bigint::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);
+
+ let mut x = VecType::from_u64(0xFFFFFFFF);
+ let y = VecType::from_u64(5);
+ x *= &y;
+ let expected: VecType = vec_from_u32(&[0xFFFFFFFB, 0x4]);
+ assert_eq!(&*x, &*expected);
+
+ // Test with carry
+ let mut x = VecType::from_u64(1);
+ assert_eq!(&*x, &[1]);
+ x.add_small(LIMB_MAX);
+ assert_eq!(&*x, &[0, 1]);
+}
+
+#[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_u64(4294967295);
+ bigint::small_add(&mut x, 5);
+ let expected: VecType = vec_from_u32(&[4, 1]);
+ assert_eq!(&*x, &*expected);
+
+ let mut x = VecType::from_u64(5);
+ bigint::small_add(&mut x, 7);
+ let expected = VecType::from_u64(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_u64(5);
+ bigint::small_mul(&mut x, 7);
+ let expected = VecType::from_u64(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_u64(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_u64(1);
+ bigint::pow(&mut x, 2);
+ let expected = VecType::from_u64(25);
+ assert_eq!(&*x, &*expected);
+
+ let mut x = VecType::from_u64(1);
+ bigint::pow(&mut x, 15);
+ let expected: VecType = vec_from_u32(&[452807053, 7]);
+ assert_eq!(&*x, &*expected);
+
+ let mut x = VecType::from_u64(1);
+ bigint::pow(&mut x, 16);
+ let expected: VecType = vec_from_u32(&[2264035265, 35]);
+ assert_eq!(&*x, &*expected);
+
+ let mut x = VecType::from_u64(1);
+ bigint::pow(&mut x, 17);
+ let expected: VecType = vec_from_u32(&[2730241733, 177]);
+ assert_eq!(&*x, &*expected);
+
+ let mut x = VecType::from_u64(1);
+ bigint::pow(&mut x, 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_u64(4294967295);
+ let y = VecType::from_u64(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_u64(5);
+ let y = VecType::from_u64(7);
+ bigint::large_add(&mut x, &y);
+ let expected = VecType::from_u64(12);
+ assert_eq!(&*x, &*expected);
+
+ // Single carry, internal overflow
+ let mut x = VecType::from_u64(0x80000000FFFFFFFF);
+ let y = VecType::from_u64(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_u64(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_u64(0xFFFFFFFF);
+ let y = VecType::from_u64(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_u64(0xFFFFFFFF);
+ let y = VecType::from_u64(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]
+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_u64(1 << 31);
+ assert_eq!(bigint::bit_length(&x), 32);
+}
+
+#[test]
+fn shl_bits_test() {
+ let mut x = VecType::from_u64(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_u64(0xD2210408);
+ bigint::shl_limbs(&mut x, 2);
+ let expected: VecType = if bigint::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_u64(0xD2210408);
+ bigint::shl(&mut x, 5);
+ let expected: VecType = vec_from_u32(&[0x44208100, 0x1A]);
+ assert_eq!(&*x, &*expected);
+
+ bigint::shl(&mut x, 32);
+ let expected: VecType = vec_from_u32(&[0, 0x44208100, 0x1A]);
+ assert_eq!(&*x, &*expected);
+
+ bigint::shl(&mut x, 27);
+ 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);
+ let expected: VecType = vec_from_u32(&[0x400200, 0x802004, 0x44208101, 0x1A]);
+ assert_eq!(&*x, &*expected);
+
+ bigint::shl(&mut x, 32);
+ let expected: VecType = vec_from_u32(&[0, 0x400200, 0x802004, 0x44208101, 0x1A]);
+ assert_eq!(&*x, &*expected);
+
+ bigint::shl(&mut x, 27);
+ let expected: VecType = vec_from_u32(&[0, 0, 0x20020010, 0x8040100, 0xD2210408]);
+ assert_eq!(&*x, &*expected);
+}