1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-31 04:57:45 +00:00

uucode: format: format_float_non_finite: Take in &ExtendedBigDecimal

First modify Format.fmt to extract absolute value and sign, then
modify printing on non-finite values (inf or nan).
This commit is contained in:
Nicolas Boichat 2025-03-07 12:09:40 +01:00 committed by Sylvestre Ledru
parent 8e11dab995
commit ce14d01da5

View file

@ -5,6 +5,7 @@
//! Utilities for formatting numbers in various formats //! Utilities for formatting numbers in various formats
use num_traits::Signed;
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use std::cmp::min; use std::cmp::min;
use std::io::Write; use std::io::Write;
@ -234,37 +235,44 @@ impl Default for Float {
impl Formatter<&ExtendedBigDecimal> for Float { impl Formatter<&ExtendedBigDecimal> for Float {
fn fmt(&self, writer: impl Write, e: &ExtendedBigDecimal) -> std::io::Result<()> { fn fmt(&self, writer: impl Write, e: &ExtendedBigDecimal) -> std::io::Result<()> {
// TODO: For now we just convert ExtendedBigDecimal back to f64, fix this. /* TODO: Might be nice to implement Signed trait for ExtendedBigDecimal (for abs)
let f = match e { * at some point, but that requires implementing a _lot_ of traits.
ExtendedBigDecimal::BigDecimal(bd) => bd.to_f64().unwrap(), * Note that "negative" would be the output of "is_sign_negative" on a f64:
ExtendedBigDecimal::Infinity => f64::INFINITY, * it returns true on `-0.0`.
ExtendedBigDecimal::MinusInfinity => f64::NEG_INFINITY, */
ExtendedBigDecimal::MinusZero => -0.0, let (abs, negative) = match e {
ExtendedBigDecimal::Nan => f64::NAN, ExtendedBigDecimal::BigDecimal(bd) => {
ExtendedBigDecimal::MinusNan => -f64::NAN, (ExtendedBigDecimal::BigDecimal(bd.abs()), bd.is_negative())
}
ExtendedBigDecimal::MinusZero => (ExtendedBigDecimal::zero(), true),
ExtendedBigDecimal::Infinity => (ExtendedBigDecimal::Infinity, false),
ExtendedBigDecimal::MinusInfinity => (ExtendedBigDecimal::Infinity, true),
ExtendedBigDecimal::Nan => (ExtendedBigDecimal::Nan, false),
ExtendedBigDecimal::MinusNan => (ExtendedBigDecimal::Nan, true),
}; };
let x = f.abs();
let s = if x.is_finite() { let s = match abs {
match self.variant { ExtendedBigDecimal::BigDecimal(bd) => {
FloatVariant::Decimal => { // TODO: Convert format_float_* functions to take in a BigDecimal.
format_float_decimal(x, self.precision, self.force_decimal) let x = bd.to_f64().unwrap();
} match self.variant {
FloatVariant::Scientific => { FloatVariant::Decimal => {
format_float_scientific(x, self.precision, self.case, self.force_decimal) format_float_decimal(x, self.precision, self.force_decimal)
} }
FloatVariant::Shortest => { FloatVariant::Scientific => {
format_float_shortest(x, self.precision, self.case, self.force_decimal) format_float_scientific(x, self.precision, self.case, self.force_decimal)
} }
FloatVariant::Hexadecimal => { FloatVariant::Shortest => {
format_float_hexadecimal(x, self.precision, self.case, self.force_decimal) format_float_shortest(x, self.precision, self.case, self.force_decimal)
}
FloatVariant::Hexadecimal => {
format_float_hexadecimal(x, self.precision, self.case, self.force_decimal)
}
} }
} }
} else { _ => format_float_non_finite(&abs, self.case),
format_float_non_finite(x, self.case)
}; };
let sign_indicator = get_sign_indicator(self.positive_sign, negative);
let sign_indicator = get_sign_indicator(self.positive_sign, f.is_sign_negative());
write_output(writer, sign_indicator, s, self.width, self.alignment) write_output(writer, sign_indicator, s, self.width, self.alignment)
} }
@ -322,12 +330,18 @@ fn get_sign_indicator(sign: PositiveSign, negative: bool) -> String {
} }
} }
fn format_float_non_finite(f: f64, case: Case) -> String { fn format_float_non_finite(e: &ExtendedBigDecimal, case: Case) -> String {
debug_assert!(!f.is_finite()); let mut s = match e {
let mut s = format!("{f}"); ExtendedBigDecimal::Infinity => String::from("inf"),
match case { ExtendedBigDecimal::Nan => String::from("nan"),
Case::Lowercase => s.make_ascii_lowercase(), // Forces NaN back to nan. _ => {
Case::Uppercase => s.make_ascii_uppercase(), debug_assert!(false);
String::from("INVALID")
}
};
if case == Case::Uppercase {
s.make_ascii_uppercase();
} }
s s
} }
@ -532,7 +546,10 @@ fn write_output(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::format::num_format::{Case, ForceDecimal}; use crate::format::{
num_format::{Case, ForceDecimal},
ExtendedBigDecimal,
};
#[test] #[test]
fn unsigned_octal() { fn unsigned_octal() {
@ -559,12 +576,12 @@ mod test {
fn non_finite_float() { fn non_finite_float() {
use super::format_float_non_finite; use super::format_float_non_finite;
let f = |x| format_float_non_finite(x, Case::Lowercase); let f = |x| format_float_non_finite(x, Case::Lowercase);
assert_eq!(f(f64::NAN), "nan"); assert_eq!(f(&ExtendedBigDecimal::Nan), "nan");
assert_eq!(f(f64::INFINITY), "inf"); assert_eq!(f(&ExtendedBigDecimal::Infinity), "inf");
let f = |x| format_float_non_finite(x, Case::Uppercase); let f = |x| format_float_non_finite(x, Case::Uppercase);
assert_eq!(f(f64::NAN), "NAN"); assert_eq!(f(&ExtendedBigDecimal::Nan), "NAN");
assert_eq!(f(f64::INFINITY), "INF"); assert_eq!(f(&ExtendedBigDecimal::Infinity), "INF");
} }
#[test] #[test]