均匀分布网格单元 horizontally/vertically?
Evenly distribute grid cells horizontally/vertically?
我正在尝试在 game_width=640
和 game_height=480
的 window 内绘制网格。网格单元的数量是预定义的。我想水平和垂直均匀分布单元格。
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
}
想到的第一个等式是:
i * (game_height / numcells)
这背后的概念是将总高度除以单元格数以获得偶数单元格大小,然后在循环的每次迭代中将其乘以 i
以获得正确的 y 坐标水平线的开头。
问题在于它似乎在最后留下了一个额外的小单元格:
我想这一定与积分除法有关,所以我们得出第二个等式:
(int)(i * ((float)game_height / numcells))
想法是避免整数除法,进行浮点数除法,像以前一样乘以 i,然后将结果转换回 int。这很好用,最后没有额外的小小区!
让我发疯的是这个等式:
i * game_height / numcells
这似乎与前面的等式具有相同的效果,但当然还有不进行任何转换的额外好处。我不明白为什么这不会受到第一个等式中整数除法问题的影响。
请注意,数学上:X * (Y / Z) == X * Y / Z
所以第一个方程的整数除法肯定有问题
Here's a video 在调试器中观察这 3 个等式 watch window.
随着 i
的增加,您可以看到第一个方程的结果与第二个和第三个方程(结果始终相同)之间的差距越来越大。
为什么第三个方程给出的结果与第二个方程一样正确,而没有受到第一个方程中积分除法错误的影响?我似乎无法理解它...
感谢任何帮助。
答案是按照执行操作的顺序。第一个方程
int y = i * (game_height / numcells);
先进行除法,乘以i
放大舍入误差。 down/to 越往右移,累积的舍入误差越大。
最后一个方程
int y = i * game_height / numcells;
从左到右求值。随着您除以较大的数字 (i * game_height
),相对误差会变小。您仍然有舍入误差,但它不会累积。事实上,在最终评估中你没有得到额外的 space 是,i
等于 numcells
,基本上相互抵消了。您将始终在最终迭代中看到 y == game_height
。
使用浮点运算仍然更准确:虽然使用整数数学的舍入误差在每一行的区间 [0 .. numcells)
中,但浮点数学将其减少到 [0 .. 1)
。使用浮点数学,您将看到分布更均匀的线条。
注意:在 Windows 上,您可以使用 MulDiv 代替整数方程,以防止常见错误,例如瞬时溢出。
我正在尝试在 game_width=640
和 game_height=480
的 window 内绘制网格。网格单元的数量是预定义的。我想水平和垂直均匀分布单元格。
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
}
想到的第一个等式是:
i * (game_height / numcells)
这背后的概念是将总高度除以单元格数以获得偶数单元格大小,然后在循环的每次迭代中将其乘以 i
以获得正确的 y 坐标水平线的开头。
问题在于它似乎在最后留下了一个额外的小单元格:
我想这一定与积分除法有关,所以我们得出第二个等式:
(int)(i * ((float)game_height / numcells))
想法是避免整数除法,进行浮点数除法,像以前一样乘以 i,然后将结果转换回 int。这很好用,最后没有额外的小小区!
让我发疯的是这个等式:
i * game_height / numcells
这似乎与前面的等式具有相同的效果,但当然还有不进行任何转换的额外好处。我不明白为什么这不会受到第一个等式中整数除法问题的影响。
请注意,数学上:X * (Y / Z) == X * Y / Z 所以第一个方程的整数除法肯定有问题
Here's a video 在调试器中观察这 3 个等式 watch window.
随着 i
的增加,您可以看到第一个方程的结果与第二个和第三个方程(结果始终相同)之间的差距越来越大。
为什么第三个方程给出的结果与第二个方程一样正确,而没有受到第一个方程中积分除法错误的影响?我似乎无法理解它...
感谢任何帮助。
答案是按照执行操作的顺序。第一个方程
int y = i * (game_height / numcells);
先进行除法,乘以i
放大舍入误差。 down/to 越往右移,累积的舍入误差越大。
最后一个方程
int y = i * game_height / numcells;
从左到右求值。随着您除以较大的数字 (i * game_height
),相对误差会变小。您仍然有舍入误差,但它不会累积。事实上,在最终评估中你没有得到额外的 space 是,i
等于 numcells
,基本上相互抵消了。您将始终在最终迭代中看到 y == game_height
。
使用浮点运算仍然更准确:虽然使用整数数学的舍入误差在每一行的区间 [0 .. numcells)
中,但浮点数学将其减少到 [0 .. 1)
。使用浮点数学,您将看到分布更均匀的线条。
注意:在 Windows 上,您可以使用 MulDiv 代替整数方程,以防止常见错误,例如瞬时溢出。