Xây dựng một trình tạo số ngẫu nhiên vượt qua các bài kiểm tra Diehard


50

Mặc dù có rất nhiều câu hỏi golf mã ở đây liên quan đến tính ngẫu nhiên, tôi chưa thấy một câu hỏi nào thực sự yêu cầu xây dựng một trình tạo số giả ngẫu nhiên thuật toán. Có cái này yêu cầu bạn tạo một luồng bit, nhưng các bài kiểm tra ngẫu nhiên được cung cấp trên đó không phải là rất nghiêm ngặt, và nó không phải là môn đánh gôn.

Chương trình bạn viết sẽ có một hàm có thể gọi duy nhất sẽ trả về một số nguyên ngẫu nhiên từ 0 đến 4294967295. Hàm này không được gọi bất kỳ thư viện hoặc các hàm khác không được viết như một phần của chương trình, đặc biệt là các lệnh gọi đến / dev / ngẫu nhiên hoặc thư viện rand () tích hợp sẵn của ngôn ngữ. Cụ thể hơn, bạn bị giới hạn ở các toán tử cơ bản của ngôn ngữ bạn đang làm việc, chẳng hạn như số học, truy cập mảng và các câu lệnh điều khiển luồng có điều kiện.

Điểm của chương trình của bạn được tính như sau:

Score = C / R

Trong đó C là độ dài của mã tính theo ký tự và R là số lần kiểm tra Diehard mà trình tạo của bạn vượt qua (Nếu trình tạo số ngẫu nhiên của bạn không vượt qua ít nhất một bài kiểm tra Diehard, điểm của nó là vô cùng và nó bị loại). Trình tạo của bạn vượt qua kiểm tra Diehard nếu tệp mà nó tạo ra cung cấp một phạm vi giá trị P dường như được phân phối đồng đều dọc theo khoảng [0, 1).

Để tính R, sử dụng trình tạo số ngẫu nhiên của bạn với hạt giống mặc định của nó để tạo tệp dữ liệu nhị phân 16 MB. Mỗi cuộc gọi của hàm trả về bốn byte; nếu chức năng của bạn quá chậm để trả về byte, điều này sẽ tạo ra sự đánh đổi để đạt được điểm thấp bởi mức độ khó kiểm tra. Sau đó, chạy nó qua các thử nghiệm Diehard và kiểm tra các giá trị P được cung cấp. (Đừng tự mình thử và thực hiện những điều này; hãy sử dụng những cái được cung cấp ở đây )

Điểm số thấp nhất chiến thắng, tất nhiên.


Là mã yêu cầu kết nối internet được cho phép? (sẽ không truy cập bất kỳ chức năng ngẫu nhiên trực tuyến nào, nhưng có thể ping hoặc các giá trị của cuộc gọi api)
elssar

"Hàm này không được gọi bất kỳ thư viện hoặc các hàm khác không được viết như một phần của chương trình." Điều đó bao gồm các chức năng kết nối Internet. Thế hệ của bạn nên hoàn toàn là thuật toán.
Joe Z.

Bộ công cụ cực kỳ mong đợi các tệp đầu vào 10-11 MB.
primo

Liên kết đến các bài kiểm tra dường như bị phá vỡ, đây là một sự thay thế có thể.
2012rcampion

Làm thế nào để làm điều này cho câu trả lời não bộ của tôi (loại bỏ dưới đây)? Tôi nghĩ rằng mã quá chậm để trở nên thiết thực
Christopher

Câu trả lời:


6

Toán học, 32/15 = 2.133

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

Một triển khai đơn giản của BBS .

Tệp nhị phân được tạo bằng:

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

Tóm tắt kết quả:

 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

Đầy đủ random.binở đây.

Hồ sơ đầy đủ ở đây.


28!-67có phần cấm đoán. Có một giá trị nhỏ hơn phù hợp với số nguyên 64 bit không?
primo

@primo Giống như Python, các số nguyên của Mathicala theo mặc định có độ chính xác tùy ý, do đó nó không gây ra sự cố.
2012rcampion

Tôi đã suy nghĩ cụ thể về tính di động vào C.
primo


21

Perl 28/13 2,15

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

đăng nhập tập tin ở đây

Perl 29/13 2,23

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

đăng nhập tập tin ở đây

Đây là một cái gì đó của một biến thể trên Xorshift , sử dụng phân chia dấu phẩy động thay vì dịch chuyển phải. Cả hai đều vượt qua 13 trong số 15 bài kiểm tra, chỉ trượt bài kiểm tra 6 và 7.

Tôi không chắc chắn chính xác chu kỳ là bao lâu, nhưng vì đoạn mã sau không chấm dứt trong bất kỳ khoảng thời gian ngắn nào, nên có khả năng là toàn bộ 2 32 :

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

Perl 39/10 = 3,9

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

Lưu ý: nếu bạn đang tìm kiếm một PRNG Blum-Blum-Shub-esque, giải pháp của Keith Randall tốt hơn nhiều so với một trong hai.

Như với giải pháp ban đầu của tôi dưới đây, đây cũng là một triển khai của Blum Blum Shub, với một sự khác biệt lớn. Tôi sử dụng một mô-đun lớn hơn 2 32 ( M = 50971 • 84263 ) và bất cứ khi nào gặp một giá trị mà nó không phải là số nguyên 32 bit hợp lệ (nghĩa là lớn hơn 2 32 ), nó sẽ trả về giá trị tiếp theo trong thay thế luân chuyển. Về bản chất, các giá trị này được cắt bỏ, khiến phần còn lại của vòng quay không bị xáo trộn, dẫn đến phân phối gần như thống nhất.

Nó dường như đã giúp đỡ. Ngoài việc vượt qua 9 bài kiểm tra tương tự như trước đây, giờ đây nó cũng vượt qua bài kiểm tra Khoảng cách tối thiểu một cách thuyết phục. Một tệp nhật ký mẫu có thể được tìm thấy ở đây .


Perl 33/9 3,67 (Không hợp lệ?)

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

Lưu ý: giải pháp này có thể được coi là không hợp lệ, vì hầu hết 0,00037% trong phạm vi sẽ không bao giờ được quan sát.

Một triển khai nhanh chóng và bẩn thỉu của Blum Blum Shub . Tôi yêu cầu các kết quả sau:

 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

Một tệp nhật ký mẫu có thể được tìm thấy ở đây , vui lòng tranh chấp bất kỳ kết quả nào. Các tập tin cho diehard có thể được tạo theo cách sau:

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

và sau đó đường ống đầu ra thành một tập tin. Khoảng cách tối thiểu có vẻ như đã vượt qua, nhưng nếu bạn chạy nó nhiều lần thì nó luôn rất gần với 1.0 , điều này cho thấy sự thất bại.


Chi tiết

Nhìn chung, Blum Blum Shub là một PRNG khủng khiếp, nhưng hiệu suất của nó có thể được cải thiện bằng cách chọn một mô-đun tốt. Các M tôi đã chọn là 7027 • 611.207 . Cả hai yếu tố chính này, pq , đều có dư lượng mô-đun 3 (mod 4)gcd ((p-1), φ (q-1)) = 2 , mức này thấp nhất có thể.

Mặc dù đây là những tiêu chí duy nhất được liệt kê trên trang wiki, nhưng dường như nó không đủ. Hầu như tất cả các modulo tôi đã thử thất bại trong mọi thử nghiệm. Nhưng có một số ít sẽ vượt qua một số bài kiểm tra, và bài kiểm tra mà tôi đã chọn dường như đặc biệt tốt, vì bất kỳ lý do gì.

Như một lưu ý cuối cùng, bản thân Test 5 dường như là một chỉ số khá tốt về mức độ PRNG tốt như thế nào. Nếu nó gần như không vượt qua Bài kiểm tra 5, nó sẽ thất bại một cách ngoạn mục.


