13

回答 #2 hereのようにランダム ID を生成するシステムに取り組んでいます。

私の問題は、前述のpseudo_encrypt()関数が bigint ではなく int で動作することです。私はそれを書き直そうとしましたが、常に同じ結果を返します:

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;

誰かがこれをチェックできますか?

4

2 に答える 2

18

429496729532 ビットを選択するには、ビットマスクとして (の代わりに) を使用する必要があります4294967296。これが、現在、異なる入力に対して同じ値を取得する理由です。

また、 andbigintの型に使用することをお勧めします。l2r2r1l1

また、ランダム性を高めるには、PRNG 関数ではるかに高い乗数を使用して、32767 ではなく 32767*32767 のように、実際に 32 ビットを占める中間ブロックを取得します。

完全な修正版:

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;

最初の結果:

x として generate_series (1, 10) から x,pseudo_encrypt(x::bigint) を選択します。
 × | pseudo_encrypt    
-+---------------------
  1 | 3898573529235304961
  2 | 2034171750778085465
  3 | 169769968641019729
  4 | 2925594765163772086
  5 | 1061193016228543981
  6 | 3808195743949274374
  7 | 1943793931158625313
  8 | 88214277952430814
  9 | 2835217030863818694
 10 | 970815170807835400
(10行)
于 2012-10-06T16:53:47.727 に答える
9

古いですが、まだ興味深い質問です。ダニエルズの回答と比較すると、記事の最後にも記載されているように、returnステートメントをこれに変更して(r1とl1を交換)、わずかに変更されたバージョンを使用していますPseudo encrypt

RETURN ((r1::bigint << 32) + l1);

この変更の理由は、基礎となるFeistel アルゴリズムが最終ラウンドの終了時に左右を交換してはならないためです。この変更により、関数は独自の逆関数として機能する能力を取り戻します。

pseudo_encrypt(pseudo_encrypt(x) == x // always returns true

pgsql の完全なコードは次のとおりです。

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 ((r1::bigint << 32) + l1);
END;
$$ LANGUAGE plpgsql strict immutable;
于 2015-04-30T08:01:23.267 に答える