简体   繁体   English

将 Rust 中的两个浮点数与任意精度水平进行比较

[英]Comparison of two floats in Rust to arbitrary level of precision

How can I do a comparison at an arbitrary level of precision such that I can see that two numbers are the same?如何在任意精度级别进行比较,以便我可以看到两个数字相同? In Python, I would use a function like round() , so I am looking for something equivalent in Rust.在 Python 中,我会使用像round()这样的函数,所以我在 Rust 中寻找等价的东西。

For example I have:例如我有:

let x = 1.45555454;
let y = 1.45556766;

In my case, they are similar up to 2 decimal places.在我的情况下,它们相似到小数点后 2 位。 So x and y would become 1.46 for the purposes of comparison.因此,为了比较, xy将变为 1.46。 I could format these, but that surely is slow, what is the best Rust method to check equivalence, so:我可以格式化这些,但这肯定很慢,检查等效性的最佳 Rust 方法是什么,所以:

if x == y { // called when we match to 2 decimal places}

To further elucidate the problem and give some context.进一步阐明问题并提供一些背景信息。 This is really for dollars and cents accuracy.这真的是为了美元和美分的准确性。 So normally in python would use the round() function with all its problems.所以通常在python会使用round()函数来解决所有问题。 Yes I am aware of the limitations of floating point representations.是的,我知道浮点表示的局限性。 There are two functions that compute amounts, I compute in dollars and need to handle the cents part to the nearest penny.有两个计算金额的函数,我以美元计算,需要将美分部分处理到最接近的一分钱。

The reason to ask the community is that I suspect that if I roll my own, it could hit performance and it's this aspect - which is I why I'm employing Rust, so here I am.询问社区的原因是我怀疑如果我自己动手,它可能会影响性能,这就是我使用 Rust 的原因,所以我在这里。 Plus I saw something called round() in the Rust documentation, but it seems to take zero parameters unlike pythons version.另外,我在 Rust 文档中看到了一种叫做round() 的东西,但与 python 版本不同,它似乎采用零参数。

From the Python documentation:来自 Python 文档:

Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68 .注意round()对浮点数的行为可能令人惊讶:例如, round(2.675, 2)给出2.67而不是预期的2.68 This is not a bug: it's a result of the fact that most decimal fractions can't be represented exactly as a float.这不是错误:这是大多数十进制分数不能完全表示为浮点数的结果。

For more information, check out What Every Programmer Should Know About Floating-Point Arithmetic .有关更多信息,请查看每个程序员应该了解的关于浮点运算的知识


If you don't understand how computers treat floating points, don't use this code .如果您不了解计算机如何处理浮点数,请不要使用此代码 If you know what trouble you are getting yourself into:如果您知道自己遇到了什么麻烦:

fn approx_equal(a: f64, b: f64, decimal_places: u8) -> bool {
    let factor = 10.0f64.powi(decimal_places as i32);
    let a = (a * factor).trunc();
    let b = (b * factor).trunc();
    a == b
}

fn main() {
    assert!( approx_equal(1.234, 1.235, 1));
    assert!( approx_equal(1.234, 1.235, 2));
    assert!(!approx_equal(1.234, 1.235, 3));
}

A non-exhaustive list of things that are known (or likely) to be broken with this code:已知(或可能)被此代码破坏的事物的非详尽列表:

  • Sufficiently large floating point numbers and/or number of decimal points足够大的浮点数和/或小数点数
  • Denormalized numbers非规范化数字
  • NaN NaN
  • Infinities无穷大
  • Values near zero ( approx_equal(0.09, -0.09, 1) )接近于零的值 ( approx_equal(0.09, -0.09, 1) )

A potential alternative is to use either a fixed-point or arbitrary-precision type, either of which are going to be slower but more logically consistent to the majority of humans.一个潜在的替代方法是使用定点或任意精度类型,这两种类型都会变慢,但对大多数人来说在逻辑上更一致。

This one seems to work pretty well for me.这个对我来说似乎很有效。

fn approx_equal (a:f64,b:f64,dp:u8) -> bool {
    let p:f64 = 10f64.powf(-(dp as f64));

    if (a-b).abs() < p {
        return true;
    } else {
        return false;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM