mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 12:37:49 +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:
parent
8e11dab995
commit
ce14d01da5
1 changed files with 54 additions and 37 deletions
|
@ -5,6 +5,7 @@
|
|||
|
||||
//! Utilities for formatting numbers in various formats
|
||||
|
||||
use num_traits::Signed;
|
||||
use num_traits::ToPrimitive;
|
||||
use std::cmp::min;
|
||||
use std::io::Write;
|
||||
|
@ -234,37 +235,44 @@ impl Default for Float {
|
|||
|
||||
impl Formatter<&ExtendedBigDecimal> for Float {
|
||||
fn fmt(&self, writer: impl Write, e: &ExtendedBigDecimal) -> std::io::Result<()> {
|
||||
// TODO: For now we just convert ExtendedBigDecimal back to f64, fix this.
|
||||
let f = match e {
|
||||
ExtendedBigDecimal::BigDecimal(bd) => bd.to_f64().unwrap(),
|
||||
ExtendedBigDecimal::Infinity => f64::INFINITY,
|
||||
ExtendedBigDecimal::MinusInfinity => f64::NEG_INFINITY,
|
||||
ExtendedBigDecimal::MinusZero => -0.0,
|
||||
ExtendedBigDecimal::Nan => f64::NAN,
|
||||
ExtendedBigDecimal::MinusNan => -f64::NAN,
|
||||
/* TODO: Might be nice to implement Signed trait for ExtendedBigDecimal (for abs)
|
||||
* at some point, but that requires implementing a _lot_ of traits.
|
||||
* Note that "negative" would be the output of "is_sign_negative" on a f64:
|
||||
* it returns true on `-0.0`.
|
||||
*/
|
||||
let (abs, negative) = match e {
|
||||
ExtendedBigDecimal::BigDecimal(bd) => {
|
||||
(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() {
|
||||
match self.variant {
|
||||
FloatVariant::Decimal => {
|
||||
format_float_decimal(x, self.precision, self.force_decimal)
|
||||
}
|
||||
FloatVariant::Scientific => {
|
||||
format_float_scientific(x, self.precision, self.case, self.force_decimal)
|
||||
}
|
||||
FloatVariant::Shortest => {
|
||||
format_float_shortest(x, self.precision, self.case, self.force_decimal)
|
||||
}
|
||||
FloatVariant::Hexadecimal => {
|
||||
format_float_hexadecimal(x, self.precision, self.case, self.force_decimal)
|
||||
let s = match abs {
|
||||
ExtendedBigDecimal::BigDecimal(bd) => {
|
||||
// TODO: Convert format_float_* functions to take in a BigDecimal.
|
||||
let x = bd.to_f64().unwrap();
|
||||
match self.variant {
|
||||
FloatVariant::Decimal => {
|
||||
format_float_decimal(x, self.precision, self.force_decimal)
|
||||
}
|
||||
FloatVariant::Scientific => {
|
||||
format_float_scientific(x, self.precision, self.case, self.force_decimal)
|
||||
}
|
||||
FloatVariant::Shortest => {
|
||||
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(x, self.case)
|
||||
_ => format_float_non_finite(&abs, self.case),
|
||||
};
|
||||
|
||||
let sign_indicator = get_sign_indicator(self.positive_sign, f.is_sign_negative());
|
||||
let sign_indicator = get_sign_indicator(self.positive_sign, negative);
|
||||
|
||||
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 {
|
||||
debug_assert!(!f.is_finite());
|
||||
let mut s = format!("{f}");
|
||||
match case {
|
||||
Case::Lowercase => s.make_ascii_lowercase(), // Forces NaN back to nan.
|
||||
Case::Uppercase => s.make_ascii_uppercase(),
|
||||
fn format_float_non_finite(e: &ExtendedBigDecimal, case: Case) -> String {
|
||||
let mut s = match e {
|
||||
ExtendedBigDecimal::Infinity => String::from("inf"),
|
||||
ExtendedBigDecimal::Nan => String::from("nan"),
|
||||
_ => {
|
||||
debug_assert!(false);
|
||||
String::from("INVALID")
|
||||
}
|
||||
};
|
||||
|
||||
if case == Case::Uppercase {
|
||||
s.make_ascii_uppercase();
|
||||
}
|
||||
s
|
||||
}
|
||||
|
@ -532,7 +546,10 @@ fn write_output(
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::format::num_format::{Case, ForceDecimal};
|
||||
use crate::format::{
|
||||
num_format::{Case, ForceDecimal},
|
||||
ExtendedBigDecimal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn unsigned_octal() {
|
||||
|
@ -559,12 +576,12 @@ mod test {
|
|||
fn non_finite_float() {
|
||||
use super::format_float_non_finite;
|
||||
let f = |x| format_float_non_finite(x, Case::Lowercase);
|
||||
assert_eq!(f(f64::NAN), "nan");
|
||||
assert_eq!(f(f64::INFINITY), "inf");
|
||||
assert_eq!(f(&ExtendedBigDecimal::Nan), "nan");
|
||||
assert_eq!(f(&ExtendedBigDecimal::Infinity), "inf");
|
||||
|
||||
let f = |x| format_float_non_finite(x, Case::Uppercase);
|
||||
assert_eq!(f(f64::NAN), "NAN");
|
||||
assert_eq!(f(f64::INFINITY), "INF");
|
||||
assert_eq!(f(&ExtendedBigDecimal::Nan), "NAN");
|
||||
assert_eq!(f(&ExtendedBigDecimal::Infinity), "INF");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue