rust-lang / rfcs

RFCs for changes to Rust
https://rust-lang.github.io/rfcs/
Apache License 2.0
5.9k stars 1.56k forks source link

Float rounding with specified digits #3608

Open amab8901 opened 5 months ago

amab8901 commented 5 months ago

Introduce method round_to_digits(T: u32) for f64 (and f32). Same as f64::round() except that you can specify how many digits you want to round to.

Example use case:

I have the number 12.34567 and I want to round it to 12.35. Current f64::round() requires a verbose/less-readable/bug-prone workaround:

let full_float = 12.34567;
let rounded_float = (full_float * 100.0).round() / 100.0;
assert_eq!(rounded_float, 12.35);

The proposed method round_to() would simplify the above to:

let rounded_float = 12.34567.round_to_digits(2);
assert_eq!(rounded_float, 12.35);
kennytm commented 5 months ago

you can get a library function into std faster through the ACP process https://std-dev-guide.rust-lang.org/development/feature-lifecycle.html#suitability-for-the-standard-library.


anyway what is the use case for this not covered by format!("{:.2}", full_float)?

CryZe commented 5 months ago

@kennytm .2 always prints 2 fractional digits, even if they are 0.

amab8901 commented 5 months ago

you can get a library function into std faster through the ACP process https://std-dev-guide.rust-lang.org/development/feature-lifecycle.html#suitability-for-the-standard-library.

anyway what is the use case for this not covered by format!("{:.2}", full_float)?

I want to have float in the output. If I use format! macro then I have to use parse and then it becomes verbose. I'm currently translating a Python repo to Rust and I need to preserve original functionality to avoid breaking changes. The original Python repo uses an operation that rounds off to 2 digits and so I need to do the same in the Rust version of the repo

kennytm commented 5 months ago

if you need to be interoperate with Python do note that Rust's rounding result might not be the same as that of Python.

Number 0.05 0.15 0.25 0.35 0.45 0.55 0.65 0.75 0.85 0.95
CPython round(x, 1) 0.1 0.1 0.2 0.3 0.5 0.6 0.7 0.8 0.8 0.9
format!("{:.2}", f64) 0.1 0.1 0.2 0.3 0.5 0.6 0.7 0.8 0.8 0.9
format!("{:.2}", f32) 0.1 0.2 0.2 0.3 0.4 0.6 0.6 0.8 0.9 0.9
(x * 10.0).round() / 10.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
(x*10).round_ties_even()/10 0 0.2 0.2 0.4 0.4 0.6 0.6 0.8 0.8 1

And CPython's round(x, n) (for n > 0) is implemented exactly as format!("{:.1$}", x, n).parse::<f64>() since 2.7.4 / 3.1.0 (python/cpython@e6a076d86c51c9d72fee088dd229a7662ccc6c19), surprise :upside_down_face:.