rust - Rust:用最少的小数点格式化浮点数
问题描述
我有一个f32
要打印的值。作为浮点数,我也可以用这种类型表示整数
let a_float: f32 = 3.0;
let another_float: f32 = 3.14;
// let's pretend this was user input,
// we didn't know what they'd put enter, so we used f32 to cover our bases
let an_integer: f32 = 3;
我想以最小的精度打印存储为 f32 的值,但使用尽可能多的值来表示存储的值。如果我想要的最小精度是一 (1),我希望在浮点数上进行以下转换:
let a_float: f32 = 3.0; // print 3.0
let another_float: f32 = 3.14; // print 3.14
let an_integer: f32 = 3; // print 3.0
我知道我可以使用std::fmt's precision设置有限的小数位数,但这似乎并没有给我想要的东西。有没有办法在不引入额外的格式化板条箱的情况下实现这个功能?增加额外的板条箱并不是不可能的,我对我能够“开箱即用”做的事情更感兴趣
解决方案
默认情况下, Rust已经这样做了。每个浮点数都打印有必要的数字,以唯一地表示特定的浮点数。
这是一个演示这一点的程序。它生成 10000 个随机浮点数,将它们转换为字符串,并检查可以从小数部分删除多少位而不更改值。
(警告:这并不表明没有数字可以通过在不同方向四舍五入以更少的数字表示的情况,如果我没记错的话有时会发生这种情况。我不是浮点格式专家。)
use std::collections::HashMap;
use rand::{Rng, thread_rng};
/// Change this to choose the type analyzed
type Float = f32;
fn main() {
let mut rng = thread_rng();
let mut digit_histogram = HashMap::new();
for _ in 1..10000 {
let x: Float = rng.gen_range(0.0..10.0);
let string = x.to_string();
// Break up string representation
let before_exponent_pos = string.find('e').unwrap_or(string.len());
let after_decimal_pos = string.find('.')
.map(|p| p + 1)
.unwrap_or(before_exponent_pos);
let prefix = &string[..after_decimal_pos];
let mut fractional_digits = &string[after_decimal_pos..before_exponent_pos];
let suffix = &string[before_exponent_pos..];
// What happens if we truncate the digits?
let initial_digits = fractional_digits.len();
let mut unnecessary_digits = 0;
while fractional_digits.len() > 0 {
fractional_digits = &fractional_digits[..fractional_digits.len() - 1];
let shortened_string = format!("{}{}{}",
prefix,
fractional_digits,
suffix,
);
let shortened_x = shortened_string.parse::<Float>().unwrap();
if shortened_x == x {
unnecessary_digits += 1;
} else {
break;
}
}
*(digit_histogram
.entry((initial_digits, unnecessary_digits))
.or_insert(0)) += 1;
}
// Summarize results.
let mut digit_histogram = digit_histogram.into_iter().collect::<Vec<_>>();
digit_histogram.sort_by_key(|pair| pair.0);
for ((initial_digits, unnecessary_digits), occurrences) in digit_histogram {
println!(
"{} digits with {} unnecessary × {}",
initial_digits,
unnecessary_digits,
occurrences);
}
}
2 digits with 0 unnecessary × 1
3 digits with 0 unnecessary × 6
4 digits with 0 unnecessary × 25
5 digits with 0 unnecessary × 401
6 digits with 0 unnecessary × 4061
7 digits with 0 unnecessary × 4931
8 digits with 0 unnecessary × 504
9 digits with 0 unnecessary × 62
10 digits with 0 unnecessary × 8
该程序看到了各种各样的数字,但从来没有任何一个可以在不改变答案的情况下被删除。
推荐阅读
- c++ - 使用高斯消除的模板中的矩阵行列式
- google-kubernetes-engine - Cloud Run On Anthos - 仅限 VPC 访问
- javascript - 在 chrome 扩展服务工作者中处理长时间运行的任务?
- transactions - CMT 中的 JBOSS Transaction 和 DB 连接管理
- python - PayPal API - 交易搜索 API:响应 400 INVALID REQUEST
- javascript - 如何修复错误 ReferenceError: 前缀未定义?
- c# - 使用 Enum.Parse 将字符串转换为枚举类型时出现问题
- python - 网页抓取 Selenium 错误:“带有 AttributeError:'list' 对象没有属性 'find_element_by_class_name'”
- unity3d - Unity URP 看起来很奇怪的光照贴图问题
- javascript - 离子变量损失