【发布时间】:2019-02-06 10:32:44
【问题描述】:
为使用内部函数实现Conway's Game of Life 做作业找到了工作代码,但无法理解它的主要部分。
此实现首先计算每个销售的存活邻居数量并将结果存储在数组counts 中,因此销售(世界)数组为states。我无法真正了解newstate 是如何在这里生成的。我了解左移是如何工作的,按位 OR 是如何工作的,但我不明白为什么要这样使用它们,为什么 shufmask 会这样以及随机播放是如何工作的。如果数组元素的类型是 uint8_t,也无法理解为什么使用 _mm256_slli_epi16。所以我的问题都是关于这个字符串
__m256i newstate = _mm256_shuffle_epi8(shufmask, _mm256_or_si256(c, _mm256_slli_epi16(oldstate, 3)));
你能帮我解释一下吗,笨蛋,如果可能最详细,它是如何工作的。
void gameoflife8vec(uint8_t *counts, uint8_t *states, size_t width, size_t height) {
assert(width % (sizeof(__m256i)) == 0);
size_t awidth = width + 2;
computecounts8vec(counts, states, width, height);
__m256i shufmask =
_mm256_set_epi8(
0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 1, 0, 0
);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j += sizeof(__m256i)) {
__m256i c = _mm256_lddqu_si256(
(const __m256i *)(counts + (i + 1) * awidth + j + 1));
c = _mm256_subs_epu8(
c, _mm256_set1_epi8(
1)); // max was 8 = 0b1000, make it 7, 1 becomes 0, 0 remains 0
__m256i oldstate = _mm256_lddqu_si256(
(const __m256i *)(states + (i + 1) * awidth + j + 1));
__m256i newstate = _mm256_shuffle_epi8(
shufmask, _mm256_or_si256(c, _mm256_slli_epi16(oldstate, 3)));
_mm256_storeu_si256((__m256i *)(states + (i + 1) * awidth + (j + 1)),
newstate);
}
}
}
数组的内存是这样分配的
uint8_t *states = (uint8_t *)malloc((N + 2) * (N + 2) * sizeof(uint8_t));
uint8_t *counts = (uint8_t *)malloc((N + 2) * (N + 2) * sizeof(uint8_t));
也可以在这里找到源代码https://github.com/lemire/SIMDgameoflife
【问题讨论】:
-
请参阅here 以获得对
_mm256_shuffle_epi8的清晰解释。 -
@wim shuffle 的算法非常清楚我的意思是我无法理解它如何引导新的单元格状态。所以它应该以某种方式检查细胞附近是否有多少活着的邻居并得到答案
-
我明白了。显然,我误解了你的问题的标题。不幸的是我不熟悉康威的游戏。
-
@wim 编辑了谢谢
-
@wim:您可能听说过en.wikipedia.org/wiki/Conway%27s_Game_of_Life,但 OP 忘记将“Life”大写。如果还没有,请检查一下;元胞自动机很漂亮。它甚至是图灵完备的。
标签: c++ intrinsics avx conways-game-of-life