mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 19:17:43 +00:00
uucore: format: print absolute value of float, then add sign
Simplifies the code, but also fixes printing of negative and positive `NaN`: `cargo run printf "%f %f\n" nan -nan` Fixes part 2 of #7412.
This commit is contained in:
parent
e3872e8e8f
commit
b7dcaa34da
1 changed files with 17 additions and 34 deletions
|
@ -85,7 +85,7 @@ impl Formatter for SignedInt {
|
||||||
x.abs().to_string()
|
x.abs().to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let sign_indicator = get_sign_indicator(self.positive_sign, &x);
|
let sign_indicator = get_sign_indicator(self.positive_sign, x.is_negative());
|
||||||
|
|
||||||
write_output(writer, sign_indicator, s, self.width, self.alignment)
|
write_output(writer, sign_indicator, s, self.width, self.alignment)
|
||||||
}
|
}
|
||||||
|
@ -239,8 +239,9 @@ impl Default for Float {
|
||||||
impl Formatter for Float {
|
impl Formatter for Float {
|
||||||
type Input = f64;
|
type Input = f64;
|
||||||
|
|
||||||
fn fmt(&self, writer: impl Write, x: Self::Input) -> std::io::Result<()> {
|
fn fmt(&self, writer: impl Write, f: Self::Input) -> std::io::Result<()> {
|
||||||
let mut s = if x.is_finite() {
|
let x = f.abs();
|
||||||
|
let s = if x.is_finite() {
|
||||||
match self.variant {
|
match self.variant {
|
||||||
FloatVariant::Decimal => {
|
FloatVariant::Decimal => {
|
||||||
format_float_decimal(x, self.precision, self.force_decimal)
|
format_float_decimal(x, self.precision, self.force_decimal)
|
||||||
|
@ -259,11 +260,7 @@ impl Formatter for Float {
|
||||||
format_float_non_finite(x, self.case)
|
format_float_non_finite(x, self.case)
|
||||||
};
|
};
|
||||||
|
|
||||||
// The format function will parse `x` together with its sign char,
|
let sign_indicator = get_sign_indicator(self.positive_sign, f.is_sign_negative());
|
||||||
// which should be placed in `sign_indicator`. So drop it here
|
|
||||||
s = if x < 0. { s[1..].to_string() } else { s };
|
|
||||||
|
|
||||||
let sign_indicator = get_sign_indicator(self.positive_sign, &x);
|
|
||||||
|
|
||||||
write_output(writer, sign_indicator, s, self.width, self.alignment)
|
write_output(writer, sign_indicator, s, self.width, self.alignment)
|
||||||
}
|
}
|
||||||
|
@ -309,8 +306,8 @@ impl Formatter for Float {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sign_indicator<T: PartialOrd + Default>(sign: PositiveSign, x: &T) -> String {
|
fn get_sign_indicator(sign: PositiveSign, negative: bool) -> String {
|
||||||
if *x >= T::default() {
|
if !negative {
|
||||||
match sign {
|
match sign {
|
||||||
PositiveSign::None => String::new(),
|
PositiveSign::None => String::new(),
|
||||||
PositiveSign::Plus => String::from("+"),
|
PositiveSign::Plus => String::from("+"),
|
||||||
|
@ -332,6 +329,7 @@ fn format_float_non_finite(f: f64, case: Case) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_float_decimal(f: f64, precision: usize, force_decimal: ForceDecimal) -> String {
|
fn format_float_decimal(f: f64, precision: usize, force_decimal: ForceDecimal) -> String {
|
||||||
|
debug_assert!(!f.is_sign_negative());
|
||||||
if precision == 0 && force_decimal == ForceDecimal::Yes {
|
if precision == 0 && force_decimal == ForceDecimal::Yes {
|
||||||
format!("{f:.0}.")
|
format!("{f:.0}.")
|
||||||
} else {
|
} else {
|
||||||
|
@ -345,6 +343,7 @@ fn format_float_scientific(
|
||||||
case: Case,
|
case: Case,
|
||||||
force_decimal: ForceDecimal,
|
force_decimal: ForceDecimal,
|
||||||
) -> String {
|
) -> String {
|
||||||
|
debug_assert!(!f.is_sign_negative());
|
||||||
let exp_char = match case {
|
let exp_char = match case {
|
||||||
Case::Lowercase => 'e',
|
Case::Lowercase => 'e',
|
||||||
Case::Uppercase => 'E',
|
Case::Uppercase => 'E',
|
||||||
|
@ -384,6 +383,7 @@ fn format_float_shortest(
|
||||||
case: Case,
|
case: Case,
|
||||||
force_decimal: ForceDecimal,
|
force_decimal: ForceDecimal,
|
||||||
) -> String {
|
) -> String {
|
||||||
|
debug_assert!(!f.is_sign_negative());
|
||||||
// Precision here is about how many digits should be displayed
|
// Precision here is about how many digits should be displayed
|
||||||
// instead of how many digits for the fractional part, this means that if
|
// instead of how many digits for the fractional part, this means that if
|
||||||
// we pass this to rust's format string, it's always gonna be one less.
|
// we pass this to rust's format string, it's always gonna be one less.
|
||||||
|
@ -460,21 +460,21 @@ fn format_float_hexadecimal(
|
||||||
case: Case,
|
case: Case,
|
||||||
force_decimal: ForceDecimal,
|
force_decimal: ForceDecimal,
|
||||||
) -> String {
|
) -> String {
|
||||||
let (sign, first_digit, mantissa, exponent) = if f == 0.0 {
|
debug_assert!(!f.is_sign_negative());
|
||||||
("", 0, 0, 0)
|
let (first_digit, mantissa, exponent) = if f == 0.0 {
|
||||||
|
(0, 0, 0)
|
||||||
} else {
|
} else {
|
||||||
let bits = f.to_bits();
|
let bits = f.to_bits();
|
||||||
let sign = if (bits >> 63) == 1 { "-" } else { "" };
|
|
||||||
let exponent_bits = ((bits >> 52) & 0x7ff) as i64;
|
let exponent_bits = ((bits >> 52) & 0x7ff) as i64;
|
||||||
let exponent = exponent_bits - 1023;
|
let exponent = exponent_bits - 1023;
|
||||||
let mantissa = bits & 0xf_ffff_ffff_ffff;
|
let mantissa = bits & 0xf_ffff_ffff_ffff;
|
||||||
(sign, 1, mantissa, exponent)
|
(1, mantissa, exponent)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut s = match (precision, force_decimal) {
|
let mut s = match (precision, force_decimal) {
|
||||||
(0, ForceDecimal::No) => format!("{sign}0x{first_digit}p{exponent:+}"),
|
(0, ForceDecimal::No) => format!("0x{first_digit}p{exponent:+}"),
|
||||||
(0, ForceDecimal::Yes) => format!("{sign}0x{first_digit}.p{exponent:+}"),
|
(0, ForceDecimal::Yes) => format!("0x{first_digit}.p{exponent:+}"),
|
||||||
_ => format!("{sign}0x{first_digit}.{mantissa:0>13x}p{exponent:+}"),
|
_ => format!("0x{first_digit}.{mantissa:0>13x}p{exponent:+}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if case == Case::Uppercase {
|
if case == Case::Uppercase {
|
||||||
|
@ -675,22 +675,14 @@ mod test {
|
||||||
assert_eq!(f(0.125), "0x1.0000000000000p-3");
|
assert_eq!(f(0.125), "0x1.0000000000000p-3");
|
||||||
assert_eq!(f(256.0), "0x1.0000000000000p+8");
|
assert_eq!(f(256.0), "0x1.0000000000000p+8");
|
||||||
assert_eq!(f(65536.0), "0x1.0000000000000p+16");
|
assert_eq!(f(65536.0), "0x1.0000000000000p+16");
|
||||||
assert_eq!(f(-0.00001), "-0x1.4f8b588e368f1p-17");
|
|
||||||
assert_eq!(f(-0.125), "-0x1.0000000000000p-3");
|
|
||||||
assert_eq!(f(-256.0), "-0x1.0000000000000p+8");
|
|
||||||
assert_eq!(f(-65536.0), "-0x1.0000000000000p+16");
|
|
||||||
|
|
||||||
let f = |x| format_float_hexadecimal(x, 0, Case::Lowercase, ForceDecimal::No);
|
let f = |x| format_float_hexadecimal(x, 0, Case::Lowercase, ForceDecimal::No);
|
||||||
assert_eq!(f(0.125), "0x1p-3");
|
assert_eq!(f(0.125), "0x1p-3");
|
||||||
assert_eq!(f(256.0), "0x1p+8");
|
assert_eq!(f(256.0), "0x1p+8");
|
||||||
assert_eq!(f(-0.125), "-0x1p-3");
|
|
||||||
assert_eq!(f(-256.0), "-0x1p+8");
|
|
||||||
|
|
||||||
let f = |x| format_float_hexadecimal(x, 0, Case::Lowercase, ForceDecimal::Yes);
|
let f = |x| format_float_hexadecimal(x, 0, Case::Lowercase, ForceDecimal::Yes);
|
||||||
assert_eq!(f(0.125), "0x1.p-3");
|
assert_eq!(f(0.125), "0x1.p-3");
|
||||||
assert_eq!(f(256.0), "0x1.p+8");
|
assert_eq!(f(256.0), "0x1.p+8");
|
||||||
assert_eq!(f(-0.125), "-0x1.p-3");
|
|
||||||
assert_eq!(f(-256.0), "-0x1.p+8");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -716,11 +708,6 @@ mod test {
|
||||||
assert_eq!(f(0.001171875), "0.00117187");
|
assert_eq!(f(0.001171875), "0.00117187");
|
||||||
assert_eq!(f(0.0001171875), "0.000117187");
|
assert_eq!(f(0.0001171875), "0.000117187");
|
||||||
assert_eq!(f(0.001171875001), "0.00117188");
|
assert_eq!(f(0.001171875001), "0.00117188");
|
||||||
assert_eq!(f(-0.1171875), "-0.117188");
|
|
||||||
assert_eq!(f(-0.01171875), "-0.0117188");
|
|
||||||
assert_eq!(f(-0.001171875), "-0.00117187");
|
|
||||||
assert_eq!(f(-0.0001171875), "-0.000117187");
|
|
||||||
assert_eq!(f(-0.001171875001), "-0.00117188");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -731,9 +718,5 @@ mod test {
|
||||||
assert_eq!(f(0.0001), "0.0001");
|
assert_eq!(f(0.0001), "0.0001");
|
||||||
assert_eq!(f(0.00001), "1e-05");
|
assert_eq!(f(0.00001), "1e-05");
|
||||||
assert_eq!(f(0.000001), "1e-06");
|
assert_eq!(f(0.000001), "1e-06");
|
||||||
assert_eq!(f(-0.001), "-0.001");
|
|
||||||
assert_eq!(f(-0.0001), "-0.0001");
|
|
||||||
assert_eq!(f(-0.00001), "-1e-05");
|
|
||||||
assert_eq!(f(-0.000001), "-1e-06");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue