diff --git a/crates/model/src/numfmt.rs b/crates/model/src/numfmt.rs index c3cf1713..da2e2315 100644 --- a/crates/model/src/numfmt.rs +++ b/crates/model/src/numfmt.rs @@ -204,7 +204,12 @@ fn sci(toks: &[Tok], v: f64, sep: char, dec: char) -> Option { let (mut m, mut exp) = (0.0, 0i32); if v != 0.0 { exp = v.log10().floor() as i32; - m = v / 10f64.powi(exp); + m = if exp < -300 { + // 10^exp underflows for subnormals; scale in two steps. + v * 1e300 / 10f64.powi(exp + 300) + } else { + v / 10f64.powi(exp) + }; if !m.is_finite() { m = 0.0; exp = 0; @@ -286,6 +291,12 @@ mod tests { const RUB: &str = r#"_-* #\ ##0\ "₽"_-;\-* #\ ##0\ "₽"_-;_-* "-"??\ "₽"_-;_-@_-"#; + #[test] + fn scientific_subnormal() { + assert_eq!(format("0.00E+00", 5e-324, None), "4.94E-324"); + assert_eq!(format("0.00E+00", f64::MIN_POSITIVE, None), "2.23E-308"); + } + #[test] fn russian_accounting_roubles() { assert_eq!(format(RUB, 800_000.0, Some("ru-RU")), "800\u{a0}000 ₽");