Diehard 테스트를 통과하는 난수 생성기 구축


50

여기에 임의성을 포함하는 많은 코드 골프 질문이 있지만, 실제로 알고리즘 의사 난수 생성기를 작성하도록 요구하는 질문은 아직 보지 못했습니다. 거기에 이 하나의 비트 스트림을 생성하도록 요청하지만, 하나에서 제공하는 무작위 시험은 매우 엄격하지 않았다, 그것은 코드 골프 아니다.

작성하는 프로그램에는 0에서 4294967295 사이의 임의의 정수를 리턴하는 단일 호출 가능 함수가 있습니다.이 함수는 프로그램의 일부로 작성되지 않은 라이브러리 또는 기타 함수, 특히 / dev / random에 대한 호출을 호출하지 않아야합니다. 또는 언어의 내장 rand () 라이브러리. 보다 구체적으로 산술, 배열 액세스 및 조건부 흐름 제어 문과 같이 작업중인 언어의 기본 연산자로 제한됩니다.

프로그램 점수는 다음과 같이 계산됩니다.

Score = C / R

여기서 C는 문자 단위의 코드 길이이고 R은 생성기가 통과하는 Diehard 테스트 수입니다 (난수 생성기가 하나 이상의 Diehard 테스트를 통과하지 않으면 점수가 무한대가되어 실격됩니다). 생성 된 파일이 간격 [0, 1)을 따라 균일하게 분포 된 것처럼 보이는 P- 값 범위를 제공하면 생성기는 Diehard 테스트를 통과합니다.

R을 계산하려면 난수 생성기를 기본 시드와 함께 사용하여 16MB 이진 데이터 파일을 생성하십시오. 함수를 호출 할 때마다 4 바이트가 반환됩니다. 함수가 바이트를 반환하기에 너무 느리면 테스트하기가 어려워 낮은 점수를 얻는 것에 대한 절충을 고려해야합니다. 그런 다음 Diehard 테스트를 통해 실행하고 제공된 P- 값을 확인하십시오. (이것을 스스로 시도하지 말고 여기에 제공된 것을 사용 하십시오 )

물론 최저 점수가 승리합니다.


인터넷 연결이 필요한 코드가 허용됩니까? (온라인으로 임의의 기능에 액세스하지는 않지만 핑 또는 api 호출의 값)
elssar

"이 함수는 프로그램의 일부로 작성되지 않은 라이브러리 나 다른 함수를 호출해서는 안됩니다." 여기에는 인터넷 연결 기능이 포함됩니다. 당신의 세대는 순수한 알고리즘이어야합니다.
Joe Z.

diehard 제품군은 10-11MB의 입력 파일이 필요합니다.
primo

시험에 대한 링크가 깨진 것 같습니다 여기에 가능한 대안.
2012rcampion

내 두뇌 반응에 대해 어떻게해야합니까 (아래 제거)? 코드가 너무 느려 실용적이지 않다고 생각합니다.
Christopher

답변:


6

수학, 32/15 = 2.133

x=3;Mod[x=Mod[x^2,28!-67],2^32]&

BBS 의 간단한 구현 .

다음으로 생성 된 이진 파일 :

f = %; (* assigns anonymous function declared in the previous expression to f *)
Export["random.bin", Array[f, 2^22], "UnsignedInteger32"];

결과 요약 :

 1. BIRTHDAY SPACINGS TEST           .684805
 2. OVERLAPPING 5-PERMUTATION TEST   .757608/.455899
 3. BINARY RANK TEST                 .369264/.634256
 4. BINARY RANK TEST                 .838396
 5. THE BITSTREAM TEST                (no summary p-value)    
 6. OPSO, OQSO and DNA                (no summary p-value)
 7. COUNT-THE-1's TEST               .649382/.831761
 8. COUNT-THE-1's TEST                (no summary p-value)
 9. PARKING LOT TEST                 .266079
10. MINIMUM DISTANCE TEST            .493300
11. 3DSPHERES TEST                   .492809
12. SQEEZE                           .701241
13. OVERLAPPING SUMS test            .274531
14. RUNS test                        .074944/.396186/.825835/.742302
15. CRAPS TEST                       .403090/.403088/.277389

random.bin여기가 가득 합니다.

여기에 전체 로그 파일이 있습니다.


28!-67다소 금지 적입니다. 64 비트 정수에 맞는 더 작은 값이 있습니까?
primo

@primo Python과 마찬가지로 Mathematica의 정수는 기본적으로 임의의 정밀도이므로 문제를 일으키지 않습니다.
2012rcampion

나는 C 로의 이식성을 특별히 생각하고 있었다.
primo


21

펄 28/13 ≈ 2.15

sub r{$s^=~($s^=$s/7215)<<8}

여기에 로그 파일

펄 29/13 ≈ 2.23

sub r{$s^=~($s^=$s<<8)/60757}

여기에 로그 파일

이것들은 오른쪽 시프트 대신 부동 소수점 나누기를 사용하여 Xorshift 의 변형입니다 . 두 테스트 모두 15 개 중 13 개 테스트를 통과하고 테스트 6과 7 만 실패합니다.

사이클의 길이는 확실하지 않지만 다음 코드가 단기간에 종료되지 않기 때문에 전체 2 32 일 가능성이 큽니다 .

$start = r();
$i++ while $start != r();
print $i;

펄 39/10 = 3.9

$s=$^T;sub r{~($s=$s*$s%4294969373)||r}

참고 : Blum-Blum-Shub-esque PRNG를 찾고 있다면 Keith Randall의 솔루션 이 이들 중 하나보다 훨씬 낫습니다.

아래의 원래 솔루션과 마찬가지로 Blum Blum Shub도 한 가지 큰 차이점으로 구현되었습니다. 나는 2 32 보다 약간 큰 계수 ( M = 50971 • 84263 )를 사용하며, 값이 유효한 32 비트 정수 (즉, 2 32 보다 크지 않음)가 될 때마다 다음 값을 대신 회전. 본질적으로 이러한 값은 잘라 내고 나머지 회전은 그대로두고 분포는 거의 균일합니다.

도움이 된 것 같습니다. 이전과 동일한 9 가지 테스트를 통과 할뿐만 아니라 이제 최소 거리 테스트를 통과했습니다. 샘플 로그 파일은 여기 에서 찾을 수 있습니다 .


펄 33/9 ≈ 3.67 (잘못된?)

 $s=$^T;sub r{$s=$s*$s%4294951589}

참고 : 범위의 최상위 0.00037 %는 절대로 관찰되지 않으므로이 솔루션은 유효하지 않은 것으로 간주 될 수 있습니다.

Blum Blum Shub 의 빠르고 더러운 구현 . 나는 다음과 같은 결과를 주장한다.

 1. passed - Birthday Spacings
 2. FAILED - Overlapping Permutations
 3. passed - Ranks of 31x31 and 32x32 Matrices
 4. passed - Ranks of 6x8 Matrices
 5. FAILED - Monkey Tests on 20-bit Words
 6. FAILED - Monkey Tests OPSO, OQSO, DNA
 7. FAILED - Count the 1s in a Stream of Bytes
 8. passed - Count the 1s for Specific Bytes
 9. passed - Parking Lot Test
10. FAILED - Minimum Distance Test
11. passed - Random Spheres Test
12. FAILED - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test

샘플 로그 파일은 여기 에서 찾을 수 있습니다 . 결과에 대해 이의를 제기하십시오. diehard 용 파일은 다음과 같은 방식으로 생성 될 수 있습니다.

print pack('N', r()) for 1..4194304

그런 다음 출력을 파일로 파이핑합니다. 최소 거리는 지나간 것으로 보이지만 여러 번 실행하면 항상 1.0에 매우 가깝습니다 . 이는 실패를 나타냅니다.


세부

일반적으로 Blum Blum Shub는 끔찍한 PRNG이지만 좋은 모듈러스를 선택하면 성능을 향상시킬 수 있습니다. M 내가 선택한이다 611207 • 7027 . 이들 주요 요인 pq 는 모두 모듈 형 잔류 물 3 (mod 4)gcd (φ (p-1), φ (q-1)) = 2 를 가지며, 가능한 한 낮습니다.

이것들이 위키 페이지에 나열된 유일한 기준이지만 충분하지는 않습니다. 내가 시도한 거의 모든 모듈로가 모든 테스트에 실패했습니다. 그러나 몇 가지 테스트를 통과하는 소수가 있으며, 내가 선택한 테스트는 어떤 이유로 든 예외적으로 좋은 것으로 보입니다.

마지막으로, 테스트 5 자체는 PRNG가 얼마나 좋은지에 대한 상당히 좋은 지표 인 것 같습니다. 테스트 5를 거의 통과 하지 못하면 나머지는 훌륭하게 실패합니다.


보너스 : Perl 62/14 ≈ 4.43

$t=$^T;sub r{$t|=(($s=$s/2|$t%2<<31)^($t/=2))<<31for 1..37;$t}

괴짜를 위해서만, 이것은 NES의 원래 Tetris에서 사용 된 32 비트 버전의 PRNG입니다. 놀랍게도 15 개의 테스트 중 14 개를 통과했습니다!

 1. passed - Birthday Spacings
 2. passed - Overlapping Permutations
 3. passed - Ranks of 31x31 and 32x32 Matrices
 4. passed - Ranks for 6x8 Matrices
 5. passed - Monkey Tests on 20-bit Words
 6. passed - Monkey Tests OPSO, OQSO, DNA
 7. FAILED - Count the 1s in a Stream of Bytes
 8. passed - Count the 1s for Specific Bytes
 9. passed - Parking Lot Test
10. passed - Minimum Distance Test
11. passed - Random Spheres Test
12. passed - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test

여기 전에 샘플 로그 파일을 사용할 수 있습니다 .

분명히, 1..37비트는 정확한 전사가 아닙니다. 원래 버전에서 엔트로피 루틴은 초당 60 회 업데이트 된 다음 사용자 간격에 따라 크게 임의의 간격으로 쿼리됩니다. ROM을 분해해야하는 사람은 엔트로피 루틴을 시작하십시오 0xAB47.

파이썬 스타일의 의사 코드 :

carry = entropy_1 & 1
entropy_1 >>= 1
entropy_2 = (entropy_2 >> 1) | (carry << 31)
carry = (entropy_1 & 1) ^ (entropy_2 & 1)
entropy_1 |= carry << 31

예, 귀하의 알고리즘이 비트 스트림 테스트에 "실패"한 것으로 나타 났지만 실제로 0.999999 미만의 값이 몇 개있었습니다. 그래도 테스트는 정확 해 보입니다.
Joe Z.

그러나 한 가지 문제가 있으며 4294951589에서 4294967295까지의 숫자가 발생할 가능성이 없다는 것입니다 (Diehard 테스트 중 일부가 실패한 이유라고 생각하지만).
Joe Z.

1
@JoeZeng 네, 문제입니다. 테스트 5에서 가장 분명합니다. 첫 번째 실행에는 151k 누락 된 단어가 있고 나머지는 143k 누락되었습니다. 한 가지 해결책은 2 ^ 32보다 약간 큰 계수를 선택하고 너무 큰 값을 0으로 감쌀 수는 있지만 잘 작동하는 값을 찾을 수 없었습니다. 그렇게하면 게시물을 업데이트하겠습니다.
primo

7

파이썬, 46/15 = 3.0666

v=3
def R():global v;v=v**3%(2**32-5);return v

