Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integer overflow and order of operations

I recently faced a problem on a C++ code of mine making me wonder whether I had some misunderstanding of what the compiler would do with long operations... Just look at the following code:

#include <iostream>

int main() {
    int i = 1024, j = 1024, k = 1024, n = 3;
    long long l = 5;
    std::cout << i * j * k * n * l << std::endl;  // #1
    std::cout << ( i * j * k * n ) * l << std::endl; // #2
    std::cout << l * i * j * k * n << std::endl;  // #3
    return 0;
}

For me the order in which the multiplications will happen in any of these 3 lines is undefined. However, here is what I thought would happen (assuming int is 32b, long long is 64b and they both follow the IEEE rules):

  • For line #2, the parenthesis is evaluated first, using ints as intermediate results, leading to an overflow and to store -1073741824. This intermediate result is promoted to long long for the last multiplication and the printed result should therefore be -5368709120.
  • Lines #1 and #3 are "equivalent" since the order of evaluation is undefined.

Now, for lines #1 and #3 here is were I'm unsure: I thought that although the order of evaluation was undefined, the compiler would "promote" all operations to the type of the largest operand, namely long long here. Therefore, no overflow would happen in this case since all computations would be made in 64b... But this is what GCC 5.3.0 gives me for this code:

~/tmp$ g++-5 cast.cc
~/tmp$ ./a.out 
-5368709120
-5368709120
16106127360

I would have expected 16106127360 for the first result too. Since I doubt there is a compiler bug of this magnitude in GCC, I guess the bug lies between the keyboard and the chair.

Could anyone please confirm / infirm this is undefined behaviour and GCC is correct in giving me whatever it gives (since this is undefined)?

like image 482
Gilles Avatar asked Dec 25 '22 10:12

Gilles


1 Answers

GCC is correct.

  1. Associativity for multiplication is left to right. This means that all of these expression are evaluated left to right.
  2. Promotion to higher type is only between two operands of different types of single binary operator.

For example, first expression is parsed as i * j * k * n * l = ((((i * j) * k) * n) * l) and the promotion happens only when last of multiplications is computed, but at this moment left operand is already incorrect.

like image 167
gudok Avatar answered Dec 28 '22 09:12

gudok