我正在开发一个生成随机 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;
有人可以检查一下吗?
最佳答案
4294967295
必须用作位掩码以选择 32 位(而不是 4294967296
)。
这就是为什么目前您对不同输入获得相同值的原因。
我还建议对 l2
和 r2
类型使用 bigint
,它们与 r1 应该没有什么区别
和 l1
并且,为了更好的随机性,在 PRNG 函数中使用更高的乘数来获得真正占用 32 位的中间 block ,例如 32767*32767 而不是 32767。
完整修改版:
CREATE OR REPLACE FUNCTION pseudo_encrypt(VALUE bigint) returns bigint AS $$
DECLARE
l1 bigint;
l2 bigint;
r1 bigint;
r2 bigint;
i int:=0;
BEGIN
l1:= (VALUE >> 32) & 4294967295::bigint;
r1:= VALUE & 4294967295;
WHILE i < 3 LOOP
l2 := r1;
r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767*32767)::int;
l1 := l2;
r1 := r2;
i := i + 1;
END LOOP;
RETURN ((l1::bigint << 32) + r1);
END;
$$ LANGUAGE plpgsql strict immutable;
第一个结果:
select x,pseudo_encrypt(x::bigint) from generate_series (1, 10) as x; x | pseudo_encrypt ----+--------------------- 1 | 3898573529235304961 2 | 2034171750778085465 3 | 169769968641019729 4 | 2925594765163772086 5 | 1061193016228543981 6 | 3808195743949274374 7 | 1943793931158625313 8 | 88214277952430814 9 | 2835217030863818694 10 | 970815170807835400 (10 rows)
关于sql - plpgsql 中采用 bigint 的 pseudo_encrypt() 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12761346/