mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
uucore: format: Use ExtendedBigDecimal in argument code
Provides arbitrary precision for float parsing in printf. Also add a printf test for that.
This commit is contained in:
parent
71a285468b
commit
b5a658528b
4 changed files with 26 additions and 9 deletions
|
@ -12,6 +12,8 @@ use crate::{
|
||||||
use os_display::Quotable;
|
use os_display::Quotable;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
use super::ExtendedBigDecimal;
|
||||||
|
|
||||||
/// An argument for formatting
|
/// An argument for formatting
|
||||||
///
|
///
|
||||||
/// Each of these variants is only accepted by their respective directives. For
|
/// Each of these variants is only accepted by their respective directives. For
|
||||||
|
@ -25,7 +27,7 @@ pub enum FormatArgument {
|
||||||
String(String),
|
String(String),
|
||||||
UnsignedInt(u64),
|
UnsignedInt(u64),
|
||||||
SignedInt(i64),
|
SignedInt(i64),
|
||||||
Float(f64),
|
Float(ExtendedBigDecimal),
|
||||||
/// Special argument that gets coerced into the other variants
|
/// Special argument that gets coerced into the other variants
|
||||||
Unparsed(String),
|
Unparsed(String),
|
||||||
}
|
}
|
||||||
|
@ -34,7 +36,7 @@ pub trait ArgumentIter<'a>: Iterator<Item = &'a FormatArgument> {
|
||||||
fn get_char(&mut self) -> u8;
|
fn get_char(&mut self) -> u8;
|
||||||
fn get_i64(&mut self) -> i64;
|
fn get_i64(&mut self) -> i64;
|
||||||
fn get_u64(&mut self) -> u64;
|
fn get_u64(&mut self) -> u64;
|
||||||
fn get_f64(&mut self) -> f64;
|
fn get_extended_big_decimal(&mut self) -> ExtendedBigDecimal;
|
||||||
fn get_str(&mut self) -> &'a str;
|
fn get_str(&mut self) -> &'a str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,14 +74,14 @@ impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_f64(&mut self) -> f64 {
|
fn get_extended_big_decimal(&mut self) -> ExtendedBigDecimal {
|
||||||
let Some(next) = self.next() else {
|
let Some(next) = self.next() else {
|
||||||
return 0.0;
|
return ExtendedBigDecimal::zero();
|
||||||
};
|
};
|
||||||
match next {
|
match next {
|
||||||
FormatArgument::Float(n) => *n,
|
FormatArgument::Float(n) => n.clone(),
|
||||||
FormatArgument::Unparsed(s) => extract_value(f64::extended_parse(s), s),
|
FormatArgument::Unparsed(s) => extract_value(ExtendedBigDecimal::extended_parse(s), s),
|
||||||
_ => 0.0,
|
_ => ExtendedBigDecimal::zero(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,12 @@ impl Zero for ExtendedBigDecimal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for ExtendedBigDecimal {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Add for ExtendedBigDecimal {
|
impl Add for ExtendedBigDecimal {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
|
|
@ -433,8 +433,7 @@ impl Spec {
|
||||||
} => {
|
} => {
|
||||||
let width = resolve_asterisk(*width, &mut args).unwrap_or(0);
|
let width = resolve_asterisk(*width, &mut args).unwrap_or(0);
|
||||||
let precision = resolve_asterisk(*precision, &mut args).unwrap_or(6);
|
let precision = resolve_asterisk(*precision, &mut args).unwrap_or(6);
|
||||||
// TODO: We should implement some get_extendedBigDecimal function in args to avoid losing precision.
|
let f: ExtendedBigDecimal = args.get_extended_big_decimal();
|
||||||
let f: ExtendedBigDecimal = args.get_f64().into();
|
|
||||||
|
|
||||||
if precision as u64 > i32::MAX as u64 {
|
if precision as u64 > i32::MAX as u64 {
|
||||||
return Err(FormatError::InvalidPrecision(precision.to_string()));
|
return Err(FormatError::InvalidPrecision(precision.to_string()));
|
||||||
|
|
|
@ -992,6 +992,16 @@ fn float_flag_position_space_padding() {
|
||||||
.stdout_only(" +1.0");
|
.stdout_only(" +1.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn float_large_precision() {
|
||||||
|
// Note: This does not match GNU coreutils output (0.100000000000000000001355252716 on x86),
|
||||||
|
// as we parse and format using ExtendedBigDecimal, which provides arbitrary precision.
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["%.30f", "0.1"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("0.100000000000000000000000000000");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn float_non_finite_space_padding() {
|
fn float_non_finite_space_padding() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue