diff --git a/lexical-core/tests/float_pow2_tests.rs b/lexical-core/tests/float_pow2_tests.rs index 33d18b6f..1e14e12a 100644 --- a/lexical-core/tests/float_pow2_tests.rs +++ b/lexical-core/tests/float_pow2_tests.rs @@ -103,6 +103,7 @@ macro_rules! test_all { test_radix!($f, 8, $buffer, $data); test_radix!($f, 16, $buffer, $data); test_radix!($f, 32, $buffer, $data); + #[cfg(feature = "radix")] test_radix!($f, 36, $buffer, $data); }}; } diff --git a/lexical-parse-float/src/number.rs b/lexical-parse-float/src/number.rs index d901feef..44632d97 100644 --- a/lexical-parse-float/src/number.rs +++ b/lexical-parse-float/src/number.rs @@ -38,11 +38,9 @@ impl Number<'_> { #[inline(always)] pub fn is_fast_path(&self) -> bool { let format = NumberFormat:: {}; - debug_assert!( - format.mantissa_radix() == format.exponent_base(), - "fast path requires same radix" - ); - F::min_exponent_fast_path(format.radix()) <= self.exponent + + format.mantissa_radix() == format.exponent_base() + && F::min_exponent_fast_path(format.radix()) <= self.exponent && self.exponent <= F::max_exponent_disguised_fast_path(format.radix()) && self.mantissa <= F::MAX_MANTISSA_FAST_PATH && !self.many_digits @@ -63,10 +61,12 @@ impl Number<'_> { #[allow(clippy::let_unit_value)] // reason = "untentional ASM drop for X87 FPUs" pub fn try_fast_path(&self) -> Option { let format = NumberFormat:: {}; - debug_assert!( - format.mantissa_radix() == format.exponent_base(), - "fast path requires same radix" - ); + + // fast path requires same radix + if format.mantissa_radix() != format.exponent_base() { + return None; + } + // The fast path crucially depends on arithmetic being rounded to the correct // number of bits without any intermediate rounding. On x86 (without SSE // or SSE2) this requires the precision of the x87 FPU stack to be @@ -113,6 +113,7 @@ impl Number<'_> { #[allow(clippy::let_unit_value)] // reason = "untentional ASM drop for X87 FPUs" pub fn force_fast_path(&self) -> F { let format = NumberFormat:: {}; + debug_assert!( format.mantissa_radix() == format.exponent_base(), "fast path requires same radix" diff --git a/lexical-parse-float/tests/issue_87_tests.rs b/lexical-parse-float/tests/issue_87_tests.rs new file mode 100644 index 00000000..c8e785a9 --- /dev/null +++ b/lexical-parse-float/tests/issue_87_tests.rs @@ -0,0 +1,16 @@ +#![cfg(all(feature = "format", feature = "power-of-two"))] + +use lexical_parse_float::{options::HEX_FLOAT, FromLexicalWithOptions}; +use lexical_util::format::C_HEX_STRING; + +#[test] +fn issue_87_test() { + assert_eq!( + f64::from_lexical_with_options::<{ C_HEX_STRING }>(b"1f.5p-2", &HEX_FLOAT), + Ok(0x1f5 as f64 / (16 * 4) as f64) + ); + assert_eq!( + f64::from_lexical_with_options::<{ C_HEX_STRING }>(b"c2.a8p6", &HEX_FLOAT), + Ok((0xc2a8 * (1 << 6)) as f64 / 256 as f64) + ); +} diff --git a/lexical-parse-float/tests/number_tests.rs b/lexical-parse-float/tests/number_tests.rs index d74d09e1..1e464c27 100644 --- a/lexical-parse-float/tests/number_tests.rs +++ b/lexical-parse-float/tests/number_tests.rs @@ -1,6 +1,9 @@ use lexical_parse_float::number::Number; use lexical_util::format::STANDARD; +#[cfg(all(feature = "format", feature = "power-of-two"))] +use lexical_util::format::C_HEX_STRING; + #[test] fn is_fast_path_test() { let mut number = Number { @@ -11,6 +14,11 @@ fn is_fast_path_test() { integer: &[], fraction: None, }; + + #[cfg(all(feature = "format", feature = "power-of-two"))] + assert_eq!(number.is_fast_path::(), false); + #[cfg(all(feature = "format", feature = "power-of-two"))] + assert_eq!(number.is_fast_path::(), false); assert_eq!(number.is_fast_path::(), true); assert_eq!(number.is_fast_path::(), true); @@ -62,6 +70,11 @@ fn try_fast_path_test() { integer: &[], fraction: None, }; + + #[cfg(all(feature = "format", feature = "power-of-two"))] + assert_eq!(number.try_fast_path::(), None); + #[cfg(all(feature = "format", feature = "power-of-two"))] + assert_eq!(number.try_fast_path::(), None); assert_eq!(number.try_fast_path::(), Some(1.2345)); assert_eq!(number.try_fast_path::(), Some(1.2345));