水平/垂直均匀分布网格单元?

Posted

技术标签:

【中文标题】水平/垂直均匀分布网格单元?【英文标题】:Evenly distribute grid cells horizontally/vertically? 【发布时间】:2015-08-17 02:00:29 【问题描述】:

我试图在game_width=640game_height=480 的窗口内绘制一个网格。网格单元的数量是预定义的。我想水平和垂直均匀分布单元格。

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 个方程。

随着i 的增加,您可以看到第一个等式的结果与第二个和第三个等式(始终具有相同的结果)之间的差距越来越大。

为什么第三个方程和第二个方程一样给出正确的结果,而没有受到第一个方程的积分除法误差的影响?我似乎无法理解它......

感谢任何帮助。

【问题讨论】:

【参考方案1】:

答案是按照执行操作的顺序。第一个方程

int y = i * (game_height / numcells);

首先执行除法,并通过乘以i 来放大舍入误差。向下/向右移动越远,累积的舍入误差就越大。

最后一个方程

int y = i * game_height / numcells;

从左到右计算。相对误差会变小,因为您正在划分更大的数字 (i * game_height)。你仍然有一个舍入误差,但它不会累积。事实上,您在最终评估中没有多余的空间是,i 等于numcells,基本上相互抵消。在最终迭代中,您将始终看到 y == game_height

使用浮点运算仍然更准确:虽然使用整数数学的舍入误差在每行的区间 [0 .. numcells) 内,但浮点数学将其减少到 [0 .. 1)。您将看到使用浮点数学的更均匀分布的线条。


注意:在 Windows 上,您可以使用 MulDiv 代替整数方程,以防止常见错误,例如瞬时溢出。

【讨论】:

以上是关于水平/垂直均匀分布网格单元?的主要内容,如果未能解决你的问题,请参考以下文章

GridBagLayout:均匀分布的单元格

使用 CSS Grid 和 Flexbox 水平对齐位于不同网格单元格中的元素

使用css网格均匀分布的图像

尝试以编程方式均匀分布网格布局

图标,它们在网格中均匀分布

css 网格自动动态/未知列数均匀分布