如何将一个浮点数舍入到一个指定的位数?

如何将 Rust 中的 f64浮点数舍入到指定数目的数字?

54387 次浏览

If you want this just for display purposes, use the formatting syntax built into println!(). For example, to print a number rounded to 2 decimal places use the {:.2} format specifier:

fn main() {
let x = 12.34567;
println!("{:.2}", x);
}

If you want to put the rounded number in a string, use the format!() macro.

If you want to round a number and get the result back as another number, then multiply the number by the given power of 10, call round, and divide by the same power, e.g. to round to 2 decimal places, use 102 = 100.

fn main() {
let x = 12.34567_f64;
let y = (x * 100.0).round() / 100.0;


println!("{:.5} {:.5}", x, y);
}

playground

This prints 12.34567 12.35000.

If the number of decimal places isn't known at compile time, one could use powi to efficiently compute the relevant power.

Note that this will breakdown for very large numbers; specifically, numbers larger than std::f64::MAX / power (where power is the power of ten, e.g. 100 in the example above) will become infinity in the multiplication, and remain infinity after. However, f64 cannot represent any fractional places for numbers larger than 253 (i.e. they're always integers), so one can special case such large numbers to just return themselves.

To add to @huon's great answer, if you want to round a floating point number for display purposes, but you don't know the precision at compile time, you can use the precision formatting syntax as follows:

fn main() {
let precision = 3;
let x = 12.34567;
println!("{:.1$}", x, precision); // prints 12.346 and works with `format!` as well
}

The documentation of std::fmt has more examples on the syntax.

Example round function with decimal count as a parameter:

fn round(x: f32, decimals: u32) -> f32 {
let y = 10i32.pow(decimals) as f32;
(x * y).round() / y
}

Here's an example which builds on the format! macro, as explained by @huon:

fn more_info(name: &str, height: f32) -> String {
let response = format!("My name is {name}, and I'm {height:.2} meters tall");
response
}


fn less_info(name: &str, height: f32) -> String {
let response = format!("My name is {name}, and I'm {height:.1} meters tall");
response
}


#[test]
fn test_more_info() {
let data = &[
(
"Bob",
1.586,
"My name is Bob, and I'm 1.59 meters tall",
"round up and truncate to two decimals",
),
(
"Robert",
1.7824,
"My name is Robert, and I'm 1.78 meters tall",
"no change",
),
];


for (person, height, message, description) in data {
assert_eq!(more_info(*person, *height), *message, "{}", description)
}
}


#[test]
fn test_less_info() {
let data = &[
(
"John",
1.46,
"My name is John, and I'm 1.5 meters tall",
"no change",
),
(
"Jane",
1.64,
"My name is Jane, and I'm 1.6 meters tall",
"round up and truncate to one decimal",
),
];


for (person, height, message, description) in data {
assert_eq!(less_info(*person, *height), *message, "{}", description)
}
}