Problem is the operation is performed with the largest type of the operands, at least int
(C standard, 6.3.1.8). The assignment is just another expression in C and the type of the left hand side of the =
is irrelevant for the right hand side operation.
On your platform, both constants fit into an int
, so the expression 55201 * 55201
is evaluated as int
. Problem is the result does not fit into an int
, thus generates an overflow.
Signed integer overflow is undefined behaviour. This means everything can happen. Luckily your compiler is clever enough to detect this and warn you instead of the computer jumping out of the window. Briefly: avoid it!
Solution is to perform the operation with a type which can hold the full result. A short calculation yields that the product requires 32 bits to represent the value. Thus an unsigned long
would be sufficient. If you want a signed integer, you need another bit for the sign, i.e. 33 bits. Such a type is very rare nowadays, so you have to use a long long
which has at least 64 bits. (Don't feel tempted to use long
, even iff it has 64 bits on your platform; this makes your code implementation defined, thus non-portable without any benefit.)
For this, you need at least one of the operands to have the type of the result type:
x = 55201LL * 55201; // first factor is a long long constant
If variables are involved use a cast:
long f1 = 55201; // an int is not guaranteed to hold this value!
x = (long long)f1 * 55201;
Note not using L
suffix for the constants here. They will automatically be promoted to the smallest type (int
at least) which can represent the value.
The other expression x = pow(55201, 2)
uses a floating point function. Thus the arguments are converted to double
before pow
is called. The double
result is converted by the assignment operator to the left hand side type.
This has two problems:
- A double is not guaranteed to have a mantissa of 63 bits (excluding sign) like a
long long
. The common IEEE754 implementations have this problem. (This is not relevant for this specific calculation)
- All floating point arithmetic may include rounding errors, so the result might deviate from the exactly result. That's why you have to use the first version.
As a general rule one should never use floating point arithmetic if an exact result is required. And mixing floating point and integer should be done very cautiously.