TIỀN THƯỞNG: Perl 62/14 4,43

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

Chỉ dành cho người đam mê, đây là phiên bản 32 bit của PRNG được sử dụng trong Tetris gốc cho NES. Thật đáng ngạc nhiên, nó vượt qua 14 trong số 15 bài kiểm tra!

 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

Tệp nhật ký mẫu có thể trước đây .

Phải thừa nhận rằng, 1..37bit không phải là phiên âm chính xác. Trong phiên bản ban đầu, thói quen entropy được cập nhật 60 lần mỗi giây và sau đó được truy vấn theo các khoảng thời gian ngẫu nhiên, chủ yếu phụ thuộc vào đầu vào của người dùng. Đối với bất cứ ai quan tâm đến việc tháo rời ROM, thói quen entropy bắt đầu từ 0xAB47.

Mã giả kiểu Python:

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

Vâng, tôi nhận thấy rằng thuật toán của bạn "thất bại" trong bài kiểm tra dòng bit, nhưng thực sự có một vài giá trị dưới 0,999999. Tuy nhiên, các bài kiểm tra của bạn có vẻ chính xác.
Joe Z.

Tuy nhiên, có một vấn đề và đó là các số từ 4294951589 đến 4294967295 không có cơ hội xảy ra (mặc dù tôi cho rằng đó là một phần lý do khiến nó thất bại trong một số bài kiểm tra Diehard).
Joe Z.

1
@JoeZeng vâng, đó là một vấn đề. Điều đó thể hiện rõ nhất trong Bài kiểm tra 5: lần chạy đầu tiên có 151k từ bị thiếu và phần còn lại chỉ thiếu 143k. Một giải pháp sẽ là chọn một mô-đun lớn hơn 2 ^ 32 một chút và cho phép các giá trị quá lớn để bao quanh bằng 0, nhưng tôi không thể tìm thấy một mô đun hoạt động tốt. Nếu tôi làm, tôi sẽ cập nhật bài viết.
primo

7

Con trăn, 46/15 = 3.0666

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

Sử dụng lũy ​​thừa mô-đun để tạo ngẫu nhiên. 2 ** 32-5 là số nguyên tố lớn nhất nhỏ hơn 2 ^ 32. (Thỏa thuận tương tự với việc không thể chạy thử nghiệm # 2.)


Bạn có thể dán một tập tin nhật ký?
primo

Đăng nhập tại đây: codepad.org/ZWhoGe0t
Keith Randall

1
Windows ngu ngốc. Nó đã chuyển đổi tất cả các lần xuất hiện \r\nsang \r\n, điều này rõ ràng làm sai lệch kết quả. Cách khắc phục là ghi tệp trực tiếp bằng f = open('file.bin', 'wb')f.write.
Primo

Điểm mới này gạch dưới điểm số trước đó, vì vậy bây giờ là câu trả lời được chấp nhận.
Joe Z.

Điểm mới này đã được undercut một lần nữa, vì vậy tôi đã thay đổi câu trả lời được chấp nhận.
Joe Z.

4

Hồng ngọc, 32/15 = 2.1333

Đây là giải pháp của Keith Randall, được thực hiện trong Ruby.

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

@JoeZ Đây dường như là câu trả lời thấp nhất mới, gắn liền với câu trả lời Mathicala hoàn toàn mới.
Đạp xe

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);}

Điều này đã vượt qua tất cả các bài kiểm tra.

Với không quá nhiều ký tự, nó vượt qua TestU01.

Kết quả: 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;}

Các kết quả

Vượt qua tất cả ngoại trừ bài kiểm tra # 6
Xem kết quả tại http://codepad.org/k1NSoyQW

Giải trình

