简体   繁体   English

使用浮点常量设置和检查

[英]Setting and checking with a float constant

I know there are a lot of questions on here about why float equality comparison is usually a bad idea.我知道这里有很多关于为什么浮动相等比较通常不是一个好主意的问题。 I understand float representation issues, rounding issues, silent promotion of floats to doubles, the dangers in relying upon arithmetic at the bit level, etc. But it seems to me that this should be fine, and no questions I found seem to cover this:我了解浮点数表示问题、舍入问题、将浮点数无声地提升为双精度数、在位级别依赖算术的危险等。但在我看来,这应该没问题,而且我发现的任何问题似乎都涵盖了这一点:

static const float MARKER = -500.0f; // some value well outside the range of valid values
std::vector<float> some_floats = {MARKER, 0.5f, 100.0f, 9.5f, MARKER, 0.f};
for (size_t i = 0; i< some_floats.size(); ++i) {
    if (some_floats[i] == MARKER) {             
       std::cout << i << std::endl;
    } else {
       // do some math
    }
}

The output is as expected: output 符合预期:

0
4

If I have -Wfloat-equal enabled (in gcc, but similar in other compilers), it will flag the comparison line as dangerous: comparing floating point with == or != is unsafe .如果我启用了-Wfloat-equal (在 gcc 中,但在其他编译器中类似),它会将比较行标记为危险: comparing floating point with == or != is unsafe And pretty much all the answers on here say not to use == or,=, period .这里几乎所有的答案都说不要使用 == or,=, period But I don't see why it's a problem here.但我不明白为什么这是一个问题。 I'm only setting the constant once and re-using it everywhere else it's used, and there is never any manipulation of that constant (eg arithmetic).我只设置常量一次,然后在其他任何地方重复使用它,并且永远不会对该常量进行任何操作(例如算术)。 Am I missing something?我错过了什么吗? What about 0.0f , even if not set as a constant? 0.0f怎么样,即使没有设置为常量?

As long as you're confident MARKER and its copies won't be altered by arithmetic functions or something, there's no issue doing a simple comparison.只要您确信MARKER及其副本不会被算术函数或其他东西改变,进行简单比较就没有问题。
Maybe consider not using -Wfloat-equal globally but disable warnings locally:也许考虑不在全球范围内使用-Wfloat-equal但在本地禁用警告:

    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wfloat-equal"
    /* your code */
    #pragma GCC diagnostic pop

Or a portable equivalent: https://www.fluentcpp.com/2019/08/30/how-to-disable-a-warning-in-cpp/或便携式等同物: https://www.fluentcpp.com/2019/08/30/how-to-disable-a-warning-in-cpp/

You miss the reason when to use floats.您错过了何时使用浮动的原因。 You use floats to do math.你用花车做数学。 As long you only compare float literals it is going to be alright.只要你只比较浮点数就没问题。 However as soon you do some manipulation on the numbers and compare them afterwards it is generally not going to be working (even though there are cases where it may be working) as floating point operations are not exact.但是,一旦您对数字进行一些操作并在之后比较它们,它通常不会起作用(即使在某些情况下它可能起作用),因为浮点运算并不精确。 That is what people mean when saying "Do not compare floats".这就是人们说“不要比较浮点数”时的意思。

Further many compilers have flags for their specify floating-point behavior.此外,许多编译器都有用于指定浮点行为的标志。 For MSVC for instance have a look here .例如,对于 MSVC,请查看此处 This makes it even more obvious that an exact comparison is never going to be a good idea.这使得更明显的是,精确比较永远不会是一个好主意。

If you want to mark floats like this you can certainly do it, however, I would suggest using std::numeric_limits<float>::min() as the marker value to be safe.如果你想像这样标记浮点数,你当然可以这样做,但是,为了安全起见,我建议使用std::numeric_limits<float>::min()作为标记值。 Just be sure to not manipulate these values mathematically.请确保不要以数学方式操纵这些值。 Also consider that other developers may take the presence of a float as an indicator that it is valid to manipulate these values, which would not be good.还要考虑到其他开发人员可能会将浮点数的存在视为可以有效操纵这些值的指示符,这并不好。 As an alternative to that you may consider std::optional to mark whether the numbers are valid.作为替代方案,您可以考虑 std::optional 来标记数字是否有效。

Just as a comment on the static : I would further suggest to drop the static as there really is no need for that and the word performance popped up somewhere.正如对static的评论一样:我进一步建议放弃 static,因为确实没有必要,而且性能这个词突然出现在某处。 I would change that to look like this:我会把它改成这样:

const float MARKER = std::numeric_limits<float>::min();  // some value well outside the range of valid values
std::vector<float> some_floats = {MARKER, 0.5f, 100.0f, 9.5f, MARKER, 0.f};
for (size_t i = 0; i < some_floats.size(); ++i) {
    if (some_floats[i] == MARKER) {
        std::cout << i << std::endl;
    } else {
    // do some math
}

} }

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

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