diff --git a/common/src/float_ops.rs b/common/src/float_ops.rs index c0e7a359b..e54513ad6 100644 --- a/common/src/float_ops.rs +++ b/common/src/float_ops.rs @@ -128,6 +128,29 @@ pub fn format_exponent(precision: usize, magnitude: f64, case: Case) -> String { } } +pub fn format_general(precision: usize, magnitude: f64, case: Case) -> String { + match magnitude { + magnitude if magnitude.is_finite() => { + let r_exp = format!("{:.*e}", precision, magnitude); + let mut parts = r_exp.splitn(2, 'e'); + let base = parts.next().unwrap(); + let exponent = parts.next().unwrap().parse::().unwrap(); + if exponent < -4 || exponent >= (precision as i64) { + let e = match case { + Case::Lower => 'e', + Case::Upper => 'E', + }; + format!("{}{}{:+#03}", base, e, exponent) + } else { + format!("{}", magnitude) + } + } + magnitude if magnitude.is_nan() => format_nan(case), + magnitude if magnitude.is_infinite() => format_inf(case), + _ => "".to_string(), + } +} + pub fn to_string(value: f64) -> String { let lit = format!("{:e}", value); if let Some(position) = lit.find('e') { diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index 396b2257e..fe1aeb81a 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -293,24 +293,6 @@ impl CFormatSpec { } } - fn normalize_float(&self, num: f64) -> (f64, i32) { - let mut fraction = num; - let mut exponent = 0; - loop { - if fraction >= 10.0 { - fraction /= 10.0; - exponent += 1; - } else if fraction < 1.0 && fraction > 0.0 { - fraction *= 10.0; - exponent -= 1; - } else { - break; - } - } - - (fraction, exponent) - } - pub(crate) fn format_float(&self, num: f64) -> String { let sign_string = if num.is_sign_positive() { self.flags.sign_string() @@ -337,17 +319,12 @@ impl CFormatSpec { } CFormatType::Float(CFloatType::General(case)) => { let precision = if precision == 0 { 1 } else { precision }; - let (fraction, exponent) = self.normalize_float(num.abs()); - if exponent < -4 || exponent >= (precision as i32) { - let case = match case { - CFormatCase::Lowercase => 'e', - CFormatCase::Uppercase => 'E', - }; - format!("{}{}{:+03}", fraction, case, exponent) - } else { - let magnitude = num.abs(); - format!("{}", magnitude) - } + let case = match case { + CFormatCase::Lowercase => float_ops::Case::Lower, + CFormatCase::Uppercase => float_ops::Case::Upper, + }; + let magnitude = num.abs(); + float_ops::format_general(precision, magnitude, case) } _ => unreachable!(), }; diff --git a/vm/src/format.rs b/vm/src/format.rs index af552593d..13b97858c 100644 --- a/vm/src/format.rs +++ b/vm/src/format.rs @@ -369,12 +369,16 @@ impl FormatSpec { Some(FormatType::Number) => { Err("Format code 'n' for object of type 'float' not implemented yet") } - Some(FormatType::GeneralFormatUpper) => { - Err("Format code 'G' for object of type 'float' not implemented yet") - } - Some(FormatType::GeneralFormatLower) => { - Err("Format code 'g' for object of type 'float' not implemented yet") - } + Some(FormatType::GeneralFormatUpper) => Ok(float_ops::format_general( + precision, + magnitude, + float_ops::Case::Upper, + )), + Some(FormatType::GeneralFormatLower) => Ok(float_ops::format_general( + precision, + magnitude, + float_ops::Case::Lower, + )), Some(FormatType::ExponentUpper) => Ok(float_ops::format_exponent( precision, magnitude,