-3

Code:

float fff = 255.0f;
float a0 = (fff / 255.0f) * 100.0f;

If I use LLVM-based compilers (for example Intel C++ compiler or clang) variable a0 equals 100.000008, but if I use g++ compiler I get the right result - 100. Why do LLVM-based compilers return the wrong results? How to fix that? I can't just switch to g++ 'cos this one has other errors which LLVM compilers have not.

Wusiki Jeronii
  • 159
  • 1
  • 8
  • it is not incorrect. it is floating point. if you need to compare floats, compare an absolute difference. if you need better precision, you can use more bits. – Abel Oct 02 '21 at 17:13
  • 2
    Please post a [mcve] and show how you are checking the value. How many digits do you expect from a `float` ? – Richard Critten Oct 02 '21 at 17:14
  • 3
    Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Richard Critten Oct 02 '21 at 17:15
  • 4
    The code you show will produce 100. Floating-point rounding errors do not just manifest out of thin air. There is something else wrong in your actual program. Edit the question to provide a [mre]. Include the complete commands used to build and the input and anything else needed to reproduce the problem. State the specific compiler versions. Preferably, provide also a link to [Compiler Explorer](https://godbolt.org) that reproduces the problem. – Eric Postpischil Oct 02 '21 at 23:39

1 Answers1

-1

I don't know much about LLVM compilers, it is odd that you get 100.000008 though, since you have only whole numbers in there, even in the intermediate results. However even with G++, you should still not rely to get an accurate result on floating point types calculations due to the (binary) rounding errors in the calculation, which is not the case for regular types (Note with regular types - what I mean by that is you won't have rounding but truncation - floating point part gets ignored) For example, try using 0.1 in g++, you will notice that the result is not 0.1 (if you look thru the debugger or compare 0.1f with 0.1, cout or printf will not show enough decimals) Rounding error

Now if you want to compare 2 floating point numbers without looking if the absolute difference is below epsilon, I recommend you use a regular int type multiplied by a certain pre-scaler (x10^n) and then use for example, the last 3 digits of the number as the floating point part, for example instead of comparing volts, compare millivolts or microvolts, and then remove the pre-scaler at the end (recast to float/double before that) when you want to print the result.

David Hožič
  • 235
  • 2
  • 7
  • Can you explain how to compare the results of floating-point values? The end function using float variables must return 0.0f. Printf returns -0.000008. Debug shows -7.62939453e-06. And assert (var == 0.0f) fails. – Wusiki Jeronii Oct 02 '21 at 17:35
  • Using g++ assertion is succesful. – Wusiki Jeronii Oct 02 '21 at 17:37
  • Well, you count compare if the absolute difference is under a certain epsilon: #define epsilon 0.001f if ( abs(num1 - num2) < epsilon ) – David Hožič Oct 02 '21 at 17:42
  • Ohh. Thanks. I've understood the approach. And seems C++ has own epsilon value (`FLT_EPSILON`) in float.h. I used a more simple way: `var < FLT_EPSILON ? 0.0f : var` – Wusiki Jeronii Oct 02 '21 at 17:58
  • 1
    The statement “you should still not rely to get an accurate result on floating point types calculations due to the (binary) rounding errors in the calculation, which is not the case for regular types” is false in the latter clause and bad advice in the first. Regarding the latter, rounding errors occur in all finite-precision arithmetic types. For example, in integer arithmetic, `7/3` produces 2, not 2⅓, and `(5*7)/3` produces a different result than `5*(7/3)`. Programmers have generally become familiar with these artifacts in integer arithmetic and program around them, but they still exist… – Eric Postpischil Oct 02 '21 at 23:36
  • 1
    Regarding the former, floating-point rounding errors do not just manifest out of thin air. They result from rules about floating-point operations. Those rules are unfortunately compiled by language standards and compilers that do not adhere well to the IEEE-754 standard, but there are still rules. When `255.0` is converted to a `float`, divided by another `255.0` converted to a `float`, and multiplied by `100.0` converted to a `float`, the result is 100 exactly, even if C++’s rules allowing for extra precision are used, or if they are not. Something else is wrong in the OP’s program. – Eric Postpischil Oct 02 '21 at 23:38
  • Regarding the 7/3 being 2 instead of 2 and 1/3, that's not really a round error, the result just gets truncated. I should of probably clarified that in my answer though. – David Hožič Oct 03 '21 at 07:55
  • 1
    @DavidHožič: Truncation is a form of rounding; it is a method of adjusting the real-number-arithmetic result to a representable number. Truncation is rounding toward zero. In fact, that is one of the five rounding methods specified in IEEE-754 (to nearest ties to even, to nearest ties to away, toward positive infinity, toward negative infinity, and toward zero). – Eric Postpischil Oct 03 '21 at 11:38