Skip to content

Commit

Permalink
fix: F56 Display trait new algorithm to display 12 sig figs
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenLove committed Feb 29, 2024
1 parent e020dd3 commit 5814bf2
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 14 deletions.
46 changes: 46 additions & 0 deletions builtins/src/types/numbers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,52 @@ mod tests {
)
}

#[test]
fn test_f56_formatting() {
// F56 should have a maximum of 12 decimal digits displayed
// And the 12th digit should be rounded using the 13th digit
// If we input an f64 with the 13th digit of 5
// The nearest F56 representation might have the 13th digit become 4 or 6
// So be wary that rounding may not occur as expected
// 3.999_999_999_995 rounds down instead of rounding up to 4
let map_from_value_to_expected_string = [
// (3.999_999_999_995, "4"), // bad rounding
(399.999_999_999_58527_f64, "400"),
(399.999_999_999_585_f64, "400"),
(399.999_999_999_58_f64, "400"),
(399.999_999_999_6_f64, "400"),
(399.999_999_999_f64, "399.999999999"),
(
0.000_000_012_312_312_412_412_312_3_f64,
"0.0000000123123124124",
),
(0.000_000_012_312_312_452_57_f64, "0.0000000123123124526"),
(399_999_999.999_58_f64, "400000000"),
(
399_999_999_999_600_000_000_000_000_000_000_0_f64,
"4000000000000000000000000000000000",
),
(
399_999_999_999_600_000_000_000_000_000_000_0_f64,
"4000000000000000000000000000000000",
),
// special values
(f64::NAN, "NaN"),
(f64::INFINITY, "inf"),
(f64::NEG_INFINITY, "-inf"),
(0.0, "0"),
(-0.0, "-0"),
(f64::MIN_POSITIVE, "0"),
(F56::MIN_POSITIVE.into(), "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002983336292479999"),
];
for (f, expected) in map_from_value_to_expected_string.iter() {
// println!("{:?}", f);
let f56 = F56::from(*f);
let formatted = format!("{:}", f56);
assert_eq!(formatted, *expected);
}
}

#[test]
fn test_i32_conversions_rust_to_value() {
let mut vm = new_slosh_vm();
Expand Down
3 changes: 2 additions & 1 deletion slosh/benches/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ fn run_float_script(n: usize, m: f32, expected: f64) {
let last = run_reader(&mut reader);
match last {
Ok(Value::Float(f)) => {
assert_eq!(f64::from(f), expected);
assert_eq!(f.to_string(), expected.to_string());
// assert_eq!(f64::from(f), expected);
}
_ => {
panic!("Not a float");
Expand Down
6 changes: 3 additions & 3 deletions slosh/benches/bench.slosh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

(def pu (eval-pol 100 0.5))
(prn "(eval-pol 100 0.5) =>\n" pu)
(prn "passed: " (equal? pu 399.99999999958527))
(prn "passed: " (equal? pu 400))

(def pu (eval-pol 1000 0.05))
(prn "(eval-pol 1000 0.05) =>\n" pu)
(prn "passed: " (equal? pu 2105.2631578924484))
(prn "passed: " (equal? pu 2105.26315789))

(def pu (eval-pol 10000 0.2))
(prn "(eval-pol 10000 0.2) =>\n" pu)
(prn "passed: " (equal? pu 24999.999999998603))
(prn "passed: " (equal? pu 2500))

21 changes: 11 additions & 10 deletions vm/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,18 @@ impl Display for F56 {
// F56 only has 12, meaning that .0023 appears as .0022999999999999687
// if F56 knew to only print 12 digits then it would be fine,
// but when going through f64, it thinks it has 15 perfect digits.
let as_f64 = f64::from(*self);

// We can set the precision to 12 but that increases numbers like 1.0 to 1.0000000000000
// So let's do that, and remove the trailing zeros and decimal points added on
let first_pass = format!("{:.*}", F56::DIGITS, f64::from(*self));
// remove trailing zeros and trailing decimal point
let second_pass = if first_pass.contains('.') {
first_pass.trim_end_matches('0').trim_end_matches('.')
} else {
&first_pass
};
write!(f, "{}", second_pass)
// Handle special cases by printing the f64 value
if as_f64.is_nan() || as_f64.is_infinite() || as_f64 == 0.0 {
return write!(f, "{}", as_f64);
}

// round to a max of F56::DIGITS sig figs
let exponent_value = as_f64.log10().floor() as i32; // the number after 'e' in scientific notation
let scale = 10f64.powi(exponent_value - F56::DIGITS as i32 + 1);
let rounded = (as_f64 / scale).round() * scale;
write!(f, "{}", rounded)
}
}
impl From<f64> for F56 {
Expand Down

0 comments on commit 5814bf2

Please sign in to comment.