4

The documentation for the clang-tidy [bugprone-incorrect-roundings] check says:

The number 0.499999975 (smallest representable float number below 0.5) rounds to 1.0

As far as I can detect the smallest float number below 0.5 is 0.4999999702, not a 0.499999975. But despite of this, both numbers give me 0 values in naive rounding calculation:

#include <iostream>

int main() {
   
    const float v1 = 0.499999975;
    const float v2 = 0.4999999702;

    std::cout << (int)(v1+0.5) << "\n" 
              << (int)(v2+0.5) << "\n";
}

Am I missing something?

1
  • I found this because I was confused by the bugprone-incorrect-roundings documentation too. Seeing the answer below, I still think this example in the documentation is incorrect. But I was also confused by the statement "It is unnecessarily slow". How so? std::round is way slower! Commented Jun 20, 2024 at 17:29

1 Answer 1

5

Regarding the arithmetic conversion in the standard:

6.3.1.8 Usual arithmetic conversions

...

  • Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose corresponding real type is double.

  • The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type;

So in this line:

(int)(v1+0.5) 

Your v1 variable is promoted to a double precision floating point operation, that's why you get zero.

This should fix your problem:

#include <iostream>

int main() {

    const float v1 = 0.499999975f;
    const float v2 = 0.4999999702f;

    std::cout << (int)(v1 + 0.5f) << "\n" 
              << (int)(v2 + 0.5f) << "\n";
}
Sign up to request clarification or add additional context in comments.

7 Comments

But nobody is typing +0.5f even in clang-tidy example. Hence +0.5 should works well, aint it?
@αλεχολυτ not quite. Double has enough bits to represent v1 + 0.5 0.99999975 which is truncated to zero by (int). But float has too few bits, so it rounds to 1.0, and later (int) truncates that to 1
@αλεχολυτ Also, note that this depends on the rounding mode. std::fesetround(FE_DOWNWARD); will make it always return 0, even for float
@MichaelVeksler code from documentation says double_expression, and since 0.5 is double too, I still can't see the problem with such rounding (for positive values).
@αλεχολυτ The problem is with pure float values in this case. With double the values are slightly different: 0.499999999999999944, but the effect is the same. (int)(0.499999999999999944 + 0.5) is rounded to 1, subject to the rounding mode. Try this out
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.