Skip to content

Commit

Permalink
Fix Alexhuszagh#87 parsing hexfloats
Browse files Browse the repository at this point in the history
Signed-off-by: max <[email protected]>
  • Loading branch information
PizzasBear committed Oct 22, 2024
1 parent 28985e5 commit 62e40dc
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 9 deletions.
1 change: 1 addition & 0 deletions lexical-core/tests/float_pow2_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}};
}
Expand Down
19 changes: 10 additions & 9 deletions lexical-parse-float/src/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ impl Number<'_> {
#[inline(always)]
pub fn is_fast_path<F: RawFloat, const FORMAT: u128>(&self) -> bool {
let format = NumberFormat::<FORMAT> {};
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
Expand All @@ -63,10 +61,12 @@ impl Number<'_> {
#[allow(clippy::let_unit_value)] // reason = "untentional ASM drop for X87 FPUs"
pub fn try_fast_path<F: RawFloat, const FORMAT: u128>(&self) -> Option<F> {
let format = NumberFormat::<FORMAT> {};
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
Expand Down Expand Up @@ -113,6 +113,7 @@ impl Number<'_> {
#[allow(clippy::let_unit_value)] // reason = "untentional ASM drop for X87 FPUs"
pub fn force_fast_path<F: RawFloat, const FORMAT: u128>(&self) -> F {
let format = NumberFormat::<FORMAT> {};

debug_assert!(
format.mantissa_radix() == format.exponent_base(),
"fast path requires same radix"
Expand Down
16 changes: 16 additions & 0 deletions lexical-parse-float/tests/issue_87_tests.rs
Original file line number Diff line number Diff line change
@@ -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)
);
}
13 changes: 13 additions & 0 deletions lexical-parse-float/tests/number_tests.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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::<f32, { C_HEX_STRING }>(), false);
#[cfg(all(feature = "format", feature = "power-of-two"))]
assert_eq!(number.is_fast_path::<f64, { C_HEX_STRING }>(), false);
assert_eq!(number.is_fast_path::<f32, { STANDARD }>(), true);
assert_eq!(number.is_fast_path::<f64, { STANDARD }>(), true);

Expand Down Expand Up @@ -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::<f32, { C_HEX_STRING }>(), None);
#[cfg(all(feature = "format", feature = "power-of-two"))]
assert_eq!(number.try_fast_path::<f64, { C_HEX_STRING }>(), None);
assert_eq!(number.try_fast_path::<f32, { STANDARD }>(), Some(1.2345));
assert_eq!(number.try_fast_path::<f64, { STANDARD }>(), Some(1.2345));

Expand Down

0 comments on commit 62e40dc

Please sign in to comment.