สร้างตัวสร้างตัวเลขสุ่มที่ผ่านการทดสอบ Diehard


50

ในขณะที่มีคำถามเกี่ยวกับการสุ่มกอล์ฟจำนวนมากที่นี่เกี่ยวกับการสุ่ม แต่ฉันยังไม่เห็นคำถามที่ถามเพื่อสร้างเครื่องกำเนิดเลขเทียมแบบอัลกอริทึม มีสิ่งนี้ที่ขอให้คุณสร้างกระแสบิต แต่การทดสอบแบบสุ่มที่ให้ไว้นั้นไม่เข้มงวดมากและไม่ใช่รหัส - กอล์ฟ

โปรแกรมที่คุณเขียนจะมีฟังก์ชั่น callable เดียวที่จะส่งกลับจำนวนเต็มแบบสุ่มจาก 0 ถึง 4294967295 ฟังก์ชั่นนี้จะต้องไม่เรียกใช้ไลบรารีหรือฟังก์ชั่นอื่น ๆ ที่ไม่ได้เขียนไว้เป็นส่วนหนึ่งของโปรแกรม หรือไลบรารี rand () ในตัวของภาษา โดยเฉพาะอย่างยิ่งคุณถูก จำกัด ให้ใช้งานตัวดำเนินการพื้นฐานของภาษาที่คุณกำลังทำงานอยู่เช่นเลขคณิตการเข้าถึงอาร์เรย์และคำสั่งควบคุมการไหลตามเงื่อนไข

คะแนนของโปรแกรมของคุณถูกคำนวณดังนี้:

Score = C / R

โดยที่ C คือความยาวของรหัสเป็นตัวอักษรและ R คือจำนวนการทดสอบ Diehardที่เครื่องกำเนิดของคุณผ่าน (หากเครื่องสร้างหมายเลขสุ่มของคุณไม่ผ่านการทดสอบ Diehard อย่างน้อยหนึ่งการทดสอบคะแนนของมันจะไม่สิ้นสุดและไม่มีคุณสมบัติ) เครื่องมือสร้างของคุณผ่านการทดสอบ Diehard ว่าไฟล์ที่สร้างนั้นมีช่วงของค่า P ที่ปรากฏว่ามีการกระจายอย่างสม่ำเสมอตลอดช่วงเวลา [0, 1)

ในการคำนวณ R ให้ใช้ตัวสร้างตัวเลขสุ่มกับเมล็ดเริ่มต้นเพื่อสร้างไฟล์ข้อมูลไบนารีขนาด 16 MB การเรียกใช้ฟังก์ชันแต่ละครั้งส่งคืนสี่ไบต์ หากฟังก์ชั่นของคุณช้าเกินกว่าจะส่งคืนจำนวนไบต์สิ่งนี้จะเป็นปัจจัยที่ทำให้การแลกเปลี่ยนคะแนนต่ำนั้นยากที่จะทดสอบ จากนั้นเรียกใช้ผ่านการทดสอบ Diehard และตรวจสอบค่า P ที่ได้รับ (อย่าพยายามใช้สิ่งเหล่านี้ด้วยตนเองใช้สิ่งที่มีให้ในที่นี้ )

ชนะคะแนนต่ำสุดแน่นอน


อนุญาตให้ใช้รหัสที่ต้องใช้การเชื่อมต่ออินเทอร์เน็ตหรือไม่ (ไม่ gonna เข้าถึงฟังก์ชั่นแบบสุ่มออนไลน์ใด ๆ แต่บางที ping หรือค่านิยมของการโทรของ API)
elssar

"ฟังก์ชั่นนี้จะต้องไม่เรียกใช้ไลบรารีใด ๆ หรือฟังก์ชั่นอื่น ๆ ที่ไม่ได้เขียนเป็นส่วนหนึ่งของโปรแกรม" ซึ่งรวมถึงฟังก์ชั่นการเชื่อมต่ออินเทอร์เน็ต รุ่นของคุณควรเป็นอัลกอริทึมอย่างหมดจด
Joe Z.

ชุดมิจฉาทิฐิคาดว่าไฟล์อินพุต 10-11 MB
primo

ลิงก์ไปยังการทดสอบดูเหมือนจะใช้งานไม่ได้นี่เป็นทางเลือกที่เป็นไปได้
2012rcampion

ฉันควรทำอย่างไรกับคำตอบที่สะกิดใจสมองของฉัน (ลบด้านล่าง) ฉันคิดว่ารหัสนี้ช้าเกินกว่าจะใช้งานได้จริง
Christopher

คำตอบ:


6

Mathematica, 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 Like Python จำนวนเต็ม Mathematica มีความแม่นยำตามอำเภอใจตามค่าเริ่มต้นดังนั้นจึงไม่ทำให้เกิดปัญหา
2012rcampion

