【问题标题】:Set of LUTs which guarantee unique integer combination保证唯一整数组合的 LUT 集
【发布时间】:2016-02-14 07:26:51
【问题描述】:

假设我有 16 个值的 8 个表:

uint32_t lut[8][16];

我想用这样的值填充这些表,以便组合(添加、eor 等)八个表中的每一个中的一个条目将产生一个唯一的 32 位值 - 与组合任何其他组的结果不同条目。

也就是说,对于随机变量ijklmnop,我想要来自@的唯一结果987654330@ 对于这些变量可以具有的所有不同值。虽然合并操作不一定是加号。

总共有16**8(40 亿)个输入组合,每个组合的结果必须不同。

另外——这是最难的部分——我希望这些条目随机出现。

显而易见的答案是:

uint32_t lut[8][16] = {
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
    { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60 /* ... */ },
    { 0x000, 0x100, 0x2000 /* ... */ },
    /* ... */
};

我们可以证明它适用于:

for (uint64_t x = 0; x < 0x100000000; x++) {
  uint32_t y = 0;
  for (int i = 0; i < 8; i++) {
    y += lut[i][(x >> (i * 4)) & 15];
  }
  assert(x == y);
}

但这根本不是随机的!

我可以这样做:

for (int i = 0; i < 8; i++) {
  shuffle(lut[i], 16);
}

这有点帮助,但不大。

我最终在上面的例子中做了一堆变换。我可以对组合值执行任何 1:1 线性 变换以使其“更随机”,可以提前对表格元素执行,并且如果我得到与我相同的结果'然后我已经证明了每种可能的组合仍然会产生唯一的值(因为它在转换之前就已经完成了)。

不过,这种方法有一些限制。所以我想知道;是否有另一种方法可以使用给定的约束随机化这些表?

【问题讨论】:

  • 为什么不做“逆向操作”呢?选择 8 个随机的 32 位值,然后将它们中的每一个“拆分”到相应索引处的表中。
  • @barakmanos 有 40 亿(16 的 8 次方)可能的表格组合,所以当我通过表格分配 32 位结果时,我必须考虑其部分如何与不同的选择交互来自不同的表条目;我不知道该怎么做。

标签: c permutation discrete-mathematics


【解决方案1】:

这就是我所做的。

我可以对组合结果进行的任何 1:1 类似哈希的变换,我也可以事先对表进行,只要这些变换是线性的。

所以,如果我能做到这一点:

uint32_t y = 0;
for (int i = 0; i < 8; i++) {
  y += lut[i][(x >> (i * 4)) & 15];
}
y = transform(y);

那么,只要transform() 是线性的,我就可以这样做:

for (int i = 0; i < 8; i++) {
  for (int j = 0; j < 16; j++) {
    lut[i][j] = transform([i][j]);
  }
}

而且我可以非常积极地使用该功能,因为我只需要做一次就可以设置表格。

作为初始操作,我可以对位重新排序,因为没有一个位重叠,这意味着无需担心进位行为:

uint32_t bitpermute(uint32_t x) {
  int s = 1;
  uint32_t y = 0;
  for (int i = 0; i < 32; i++) {
    if ((x & 1) != 0) {
      y |= 1 << (a & 31);
    }
    a = a * 1103515245 + 12345;
    x >>= 1;
  }
  return y;
}

uint32_t transform(uint32_t x) {
  return bitpermute(x);
}

而且我可以乘以一个奇数(任何奇数都与 uint32_t 的隐式模互质,因此它始终具有 1:1 映射):

uint32_t transform(uint32_t x) {
  return bitpermute(x) * 0x39597a05;
}

这里的问题是低位不能被高位影响,所以对输入的改变导致高位改变(bitpermute()之后的高位)不会有任何影响在低位。我们不能右移,因为那不是线性的。合并操作之前的右移与之后的右移具有不同的进位传播。

那些carry正在毁掉一切!

要从等式中取出进位位,我们可以更改域。将我们的 plus 设为 plus-mod2(异或):

uint32_t y = 0;
for (int i = 0; i < 8; i++) {
    y ^= lut[i][(x >> (i * 4)) & 15];
}

现在我们的乘法必须用类似的东西代替:

uint32_t bitmix(uint32_t x, uint32_t p, int s) {
  uint32_t y = 0;
  while (p > 0) {
    if ((p & 1) != 0) {
      y ^= x;
    }
    x = (s > 0) ? (x >> -s) : (x << s);
    p >>= 1;
  }
  return y;
}

uint32_t transform(uint32_t x) {
  x = bitpermute(x);
  x = bitmixup(x, 0x39597a05, 1);
  x = bitmixdn(x, 0x1b0bb8ad, -1);
  x = bitmixup(x, 0x09bb8825, 1);
  return x;
}

在那里,我修好了。

遗憾的是,这牺牲了进位的好处,即相邻位的组合会影响其他位......但如果它们都遵循相同的模式,我可以从任何位混合到任何其他位。

而不是 mod-2 算术(使用 ^ 代替 +),我可以使用以下成语将其设为 mod-4:r = x + y - (x &amp; y &amp; 0xaaaaaaaa),然后我必须将所有班次限制为均匀。不过,我还没有对此进行调查,因为我不确定它是否朝着有帮助的方向发展。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    • 2018-11-20
    相关资源
    最近更新 更多