2015-11-17 24 views
7

PostgreSQLで固有の乱数を13桁の固定長で生成する必要があります。 "pseudo_encrypt"を使用して暗号化されたシーケンスが使用されたのと同じようなthreadが見つかりましたが、返された数字は固定長ではありませんでした。Postgresqlで一意の乱数を固定長で生成する

だから、私は必要なものである:最小値が0000000000001で、最大値は9999999999999.

ことが可能です13桁の固定長で暗号化された乱数列を取得しますか?正面のゼロで始めることができないのは大きな問題ではない(私は思う)、私はそれらをプログラムからdbから読み込む間に設定できるが、PostgreSQLが単独でそれを行うことができるならば素晴らしいだろう。

は、私はPostgreSQLでユニークな乱数(BIGINT)を生成する必要があります。

- - EDIT

私は私が必要なものをよりよく説明するために質問を変更しなければならないいくつかの有用なものを実現していた後、 13桁の固定長です。実際には私はpseudo_encrypt関数(64ビット)を使用しようとしていますが、返された数は明らかに固定長さ13、32ビットの場合、最大長は10桁(int)であり、64ビットは19(bigint)。

最小値が1で最大値が9999999999999の固定長さが13桁の暗号化ランダムシーケンスを取得するにはどうすればよいですか?

この結果を得るには、64ビットpseudo_ecrypt関数を変更することはできますか?あるいは、可能でない場合は、この要件を備えたユニークなシーケンスを得る他の方法がありますか?

擬似暗号化機能(64)Nの既存の機能を微調整

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; 
+1

'to_char(pseudo_encrypt(nextval( 'seq'):: int)、 '0000000000000')' –

+0

シーケンスはどうなっていますか?どのように私はそれを設定する必要がありますか? – MattC

+0

リンク先の質問と同じです。最大値が13桁を超えないようにしてください。 –

答えて

11

< 64ビットは、それが出力を低減するbigint型バリアントを微調整することは比較的簡単です

2^N値であり、Nが偶数であり、64未満である。

13桁の13桁を取得するには、に13桁の最大Nを入力します。それはN = 42、2^42=4398046511104です。

このアルゴリズムは、入力値を等しいビット数で2つの半分に分割し、それらがFeistelネットワークを流れ、基本的にラウンド関数の結果と排他的論理和をとり、反復ごとに半分を入れ替えることによって機能します。

プロセスの各段階で、各半分が21ビットに制限されている場合、両方の半分を組み合わせた結果は42ビットを超えないことが保証されます。

だからここに私の提案Variantの:

CREATE OR REPLACE FUNCTION pseudo_encrypt42(VALUE bigint) returns bigint 
AS $$ 
DECLARE 
    l1 bigint; 
    l2 bigint; 
    r1 bigint; 
    r2 bigint; 
    i int:=0; 
    b21 int:=(1<<21)-1; -- 21 bits mask for a half-number => 42 bits total 
BEGIN 
    l1:= VALUE >> 21; 
    r1:= VALUE & b21; 
    WHILE i < 3 LOOP 
    l2 := r1; 
    r2 := l1 # (((((1366*r1+150889)%714025)/714025.0)*32767*32767)::int & b21); 
    l1 := l2; 
    r1 := r2; 
    i := i + 1; 
    END LOOP; 
    RETURN ((l1::bigint << 21) + r1); 
END; 
$$ LANGUAGE plpgsql strict immutable; 

が入力さそう出力はpseudo_encrypt42(x) = pseudo_encrypt42(x mod 2^42)として、衝突し、(2^42)-1未満でなければなりません。

2^42と10^13の間の番号の欠落については何ができるのですか?

2^42 - 10^13 = 5601953488896これはかなり多くの欠落した数字です。 私は、Feistelネットワークで一回のパスでそれを手助けする方法がわかりません。ただし、受け入れられる可能性のある回避策の1つは、0..Mに別の一意の値を生成し、2^42を追加することで、衝突の危険はありません。

この別のセットは、オフセットが追加された同じ機能で取得できます。 4398046511104 + pseudo_encrypt42(x)43980465111042*4398046511104 = 8796093022208の間で一意の値になることが保証されているため、目標に近づいています。同じテクニックは、必ずしも同じサイズでなくても、他のいくつかの範囲で適用することができます。

ただし、この回避策ではなく、すべての数は0X間とすることができる単一の出力レンジを持つのように、ランダムに見える行動を低下させる、あなたはX/N数字のN明確な出力範囲を取得したいです。このようないくつかの異なるパーティションでは、出力がどのパーティションにあるのかを推測するのは簡単です。

+1

これは私の問題を解決します、ダニエルありがとう!これは非常に詳細な応答ですが、私はこれが他の開発者にとっても非常に有用であると確信しています! – MattC

+1

あなたのケースでは、左側の部分に 'VALUE >>(64-21)'を使用しているので、衝突を避けるために入力は '(2^21)'より小さくなければならないと思います。この場合、 '2^21'よりも値が小さく、何かよりも小さい場合は、左の部分としてゼロになりますが、右の部分は再びゼロから始まります。それを修正するために、私は 'VALUE >> 21'シフトを左の部分に使いました(最初の21ビットの後に次の21ビットをとるようなものです)、あなたの制限'(2^42) 'が有効になりました。 – mopdobopot

+0

@mopdobopot:そうです、良いキャッチです。答えにコードを修正しました。 –

関連する問題