정확하게 n 세트 비트로 숫자를 생성하기위한 PRNG


12

현재 이진 데이터를 생성하는 코드를 작성 중입니다. 특정 수의 세트 비트로 64 비트 숫자를 생성해야합니다. 보다 정확하게, 프로시 저는 취하고 0<n<64정확히 n 비트가 1 설정되고 나머지는 0으로 설정된 의사 난수 64 비트 숫자를 반환해야합니다 .

내 현재 접근 방식은 다음과 같습니다.

  1. 의사 난수 64 비트 숫자 생성하십시오 k.
  2. 비트를 단위로 세어 k결과를 저장합니다 b.
  3. 만약 b=n , 출력 k ; 그렇지 않으면 1로 이동하십시오.

이것은 효과가 있지만 우아하지 않은 것 같습니다. 이보다 n 세트 비트로 숫자를 생성 할 수있는 PRNG 알고리즘 이 있습니까?

답변:


12

필요한 것은 0과 사이의 난수 입니다. 문제는 이것을 비트 패턴으로 바꾸는 것입니다.(64n)1

이것을 열거 형 코딩이라고하며 가장 오래된 배포 압축 알고리즘 중 하나입니다. 아마도 가장 간단한 알고리즘은 Thomas Cover의 것입니다. 비트 길이 의 단어가 있고 설정된 비트가 가장 중요한 비트 순서 로 경우이 속성을 사용하는 모든 단어의 사전 순서 에서이 단어의 위치가 간단한 관찰을 기반으로합니다. 입니다 :nxkx1

1ik(xii)

예를 들어 7 비트 단어의 경우 :

i(0000111)=(23)+(12)+(01)=0
i(0001011)=(33)+(12)+(01)=1
i(0001101)=(33)+(22)+(01)=2

...등등.

서수에서 비트 패턴을 얻으려면 각 비트를 차례로 디코딩하면됩니다. C와 같은 언어로 이런 것이 있습니다 :

uint64_t decode(uint64_t ones, uint64_t ordinal)
{
    uint64_t bits = 0;
    for (uint64_t bit = 63; ones > 0; --bit)
    {
        uint64_t nCk = choose(bit, ones);
        if (ordinal >= nCk)
        {
            ordinal -= nCk;
            bits |= 1 << bit;
            --ones;
        }
    }
    return bits;
}

이항 계수는 최대 64 개만 필요하므로 미리 계산할 수 있습니다.


  • 커버, T., 열거 소스 인코딩 . 정보 이론에 관한 IEEE 거래, Vol IT-19, No 1, 1973 년 1 월.

아름답고 우아한! 열거 형 코딩은 매우 유용한 것으로 보입니다. 좋은 리소스가 있습니까 (교과서 형식으로)?
Koz Ross

실제로 실제로 더 나은 성능을 제공합니까? (물론 RNG의 속도에 따라 다릅니다.) 그렇지 않으면 더 복잡한 코드를 사용할 필요가 없습니다.
Gilles 'SO- 악의를 멈춰라'

1
@Giles 나는 이것이 cs.se이기 때문에 이것을 컴퓨터 과학 질문으로 해석했습니다. RRR 배열 구현에서 소스 코드를 사용했기 때문에 소스 코드 만 제공했습니다. ( 의미가 무엇인지에 대한 설명은 alexbowe.com/rrr 를 참조하십시오 .)
Pseudonym

1
@Gilles 귀하의 질문에 후속 조치를 취하기 위해 필자는 순진한 방법과 Forth의 가명에서 제공 한 방법을 모두 구현했습니다. 매우 간단한 xorshift PRNG를 사용할 때도 순진한 방법 은 숫자 당 20 초 정도 걸리는 반면, Pseudonym의 방법은 거의 즉각적입니다. 미리 계산 된 이항 표를 사용했습니다.
Koz Ross

1
@KozRoss n 비트 숫자를 생성하고 k 비트가 설정된 숫자를 찾는 경우 k가 n / 2에서 멀리 떨어져 있으면 드물게 나타납니다. 그것을 설명 할 것입니다.
gnasher729

3

다른 방법으로 얻은 가명과 매우 유사합니다.

별과 막대 방법 으로 사용 가능한 총 조합 수에 접근 할 수 있으므로 이어야 합니다. 숫자를 샘플링하려고 시도하는 총 64 비트 숫자의 수는 분명히 그보다 훨씬 높습니다.c=(64n)

그런 다음 필요한 것은 에서 사이 의 의사 난수 에서 해당 64 비트 조합으로 이어질 수있는 함수입니다 .1 ck1c

파스칼의 삼각형은 모든 노드의 값이 해당 노드에서 삼각형의 루트까지의 경로 수를 정확하게 나타내며 모든 왼쪽 경로가 레이블이 지정 되고 모든 오른쪽 회전은 됩니다.010

따라서 는 결정하기 위해 남겨진 비트 수이고, 사용할 비트 수입니다.yxy

우리는 이라는 것을 알고 있으며이를 사용하여 숫자의 다음 비트를 올바르게 결정할 수 있습니다 각 단계에서 :(xy)=(x1y)+(x1y1)

whilex>0

ifx>y

ifk>(x1y):ss+"1",kk(x1y),yy1

else:ss+"0"

else:ss+"1",yy1

xx1


2

또 다른 매우 우아한 방법은 이 stackoverflow 답변에 설명 된대로 이분법을 사용하는 입니다. 아이디어는 두 단어를 유지하는 것이며, 하나는 최대 k 비트 세트를 갖는 것으로 알려진 것과 다른 하나는 k 비트 이상을 설정 한 것으로 알려진 것입니다. 다음은이를 설명하기위한 소스 코드입니다.

word randomKBits(int k) {
    word min = 0;
    word max = word(~word(0)); // all 1s
    int n = 0;
    while (n != k) {
        word x = randomWord();
        x = min | (x & max);
        n = popcount(x);
        if (n > k)
            max = x;
        else
            min = x;
    }
    return min;
}

나는 다양한 방법성능을 비교 했으며 k가 매우 작은 것으로 알려진 경우가 아니면 가장 빠릅니다.


0

다음을 수행 할 수 있습니다.

1) 에서 사이의 난수 생성하십시오 .k164

2) th 을 설정하십시오 .k01

3) 1 단계와 2 단계를 반복 배n

A[] 이다 모두와 함께 비트 열 S640

for(i=1 to n)
{
    k=ran(1,65-i) % random number between 1 and 65-i
    for(x=1;x<65;x++)
    {
        if(A[x]==0)k--;
        if(k==0)break;
    }
    A[x]=1;
}

산문이 코드와 일치하지 않습니까? 코드는 1s를 배열에 할당하지 않습니다 . 또한 다중 k충돌 시 균일 분포 (및 구속 조건을 만족하는 숫자조차)를 생성하지 않는 것
Bergi

@Bergi Ya는 줄을 잊어 버렸습니다 ... 지금 추가했습니다. 그리고 k의 다중 충돌이 처리됩니다. 첫 번째 숫자는 1과 64 사이에서 선택되고 두 번째는 1과 "나머지"사이에서 선택됩니다 63. 계산하는 동안 1을 건너 뜁니다 ...선. 그리고 그것은 균일 한 분포입니다. A[x]=1if(A[x]==0)k;
사용자를 찾을 수 없음

아, 지금 봅니다. 산문 알고리즘은 건너 뛰기를 언급하지 않았습니다.
Bergi

@ArghyaChakraborty 1 기반 인덱싱을 사용하고 있습니까?
Koz Ross

@KozRoss (물론 는 모두 0) 인 경우에 발생하는 것부터 시작합니다. 따라서 하고 의미를이것은 을 제공합니다 . 따라서 루프 외부에서 설정 합니다. 예, 1 기반 인덱싱입니다. 그것은 0을 기반으로 당신이해야 할 모든 내부 변경되어 있는지 확인하기 에i=1,k=1AA[1]==0truek;k=0A[1]=1for(x=0;x<64;x++)
찾을 수 없음 사용자
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.