数组引用速度与按位运算符

时间:2016-01-27 23:47:20

标签: c++ arrays performance reference bit-manipulation

我目前正在制作国际象棋游戏,我将我的信息存储在两个8乘8阵列中。第一个商店团队类型(1表示白色,0表示空白,-1表示黑色),第2个存储部件类型(1表示pawn,2表示车辆等等)。由于我正在为游戏编程AI,我想知道我是否可以将这两个地图组合在一起,一个8乘8阵列。信息将存储在一个字节中,如下所示:

  

00 A BC DEF

其中A表示如果移动,BC代表团队:

  

00 A 01 DEF for white,

     

00黑色的10 DEF,

     <00> 00 A 00 DEF什么都没有

和DEF以类似的方式表示片段类型。我会通过&amp; 使用字节的掩码来访问这些值。所以这是我的问题。计算机是否能够使用较小的阵列更快地访问信息,或者按位功能是否会使其运行得太慢?记忆对我来说不是问题。

2 个答案:

答案 0 :(得分:2)

这里的答案是“是,否,也许”。它真的取决于编译器的优秀程度,运行的处理器,以及最重要的,空间或时间。

我的直觉是在位掩码中存储速度会慢一些,无论是一次存储一个字节还是按位模式,检索都是一样的。

商店的原因包括:

  value = (value & ~ bits) | new_value; 

其中bits是您要使用的位的掩码(例如,对于颜色,它将是0x18或00011000.

检查值涉及单一操作:

  value & bits; 

另一方面,如果使用三个[或四个]字节来存储每个值,则会为每个元素获得单字节存储和单字节加载。这与现代机器上的任何东西一样快。

影响这一点的还有处理器有多少缓存 - 从主内存中获取甚至执行L2缓存获取比两个或三个额外的简单指令要慢。

但对于这样的事情,真正的答案是:编写一些代码并测量速度。确保你这样做是真实的,这样你就有了适量的其他指令,正确的数据量(5个字节的工作量不同于建立可能的6个移动的移动,100000个选择[全板]计算对于每个移动级别。)

答案 1 :(得分:1)

您选择DEF作为底部3位是明智的。您可能希望使用它们来索引表,因此只需要屏蔽,而不是移位和屏蔽,这很好。

如果您想要使用BC位索引表,将它们作为高2位意味着您只需要移位,而不是掩码。

或者,如果您经常要测试A位,将其作为MSB可以节省少量代码。由于直接字节,test al,al / js(符号位上的分支)略短于test al, 0x20 / jnz(第5位分支)。但是,唯一的速度差异在于x86代码大小,所以它非常小。

What is the efficient way to count set bits at a position or lower?利用了类似的技巧,编译器可以使用算术右移将符号位广播到整个寄存器。然后可以将其用作AND掩码。

按位操作很便宜。如果您经常需要两条信息(片段类型和颜色),那么将地图打包在一起可能会更好,而不是拥有两个单独的数组。四个16B矢量寄存器可以容纳整个电路板。从内存中加载L1高速缓存在x86上非常便宜,如果有很多并行性并且你的代码已经在每个时钟的3或4个ALU操作上已经瓶颈,那么甚至可能比寄存器中的几个ALU操作更便宜。 (Intel SnB / Haswell)。所以单独存储它可能是一个胜利,但只有当L1中的所有内容真的很热时。否则,每次都要获取数据密度。

许多国际象棋程序将棋盘位置存储为Bitboard,其中64位int的每个位置代表棋盘位置。所以你可能有一个&#34;黑色棋子的面具&#34;和&#34;白色的棋子&#34;。您可以将它们组合在一起以获得多个部分的位板。你可以和他们一起看看他们相交的地方。

我认为你可以使用聪明的按位来检查主教可以攻击的对角线,以及类似的东西。 32位和64位立即常数很便宜。