1use crate::{
10 memory::{Produced, ProductionControl, ProductionString},
11 ValueRetentionError,
12};
13
14#[must_use]
16pub fn format_float_pg(f: f64) -> String {
17 format_float_pg_with_control(f, &ProductionControl::uncontrolled())
18 .expect("ordinary float formatting")
19 .into_uncontrolled()
20 .expect("ordinary float text")
21}
22
23pub fn format_float_pg_with_control(
24 f: f64,
25 control: &ProductionControl<'_>,
26) -> Result<Produced<String>, ValueRetentionError> {
27 if f.is_nan() {
28 return control.copy_text("NaN");
29 }
30 if f.is_infinite() {
31 return control.copy_text(if f > 0.0 { "Infinity" } else { "-Infinity" });
32 }
33 let sci = control.format(format_args!("{f:e}"))?;
34 let Some((mantissa, exp)) = sci.split_once('e') else {
35 return Ok(sci);
36 };
37 let Ok(exp) = exp.parse::<i32>() else {
38 return Ok(sci);
39 };
40 let mut digits = ProductionString::new(*control);
41 for character in mantissa.chars().filter(char::is_ascii_digit) {
42 digits.push(character)?;
43 }
44 let sign = if mantissa.starts_with('-') { "-" } else { "" };
45 let mut output = ProductionString::new(*control);
46 output.push_str(sign)?;
47 if (-4..15).contains(&exp) {
48 if exp >= 0 {
49 let Ok(int_len) = usize::try_from(exp + 1) else {
50 return Ok(sci);
51 };
52 if digits.len() > int_len {
53 output.push_str(&digits[..int_len])?;
54 output.push('.')?;
55 output.push_str(&digits[int_len..])?;
56 } else {
57 output.push_str(&digits)?;
58 for _ in digits.len()..int_len {
59 output.push('0')?;
60 }
61 }
62 } else {
63 let Ok(zero_count) = usize::try_from(-exp - 1) else {
64 return Ok(sci);
65 };
66 output.push_str("0.")?;
67 for _ in 0..zero_count {
68 output.push('0')?;
69 }
70 output.push_str(&digits)?;
71 }
72 } else {
73 output.push_str(&digits[..1])?;
74 if digits.len() > 1 {
75 output.push('.')?;
76 output.push_str(&digits[1..])?;
77 }
78 output.push_str(&control.format(format_args!("e{exp:+03}"))?)?;
79 }
80 output.finish()
81}
82
83#[cfg(test)]
84mod tests;