1

I'm having a very interesting bug where .498*2000 yields 995 rather than 996 - but only when the 2000 is stored in an integer variable rather than simply a literal. I ran the following code to make sure I wasn't going crazy, the results of the variables are shown in the comments. dequeue and peek are functions I was using, they return int16_t, though that doesn't seem it should matter as c is still an int of value 2000. All values confirmed both by print statements and by running in gdb.

int a = buffer.dequeue();    // a = 0
int b = buffer.peek();       // b = 2000
int c = a + b;               // c = 2000
float d = .498*2000;         // d = 996
int e = static_cast<int>(d); // e = 996
int f = .498*2000;           // f = 996
int g = .498*c;              // g = 995 WHY??????

I really don't understand what's happening here, and would much appreciate some light on the subject. Thank you!

EDIT:

A clarification of what exactly is happening, simplified: I run the following code in my main file:

int a = 2000;
int b = .498*2000;
int c = .498*a;
std::cout << a << " " << b << " " << c << std::endl;

resulting this following output:

2000 996 995

what I do not understand is why c and b are different values based on whether the 2000 is a literal or an integer variable. It seems to me that the same rounding or truncation should be applied in either case. thank you.

I am compiling with the following:

g++ -o main.o -g -std=c++0x
Zyxion
  • 13
  • 4
  • Instead of writing in comments what you assume the values are, why not print them out with the requisite number of decimal places. More than likely, the value of `d` is `995.9999999` or similar, and truncating that you get 996. – PaulMcKenzie Mar 27 '18 at 03:27
  • @PaulMcKenzie I did in fact print them out and also confirmed them with gdb, as I stated. No assumptions were made. I put them in comments because I thought it would be easy to read. And if truncation was the problem, then why would it only truncate if 2000is stored in a variable, and round up if it's a literal? – Zyxion Mar 27 '18 at 03:28
  • Sorry my first comment should read "truncating that gives you 995". – PaulMcKenzie Mar 27 '18 at 03:29
  • 1
    Basically your edit just shows that floating point math is not exact. [Possible duplicate](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – PaulMcKenzie Mar 27 '18 at 03:40
  • @Zyxion I think this is compiler specific. I cannot reproduce this with VSC++ 2015/2017. – wp78de Mar 27 '18 at 03:41
  • @Zyxion It would be extremely helpful if you could state the name of your compiler, version and flags used to compile. It might help in identifying the issue. – Anirban Sarkar Mar 27 '18 at 03:48
  • I agree. It seems to be compiler specific. I cannot reproduce it. – dmg Mar 27 '18 at 04:09
  • It is kind of implicit conversation. Try .498d * a – Ratah Mar 27 '18 at 05:23

1 Answers1

1

I think the difference comes from compile time evaluation vs run time evaluation of floating point expressions.

The compiler is able to evaluate d at compile time. It evaluates g only at run time. However, they are not required to result in exactly the same value.

From 5.19 Constant expressions /4:

Although in some contexts constant expressions must be evaluated during program translation, others may be evaluated during program execution. Since this International Standard imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution.

It's best to avoid such code. The standard does not guarantee the accuracy of such numbers. The results can vary from compiler to compiler. It's possible that they will vary with the same compiler but different optimization flags.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • So in that case my question would be why is e not 995, as it too was computed at run time rather than compile time, and yet evaluated differently from c, which was also evaluated at run time? – Zyxion Mar 27 '18 at 03:38
  • @Zyxion, you can verify what the compiler does by compiling your code into assembly and looking at the assembly code. – R Sahu Mar 27 '18 at 03:40