랜덤 지수를 생성하기 위해 모듈 식 지수를 사용합니다. 2 ** 32-5는 2 ^ 32보다 작은 소수입니다. (테스트 # 2를 실행할 수없는 것과 동일합니다.)


로그 파일을 붙여 넣을 수 있습니까?
primo

여기에 기록하십시오 : codepad.org/ZWhoGe0t
Keith Randall

1
바보 같은 창문. 그것은 모든 차례 나오는 변환 된 \r\n\r\n분명히 결과를 스큐한다. 수정은 f = open('file.bin', 'wb')and를 사용하여 파일을 직접 작성하는 것 f.write입니다.
primo

이 새로운 점수는 이전 점수를 약화 시키므로 이제는 정답입니다.
Joe Z.

이 새로운 점수는 다시 한 번 저평가되었으므로 합격 답변을 변경했습니다.
Joe Z.

4

루비, 32/15 = 2.1333

이것이 Ruby로 구현 된 Keith Randall의 솔루션입니다.

$v=3;def R;$v=$v**3%(2**32-5)end

@JoeZ 이것은 새로운 Mathematica 답변과 함께 새로운 최저 답변으로 보입니다.
Riking

3

C # 144/15 = 9.6

uint a=15,b=26,y;uint q(int n){y=(a*1414549U+876619U)^(b*889453U+344753U);b=a;a=y>>12;return(a%256)<<n;}uint r(){return q(24)|q(16)|q(8)|q(0);}

이것은 모든 테스트를 통과했습니다.

문자가 너무 많지 않으면 TestU01을 통과합니다.

결과 : http://codepad.org/iny6usjV

    uint a = 15;
    uint b = 26;

    byte prng8()
    {
        uint y = ((a * 1414549U + 876619U) ^ (b * 889453U + 344753U)) >> 12;
        b = a;
        a = y;
        return (byte)y;
    }

    uint prng32()
    {
        return ((uint)prng8() << 24) | ((uint)prng8() << 16) | ((uint)prng8() << 8) | (uint)prng8();
    }

2

C #-103/14 = 7.36

double j=999;uint N(){uint i=0,n=0;for(;i++<4;n=n*256+(uint)j%256)for(j/=277;j<100000;j*=j);return n;}

결과

시험 # 6을 제외한 모든 시험에 합격 http://codepad.org/k1NSoyQW
에서 결과보기

설명

C #은 평소와 같이 루비와 파이썬과의 간결함을 경쟁 할 수는 없지만 시도를 즐겼습니다. 확실히 작동하는 다른 값들도 있습니다 (예 : j = 999의 초기 값 및 제수 = 277). 나는 간단한 실험 후에 이것을 골랐다.

파일 생성 래퍼

class R
{
    public static void Main(string[] args)
    {
        var r = new R();
        using (var f = new System.IO.FileStream(".\\out.bin", System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Read))
        using (var b = new System.IO.BinaryWriter(f))
        {
            for (long i = 0; i < 12 * 1024 * 1024; i += 4)
            {

                b.Write(r.N());
            }
        }
    }

    double j = 999;

    uint N()
    {
        uint i = 0, n = 0;
        for (; i++ < 4; n = n * 256 + (uint)j % 256)
            for (j /= 277; j < 100000; j *= j) ;
        return n;
    }

}

1

파이썬, 41/15 = 2.73333

v=0
def R():global v;v=hash(`v`);return v

일종의 사용하여 부정 행위 해시 기능 내장,하지만이 됩니다 에 내장, 그래서 같은 다른 내장 명령을 사용하는 것보다 더 이상 부정 행위 len. 반대로, global v;진술에 대한 비용을 지불 해야하는 것은 고통 스럽습니다 ...

모든 Diehard 테스트를 통과합니다 (테스트 # 2에 문제가있었습니다. OSX 컴퓨터에서 SEGV입니다. 점수에 대해서는 합격한다고 가정합니다).

16MB 파일을 생성하는 드라이버는 다음과 같습니다.

import sys
for i in xrange(1<<22):
  r=R()
  sys.stdout.write('%c%c%c%c'%(r&255, r>>8&255, r>>16&255, r>>24&255))

"이 함수는 프로그램의 일부로 작성되지 않은 라이브러리 나 다른 함수, 특히 / dev / random 또는 언어의 내장 rand () 라이브러리를 호출하지 않아야합니다." 죄송 합니다만 참가 자격이 박탈됩니다.
Joe Z.

분명히, "len"은 또한 참가 자격을 박탈합니다.
Joe Z.

선은 어디에서 그리나요? 되어 +A는 기능을 내장하고, 따라서 실격?
Keith Randall

6
그러나 많은 언어에서 연산자와 함수는 동일합니다. 참조 +__add__파이썬에서, 또는 운영자 C ++에 과부하. 나는 머리카락을 쪼개고 있다는 것을 알고 있으므로이 예를 고려하십시오. 파이썬에서 다음과 같은 맵을 만들 수 {'a':5}있습니까? 당신은 아마 그렇다고 말할 것입니다, 그러나 hash('a')당신이 그것을 할 때 표지 아래에서 그것을 부르는 것을 고려하십시오 .
Keith Randall

2
구문 방식으로 함수를 참조해야 할 때 선을 그립니다. 파이썬에서 "해시"함수를 구문 적으로 참조하지 않고 맵 주소에 직접 액세스 할 수있는 해킹을 찾을 수 있다면 받아 들일 수 있습니다.
Joe Z.

1

C, 38/15 = 2.533

long long x;f(){return(x+=x*x+9)>>32;}

내 컴퓨터에서 Diehard 테스트를 수행 할 수 없지만 PractRand 제품군을 최대 8GB의 출력으로 전달하므로 모두 통과한다고 가정합니다.


0

Brain-Flak , 344 / (보류 중)

<>((()()){})<> push the amount of iterations to do for the PRNG
(((((((((((((((((((((((((((((((((((()()()){}()){})){}{}){()()()()({}[()])}{})){}{})){}{})()){}{})()){}{})){}{})){}{}){}())){}{})){}{})()){}{})()){}{})){}{})){}{})()){}{})()){}{}) push M (one of the values for the Blum Blum Shub PRNG
((((((((((((()()()){}){}){})){}{}){()({}[()])}{}){}())){}{})()){}{}) push s see above
<>{({}[()])<>starts the loop
(({({})({}[()])}{}) squares the current number
(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]({}))mods by M
<>}{}<>loop ends

온라인으로 사용해보십시오!

이것은 잘 작동하지만 diehard 테스트 링크가 모두 끊어졌습니다 : (우리가 새로운 것을 얻을 때까지 나는 최종 점수가 없습니다.

이것은 Blum Blum Shub PRNG를 사용하므로 대부분의 경우를 통과해야합니다. 사용 된 숫자가 충분히 커서 16MB의 테스트 사례에 패턴이 나타나지 않습니다.


이것이 유효하지 않다면 말해줘
Christopher

1
나는 344를 세었다. 정리 : 완전히 골프를 친 Brain-flak 프로그램에는 홀수 바이트가 없다.
user202729

0

오브젝티브 -C, 40/1 = 40

.hash여기에 약간의 속임수를 사용 하는 꽤 영리한 접근 방식 이지만 좋아합니다.

for(int v=9;v=@(v).hash;printf("%i",v));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.