Reputation: 5615
I'm trying to draw a grid inside a window of game_width=640
and game_height=480
. The numbers of grid cells is predefined. I want to evenly distribute the cells horizontally and vertically.
void GamePaint(HDC dc)
{
int numcells = 11;
for(int i = 1; i <= numcells; i++)
{
int y = <INSERT EQUATION>;
MoveToEx(dc, 0, y, NULL);
LineTo(dc, game_width, y);
}
// solving the horizontal equation will in turn solve the vertical one so no need to show the vertical code
}
The first equation came to mind was:
i * (game_height / numcells)
The notion behind this is to divide the total height by the number of cells to get the even cell size, which is then multiplied by i
in each iteration of the loop to get the correct y coordinate of the beginning of the horizontal line.
The problem with that is that it seems to leave an extra small cell at the end:
I figured this must have something to do with that integral division, so we come to the second equation:
(int)(i * ((float)game_height / numcells))
The idea is to avoid the integer division, do a float division, multiply by i like before and cast the result back to int. This works well, no extra small cell at the end!
What's driving me nuts, is this equation:
i * game_height / numcells
which seems to have the same effect as the previous equation, but of course with the added benefit of not doing any casting. I can't figure out why this doesn't suffer from the integer division issues in the first equation.
Note that mathematically: X * (Y / Z) == X * Y / Z So there's definitely a problem with integer division in the first equation.
Here's a video watching these 3 equations in the debugger watch window.
You can see an increasing gap between the result of the first equation vs the second and third (which always had the same result) as i
increases.
Why is the 3rd equation giving correct results as the second equation and not suffering from the integral division error in the first equation? I just can't seem to wrap my head around it...
Any help is appreciated.
Upvotes: 1
Views: 403
Reputation: 51503
The answer is in the order of operations performed. The first equation
int y = i * (game_height / numcells);
performs the division first, and magnifies the rounding error by multiplying with i
. The further you move down/to the right, the larger the accumulated rounding error becomes.
The last equation
int y = i * game_height / numcells;
is evaluated left to right. The relative error gets smaller, as you are dividing larger numbers (i * game_height
). You still have a rounding error, but it doesn't accumulate. The fact, that you do not wind up with extra space at the final evaluation is, that i
is equal to numcells
, essentially cancelling each other out. You will always see y == game_height
in the final iteration.
Using floating point operations is still more accurate: While the rounding error using integer math is in the interval [0 .. numcells)
for each line, floating point math reduces that to [0 .. 1)
. You will see more evenly distributed lines using floating point math.
Upvotes: 2