I'm coding a physical simulation and recently I was encountering anomalous results. I managed to debug my program, the error was in the division of a large double by a large int, something of the form:
cout << my_large_double/my_large_int << endl
with my_large_double of the order -10^{9} and the product of my two ints is of the order 10^{9} was returning something positive of the order 1. I fixed it by imposing a conversion to double in the denominator:
cout << my_large_double/( (double)my_large_int1*my_large_int2) << endl
But I would like to understand where is the mistake coming from, and are there ways to prevent them from happening usually?
Update: I skipped a detail that matters in my first question: the int is actually the product of two ints.
It depends on exactly how the expression was written.
If you write this:
my_large_double / my_large_int1 / my_large_int2
then it's equivalent to:
(my_large_double / my_large_int1) / my_large_int2
which should give you reasonably accurate results; my_large_int1
is promoted to double
before the first division, and my_large_int2
is promoted to double
before the second division.
If you write this:
my_large_double / (my_large_int1 * my_large_int2)
then the multiplication is done in the type of the two integer variables, and depending on their values you could have an overflow (which can give you a much smaller value than the mathematical product -- though strictly speaking the behavior of signed integer overflow is undefined).
The important thing to remember is that, in most cases, each C expression is effectively evaluated in isolation; its type is not affected by the context in which it appears. The expression my_large_int1 * my_large_int2
is an integer multiplication, even if the result is the operand of a floating-point division or is assigned to a floating-point variable.
Any operation whose operands are both integers is an integer operation. If one operand is double
and the other is int
, the int
operand is promoted to double
.
Even this:
double temp = my_large_int1 * my_large_int2;
... my_large_double / temp ...
will perform an integer multiplication before using the result to initialize temp
, and this:
my_large_double / (double)(my_large_int1 * my_large_int2)
has the same problem.
As you've found, the solution is to cast one or both of the integer operands to double
:
my_large_double / ((double)my_large_int1 * (double)my_large_int2)
(You might as well cast both of them, just for symmetry and clarity.)