C # không thể cạnh tranh với Ruby và Python vì sự căng thẳng, như thường lệ, nhưng tôi rất thích thử. Chắc chắn có các giá trị khác cũng sẽ hoạt động tốt (nghĩa là giá trị ban đầu cho j = 999 và ước số = 277). Tôi đã chọn những thứ này sau khi thử nghiệm ngắn.

Với trình bao bọc tạo tệp

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

Con trăn, 41/15 = 2.73333

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

Loại gian lận bằng cách sử dụng hàm băm tích hợp, nhưng nó được tích hợp sẵn, vì vậy không gian lận hơn so với sử dụng các nội dung khác, như thế nào len. Mặt khác, tôi cảm thấy đau đớn khi phải trả tiền cho global v;tuyên bố ...

Vượt qua tất cả các bài kiểm tra Diehard (Tôi gặp vấn đề với bài kiểm tra số 2, đó là SEGV trên máy OSX của tôi. Đối với điểm số của tôi, tôi cho rằng nó sẽ vượt qua).

Đây là trình điều khiển để tạo tệp 16 MB:

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))

"Hàm này không được gọi bất kỳ thư viện hoặc các hàm khác không được viết như một phần của chương trình, đặc biệt là các lệnh gọi đến / dev / ngẫu nhiên hoặc thư viện rand () tích hợp của ngôn ngữ." Tôi xin lỗi, nhưng điều đó không đủ tiêu chuẩn của bạn.
Joe Z.

Để rõ ràng, "len" cũng sẽ không đủ điều kiện cho mục nhập của bạn.
Joe Z.

Bạn ve con đương nay ở đâu vậy? Là +một chức năng tích hợp, và do đó bị loại?
Keith Randall

6
Nhưng trong rất nhiều ngôn ngữ, toán tử và hàm giống hệt nhau. Xem +__add__trong python, hoặc toán tử quá tải trong c ++. Tôi biết tôi là loại tóc chẻ ngọn, vì vậy hãy xem xét ví dụ này. Trong python tôi có thể tạo một bản đồ như thế này {'a':5}không? Bạn có thể nói có, nhưng sau đó xem xét rằng dưới vỏ bọc, hash('a')được gọi khi bạn làm điều đó.
Keith Randall

2
Tôi cho rằng tôi sẽ vẽ đường khi bạn cần tổng hợp tham chiếu hàm theo cách đó. Nếu bạn có thể tìm thấy một bản hack trong Python cho phép bạn truy cập trực tiếp vào địa chỉ bản đồ mà không cần tham khảo cú pháp về chức năng "băm", tôi có thể chấp nhận nó.
Joe Z.

1

C, 38/15 = 2.533

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

Tôi không thể để các thử nghiệm Diehard hoạt động trên máy của mình, nhưng nó vượt qua bộ PracticeRand cho đầu ra tối đa 8GB vì vậy tôi cho rằng nó sẽ vượt qua tất cả.


0

Brain-Flak , 344 / (đang chờ xử lý)

<>((()()){})<> 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

Hãy thử trực tuyến!

Điều này hoạt động tốt nhưng các liên kết kiểm tra cực đoan đều bị hỏng :( vì vậy cho đến khi chúng tôi nhận được các liên kết mới, tôi không có điểm cuối cùng

Điều này sử dụng Blum Blum Shub PRNG vì vậy nó sẽ vượt qua hầu hết các trường hợp. Các số được sử dụng đủ lớn, sẽ không có mẫu nào xuất hiện trong 16 MB trường hợp thử nghiệm


nếu điều này không hợp lệ, chỉ cần cho tôi biết
Christopher

1
Tôi đếm 344. Định lý: Không có chương trình Brain-flak nào được đánh gôn hoàn toàn có số byte lẻ.
dùng202729

0

Mục tiêu-C, 40/1 = 40

Cách tiếp cận khá thông minh, khai thác .hashđể phần nào gian lận ở đây, nhưng tôi thích nó

for(int v=9;v=@(v).hash;printf("%i",v));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.