ฉันคิดมาโดยเฉพาะสำหรับการพกพาเข้าไปในซี
พรีโม่


21

Perl 28/13 ≈ 2.15

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

ล็อกไฟล์ที่นี่

Perl 29/13 ≈ 2.23

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

ล็อกไฟล์ที่นี่

สิ่งเหล่านี้เป็นความแตกต่างของXorshiftโดยใช้การแบ่งจุดแบบลอยแทนการกะขวา พวกเขาทั้งสองผ่านการทดสอบ 13 จาก 15 การทดสอบที่ล้มเหลวเพียง 6 และ 7

ฉันไม่แน่ใจว่ารอบการทำงานนั้นนานแค่ไหน แต่เนื่องจากรหัสต่อไปนี้ไม่ได้สิ้นสุดลงในช่วงเวลาสั้น ๆ จึงเป็นไปได้ที่2 32เต็ม:

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

Perl 39/10 = 3.9

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

หมายเหตุ: หากคุณกำลังมองหา PRNG Blum-Blum-Shub-esque วิธีแก้ปัญหาของ Keith Randallดีกว่าสิ่งใดสิ่งหนึ่ง

เช่นเดียวกับโซลูชันดั้งเดิมของฉันด้านล่างนี่เป็นการนำ Blum Blum Shub มาใช้ซึ่งมีความแตกต่างที่สำคัญอย่างหนึ่ง ฉันใช้มอดุลัสที่มีขนาดใหญ่กว่า2 32เล็กน้อย( M = 50971 • 84263 ) และเมื่อใดก็ตามที่พบว่าค่านั้นไม่ใช่จำนวนเต็ม 32 บิตที่ถูกต้อง (นั่นคือมากกว่า2 32 ) จะส่งกลับค่าถัดไปใน หมุนแทน ในสาระสำคัญค่าเหล่านี้จะถูกตัดออกเหลือส่วนที่เหลือของการหมุนที่ไม่ถูกรบกวนส่งผลให้มีการกระจายเกือบสม่ำเสมอ

ดูเหมือนว่าจะช่วย นอกเหนือจากการผ่านการทดสอบ 9 ครั้งเหมือนเมื่อก่อนตอนนี้ก็ผ่านการทดสอบระยะทางขั้นต่ำอย่างน่าเชื่อถือ แฟ้มบันทึกตัวอย่างสามารถพบได้ที่นี่


Perl 33/9 ≈ 3.67 (ไม่ถูกต้อง?)

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

หมายเหตุ: การแก้ปัญหานี้อาจถือว่าไม่ถูกต้องเนื่องจาก 0.00037% สูงสุดของช่วงจะไม่ถูกสังเกต

การดำเนินรวดเร็วและสกปรกของบลัมบลัม 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

ไฟล์บันทึกตัวอย่างสามารถพบได้ที่นี่อย่าลังเลที่จะโต้แย้งผลลัพธ์ใด ๆ ไฟล์สำหรับมิจฉาทิฐิสามารถสร้างในลักษณะดังต่อไปนี้:

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

จากนั้นไพพ์เอาท์พุทเป็นไฟล์ ระยะทางขั้นต่ำดูเหมือนว่ามันจะผ่านไปแล้ว แต่ถ้าคุณวิ่งหลาย ๆ ครั้งมันจะอยู่ใกล้กับ1.0มากซึ่งบ่งบอกถึงความล้มเหลว


รายละเอียด

โดยทั่วไป Blum Blum Shub นั้นแย่มาก PRNG แต่ประสิทธิภาพนั้นสามารถปรับปรุงได้ด้วยการเลือกโมดูลัสที่ดี Mผมเคยได้รับการแต่งตั้งเป็น7027 • 611,207 ทั้งปัจจัยสำคัญเหล่านี้pและqมีสารตกค้างแบบแยกส่วน3 (mod 4)และgcd (φ (p-1), φ (q-1)) = 2ซึ่งต่ำที่สุดเท่าที่จะเป็นไปได้

แม้ว่าสิ่งเหล่านี้เป็นเพียงเกณฑ์ที่ระบุไว้ในหน้า wiki แต่ก็ดูเหมือนจะไม่เพียงพอ โมดูโล่เกือบทั้งหมดที่ฉันลองใช้นั้นล้มเหลวทุกการทดสอบ แต่มีไม่กี่คนที่จะผ่านการทดสอบบางอย่างและแบบทดสอบที่ฉันเลือกนั้นดูดีมากไม่ว่าด้วยเหตุผลใด

ในฐานะที่เป็นบันทึกสุดท้ายการทดสอบ 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}

