Thread: What's the best way to make an expression evaluate as a double?

1. What's the best way to make an expression evaluate as a double?

Code:
`double x = (WIDTH - 2 * MARGIN) / (MAX - 1) * i;`
If I wanted to make the above statement evaluate as a double for the most accuracy where the variables are ints, what's the best way to do that? I would put (double) in front of every variable to be safe, but that seems repetitive.

2. Change 2 to 2.0 and 1 to 1.0.

3. Originally Posted by tabstop
Change 2 to 2.0 and 1 to 1.0.
Even changing the 1 to 1.0 is optional.

This assumes your notion of "best" means "least additional typing". However, the scope for confusion with such a line is large. A common problem in a team environment is that one person will write such a line, and someone else will come along and remove parts they consider unnecessary. That ".0" will therefore probably be removed by someone and there will then be a small bug in the program that shows up occasionally and is very hard to track down.

It is even more embarrassing when you do that to your own code, and realise that the idiot who removed the ".0" and broke the program is yourself.

4. If you don't change the 1 to 1.0, is it guaranteed that (MAX - 1) * i won't be evaluated first, as an int?

5. Order of operations: a/b*c = (a/b)*c, not a/(b*c). (They're not equivalent).

And I suppose you could always add a comment why it's 2.0, and not 2; or, if you're paranoid, you can cast the whole expression to double.

6. To clearly state your purpose do what tabstop suggested.
Code:
`double x = double((WIDTH - 2 * MARGIN) / (MAX - 1) * i);`

7. To clearly state your purpose do what tabstop suggested.
You still need to make sure that the operations in the expression are performed with doubles by making 2 be 2.0, and of course static_cast should be preferred to a C-style cast.

8. Changing 2 to 2.0 is the minimal solution. For more clarity you would want to cast each of WIDTH, MARGIN, and MAX, and change 1 to 1.0.

Putting the cast around the whole thing is pretty pointless, cause it is clear that you are assigning to a double. Furthermore such a habit could sometimes hide when the expression evaluates to a non-numeric type, and stop a compiler from giving loss of precision warnings. Using a static cast helps but does not eliminate this potential for error.

9. You need only change one operand to a double, King. If an integer interacts with a double in any way it gets promoted to a double.

10. Originally Posted by tabstop
Order of operations: a/b*c = (a/b)*c, not a/(b*c). (They're not equivalent).

And I suppose you could always add a comment why it's 2.0, and not 2; or, if you're paranoid, you can cast the whole expression to double.
IIRC order of operations isn't the same as order of evaluation. The compiler is free to evaluate the parts in any order it chooses.

11. Really? I did not know that. I would double check that, but I am not in that kind of mood today.

12. I should clarify a bit: Any order that still follows the rules of the order of operations.

So if the case of:
Code:
`(WIDTH - 2 * MARGIN) / (MAX - 1) * i;`
It could evaluate (MAX - 1) before evaluating (WIDTH - 2 * MARGIN). It could even evaluate (WIDTH - 2 * MARGIN) * i before dividing by (MAX - 1) but I kinda doubt it would.

13. Ah ok. Yeah I feel ya on that one. In all the time I have been posting on the forums (which has been a while) I have never found that you were in much need of correction, Thantos. Thats why I just figured I wasn't tracking what you meant well. I have been up since 5:00 this morning. So I am too tired to know what is what.

14. Originally Posted by master5001
You need only change one operand to a double, King. If an integer interacts with a double in any way it gets promoted to a double.
That's why the minimal solution is to convert the 2. Alternatively you could cast MARGIN. Anything else and the result may be different. That's why the safest approach is to cast everything, and write everything in terms of doubles. Then there is less room for error.

For example, casting WIDTH is not sufficient if MARGIN*2 will overflow an int (or whatever larger size MARGIN is).

15. Originally Posted by Thantos
It could evaluate (MAX - 1) before evaluating (WIDTH - 2 * MARGIN). It could even evaluate (WIDTH - 2 * MARGIN) * i before dividing by (MAX - 1) but I kinda doubt it would.
Yes to the first, no to the second. / and * have the same precedence and are evaluated left to right. The rule is such that it never matters for primitives, only for impure functions and state changing classes.