Reputation: 13
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
Upvotes: 1
Views: 103
Reputation: 206747
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.
Upvotes: 1