เพียงแค่ geekery นี่คือ PRNG รุ่น 32 บิตที่ใช้ใน Tetris ดั้งเดิมสำหรับ NES น่าประหลาดใจที่ผ่านการทดสอบ 14 จาก 15 ครั้ง!

 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 ครั้งต่อวินาทีจากนั้นทำการสอบถามตามช่วงเวลาที่สุ่มขึ้นอยู่กับอินพุตของผู้ใช้เป็นหลัก 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 เล็กน้อยและอนุญาตให้ค่าที่มีขนาดใหญ่เกินไปที่จะล้อมรอบเป็นศูนย์ แต่ฉันไม่สามารถหาวิธีที่ทำงานได้ดี ถ้าฉันทำฉันจะอัปเดตโพสต์
primo

7

Python, 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
Windows ที่โง่ มันกำลังแปลงเหตุการณ์ทั้งหมดที่เกิดขึ้น\rและ\nไป\r\nเป็นซึ่งเห็นได้ชัดว่าผลลัพธ์ที่ได้ การแก้ไขคือการเขียนไฟล์โดยตรงโดยใช้และf = open('file.bin', 'wb') f.write
primo

คะแนนใหม่นี้จะลดคะแนนก่อนหน้านี้ดังนั้นจึงเป็นคำตอบที่ยอมรับแล้ว
Joe Z.

คะแนนใหม่นี้ถูกตัดราคาอีกครั้งดังนั้นฉันจึงเปลี่ยนคำตอบที่ยอมรับได้
Joe Z.

4

Ruby, 32/15 = 2.1333

นี่คือวิธีการแก้ปัญหาของ Keith Randall นำไปใช้ใน Ruby

$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 # ไม่สามารถแข่งขันกับ Ruby และ Python เพื่อความตึงเครียดได้ตามปกติ แต่ฉันสนุกกับการลอง มีค่าอื่น ๆ ที่แน่นอนเช่นกัน (เช่นค่าเริ่มต้นสำหรับ 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

Python 41/15 = 2.73333

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

Kinda โกงโดยใช้ฟังก์ชั่นกัญชา แต่มันถูกสร้างขึ้นในจึงไม่มีการโกงมากกว่าการใช้ builtins อื่น ๆ lenเช่น ในทางกลับกันมันทำให้ฉันต้องจ่ายสำหรับglobal v;งบ ...

ผ่านการทดสอบ Diehard ทั้งหมด (ฉันมีปัญหากับการทดสอบ # 2 มัน SEGVs บนเครื่อง OSX ของฉันสำหรับคะแนนของฉันฉันคิดว่ามันจะผ่านไป)

นี่คือไดรเวอร์สำหรับสร้างไฟล์ 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.

คุณวาดเส้นที่ไหน ถูก+สร้างขึ้นในฟังก์ชั่นและตัดสิทธิ์ด้วยเหตุนี้?
Keith Randall

6
แต่ในภาษาจำนวนมากตัวดำเนินการและฟังก์ชั่นเหมือนกัน ดู+และ__add__ในหลามหรือผู้ประกอบการมากไปใน c ++ ฉันรู้ว่าฉันเป็นเส้นขนแยกดังนั้นลองพิจารณาตัวอย่างนี้ ในไพ ธ อนฉันสามารถสร้างแผนที่แบบนี้ได้{'a':5}ไหม: คุณอาจจะตอบว่าใช่ แต่จากนั้นให้พิจารณาว่าภายใต้ที่กำบังhash('a')ได้รับการเรียกเมื่อคุณทำเช่นนั้น
Keith Randall

2
ฉันคิดว่าฉันจะวาดเส้นเมื่อคุณจำเป็นต้องมีการอ้างอิง syntactically ฟังก์ชั่นในลักษณะที่ หากคุณพบแฮ็คใน Python ที่จะช่วยให้คุณเข้าถึงที่อยู่แผนที่ได้โดยตรงโดยไม่ต้องมีการอ้างอิงถึงฟังก์ชัน "แฮช" ทางไวยากรณ์ฉันอาจยอมรับมัน
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

ลองออนไลน์!

วิธีนี้ใช้งานได้ดี แต่ลิงก์การทดสอบมิจฉาทิฐิใช้งานไม่ได้ :( ดังนั้นจนกว่าเราจะได้คะแนนใหม่ฉันไม่มีคะแนนสุดท้าย

วิธีนี้ใช้ Blum Blum Shub PRNG ดังนั้นจึงควรผ่านกรณีส่วนใหญ่ ตัวเลขที่ใช้มีขนาดใหญ่พอจะไม่มีรูปแบบปรากฏในกรณีทดสอบ 16 MB


ถ้าสิ่งนี้ไม่ถูกต้องเพียงแค่บอกฉัน
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.