我正在开发一个生成随机ID的系统,如答案#2 here。
我的问题是,提到的pseudo_encrypt()函数使用int而不是bigint。我试着重写它,但它总是返回相同的结果:
CREATE OR REPLACE FUNCTION pseudo_encrypt(VALUE bigint) returns bigint AS $$
DECLARE
l1 bigint;
l2 int;
r1 bigint;
r2 int;
i int:=0;
BEGIN
l1:= (VALUE >> 32) & 4294967296::bigint;
r1:= VALUE & 4294967296;
WHILE i < 3 LOOP
l2 := r1;
r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int;
l1 := l2;
r1 := r2;
i := i + 1;
END LOOP;
RETURN ((l1::bigint << 32) + r1);
END;
$$ LANGUAGE plpgsql strict immutable;
有人能检查一下吗?
2条答案
按热度按时间9q78igpj1#
4294967295
必须用作位掩码以选择32位(而不是4294967296
)。这就是为什么目前不同的输入得到相同的值的原因。我还建议对
l2
和r2
类型使用bigint
,它们应该与r1
和l1
没有什么不同而且,为了更好的随机性,在PRNG函数中使用更高的乘数来获得真正占用32位的中间块,如32767*32767而不是32767。
完整的修改版本:
初步结果:
ej83mcc02#
古老但仍然是一个有趣的问题。与Daniels的答案相比,我使用了一个稍微修改过的版本,将return语句改为这样(交换了r1和l1),正如文章Pseudo encrypt的结尾所提到的:
这种变化的原因是基础Feistel algorithm不应该在最后一轮结束时交换左和右。通过此更改,函数重新获得充当其自身的反函数的能力:
下面是pgsql中的完整代码: