假设我有8个包含16个值的表:
uint32_t lut[8][16];
我想用这些值填充这些表,以便组合(添加,eor,等等)来自八个表中的每个表的一个条目将产生唯一的32位值 - 不同于组合任何其他组的结果条目。
也就是说,对于随机变量i
,j
,k
,l
,m
,n
,{{1我需要来自o
的唯一结果,以获取这些变量可以拥有的所有不同值。{}和p
虽然合并操作不一定是加号。
总共有lut[0][i] + lut[1][j] + lut[2][k] + lut[3][l] + lut[4][m] + lut[5][n] + lut[6][o] + lut[7][p]
个(40亿)输入组合,每个输入的结果必须是不同的。
另外 - 这是困难的部分 - 我希望这些条目看起来是随机的。
显而易见的答案是:
16**8
我们可以证明它适用于:
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);
}
这有点帮助,但并不多。
我最终做的是上面例子中的一系列变换。我可以对组合值执行的任何1:1 线性变换使其更加随机,可以提前对表格元素执行,如果我得到了同样的结果,就好像我在那之后完成它我已经证明每个可能的组合仍然产生一个唯一的值(因为它在变换之前做了)。
但这种方法有一些限制。所以我想知道;还有另一种方法可以使用给定的约束来随机化这些表吗?
答案 0 :(得分:0)
这就是我所做的。
我可以对组合结果执行任何1:1类似哈希的变换,我也可以事先对表进行,只要这些变换是线性的。
所以,如果我能做到这一点:
for (int i = 0; i < 8; i++) {
shuffle(lut[i], 16);
}
然后,只要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);
}
的隐式模的共同素数,所以它总是有一个1:1的映射):
uint32_t
这里的问题是低阶位不会受到高阶位的影响,因此导致高位变化的输入变化(uint32_t transform(uint32_t x) {
return bitpermute(x) * 0x39597a05;
}
之后的高位)赢了&# 39; t对低位有影响。我们不能右移,因为那不是线性的。在组合操作之前的右移在它之后具有不同的进位传播。
这些携带物正在破坏一切!
为了使进位不在等式中,我们可以改变域。使我们的加号为plus-mod2(exclusive-or):
bitpermute()
现在我们的乘法必须用可比较的东西代替:
uint32_t y = 0;
for (int i = 0; i < 8; i++) {
y ^= lut[i][(x >> (i * 4)) & 15];
}
在那里,我修好了。
遗憾的是,这牺牲了进位的好处,相邻位的组合可以影响其他位...但是如果它们都遵循相同的模式,我可以从任何位混合到任何其他位。
而不是mod-2算术(使用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-4:+
然后我必须限制所有我的变得平坦。尽管如此,我还没有调查过这个问题,因为我不确定它是否会朝着有用的方向发展。