Question

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.

Était-ce utile?

La solution

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.)

Autres conseils

An IEEE format double can hold an int without precision loss up to 53 bits, versus the 31 bits typical for an int. Your solution is a good one, convert to double up front so that you don't hit an integer overflow in the multiply.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top