Oct*_*nus 8 c++ math sse bit-manipulation ternary
我有一个问题,我有八个可以包含 0、1 或 2 的元素。我可以很容易地用 16 位来表示它,但是出于 SIMD 效率的原因,我需要它占据 13 位(它不是唯一存在的东西)在车道)。
幸运的是,2^13==8192, 和3^8==6561,所以我想要的状态可以适合。然而,这就是事情变得有趣的地方。天真地,我只是通过计算三元数字状态来表示这些状态。例如,要表示 tritmask 0t12211012(尽管我将使用它作为示例),我可以只写0t12211012 = 2*3^0+1*3^1+0*3^2+1*3^3+1*3^4+2*3^5+2*3^6+1*3^7 = 4244 = 0b1000010010100.
我有一组我需要支持的操作:
0t12211012并且我希望将 a2放在保持零的位置,我可以简单地添加0t200=18. (请注意,转换为 tritspace 很容易,因为我只有 8 个 trit,所以我可以将基本幂存储在寄存器中并使用 pshufw 对其进行索引)。0t12211012,我希望能够提取位掩码 for 0,即0b00000100, for 1,即0b10011010,和 for 2,即0b01100001。这我还没有想出该怎么做,这就是我想要的帮助。如何在适用于 x86 SIMD 的少量操作中做到这一点?谢谢!
20 年 18 月 11 日编辑:举一个我认为太慢的方法的例子:我们可以迭代地找到值 mod 3 并除以 3 以从表示的最不重要的一端拉出trits,然后以这种方式组装掩码. C++ 片段:
uint32_t trits = <something>;
uint8_t mask0 = 0, mask1 = 0, mask2 = 0;
for (uint8_t shift = 0; shift < 8; ++shift) {
const uint32_t remainder = trits % 3;
mask0 |= (!remainder) << shift;
mask1 |= (remainder == 1) << shift;
mask2 |= (remainder == 2) << shift;
trits /= 3;
}
Run Code Online (Sandbox Code Playgroud)
当实际用 SIMD 语言编写它时,我们将使用标准的乘法和移位技巧来除以常数。但是你可以看到它在 trits 的数量上是线性的,并且每次迭代有很多 ops。我们可以稍微降低一下代码,但我认为这从根本上是错误的方法。理想情况下应该可以为每个 Trit 并行做一些事情......但我没有看到它。
20 年 11 月 20 日编辑:我做了半心半意的努力,将Aha应用于这个问题,但没有成功。也许要解决的一个有趣的子问题是 - 在与上述相同的约束下,是否有一个短序列的按位操作充当“三元按位与”?也就是说,一个 op 比较 tritspace 中的两个编码数字并返回一个位掩码,当相应的 trits 相等时返回 1,否则返回 0?那将是我们可以从中构建所需操作的原语。我们在 tritspace 中有左移和右移(只需乘以或除以 3);我们有 +/- 一个值。所以我们缺少的是测试trits是否是特定值的能力......