เหตุใดจึงต้องใช้ C # class System.Random แทน System.Security.Cryptography.RandomNumberGenerator


87

ทำไมใคร ๆ ก็ใช้ตัวสร้างตัวเลขสุ่ม "มาตรฐาน" จากSystem.Randomเลยแทนที่จะใช้ตัวสร้างตัวเลขสุ่มที่ปลอดภัยด้วยการเข้ารหัสลับจากSystem.Security.Cryptography.RandomNumberGenerator (หรือคลาสย่อยเนื่องจาก RandomNumberGenerator เป็นนามธรรม)

Nate Lawson บอกเราในงานนำเสนอของ Google Tech Talk ว่า " Crypto Strikes Back " ในนาทีที่ 13:11 ว่าอย่าใช้เครื่องกำเนิดตัวเลขสุ่ม "มาตรฐาน" จาก Python, Java และ C # และให้ใช้เวอร์ชันที่มีการเข้ารหัสลับที่ปลอดภัยแทน

ฉันรู้ความแตกต่างระหว่างเครื่องสร้างตัวเลขสุ่มทั้งสองเวอร์ชัน (ดูคำถาม 101337 )

แต่มีเหตุผลอะไรบ้างที่จะไม่ใช้ตัวสร้างตัวเลขสุ่มที่ปลอดภัยเสมอไป? ทำไมต้องใช้ System.Random เลย? ประสิทธิภาพบางที?


7
คุณอยากพิมพ์แบบไหน
Macha

13
มีคนจำนวนมากที่ใช้สิ่งนั้นอย่างจริงจังเพื่อเป็นเหตุผลในสิ่งที่พวกเขาทำ (โดยปกติจะไม่ดัง) อ่านโค้ดมากกว่าที่เขียนใครสนใจเกี่ยวกับความแตกต่างของความยาวเล็กน้อย
Mark Sowul

3
แต่ทำไมคุณควรใช้ RNG การเข้ารหัสหากคุณไม่ได้ทำการเข้ารหัส
Mark Sowul

3
@Macha นั่นคือนามแฝงสำหรับ ->using R = System.Security.Cryptography.RandomNumberGenerator; R.Create();
cchamberlain

คำตอบ:


147

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


31
ฉันชอบการโต้แย้งเจตนาเป็นอย่างมาก
Lernkurve

12
ควรสังเกตว่า Random.GetNext ยังห่างไกลจากความสามารถในการ "กระจาย" ตัวเลขสุ่มบนสเปกตรัมโดยเฉพาะอย่างยิ่งในสภาพแวดล้อมแบบเธรด ฉันพบปัญหานี้เมื่อเขียนโปรแกรมเพื่อทดสอบวิธีแก้ปัญหาต่างๆของ Rand7 จากปัญหา Rand5 ในการทดสอบแบบเธรดอย่างรวดเร็วตอนนี้มีตัวเลขสุ่ม 100000 หมายเลขระหว่าง 0 ถึง 10 82470 ของตัวเลขที่สร้างขึ้นคือ 0 ฉันเห็นความคลาดเคลื่อนที่คล้ายคลึงกันในการทดสอบครั้งก่อน Crytpography random มากแม้ในการแจกแจงตัวเลข ฉันเดาว่าบทเรียนคือการทดสอบข้อมูลสุ่มของคุณเสมอเพื่อดูว่า "สุ่มเพียงพอ" สำหรับความต้องการของคุณ
Kristoffer L

35
@Kristoffer Randomฉันคิดว่าคุณในทางที่ผิด ให้ฉันเดา: คุณได้สร้างอินสแตนซ์ใหม่ของRandomคลาสสำหรับแต่ละหมายเลขซึ่งตั้งแต่เริ่มต้นโดยตัวจับเวลาหยาบจะถูก seed ด้วยค่าเดียวกันในช่วงเวลาประมาณ 1-16ms
CodesInChaos

15
@CodesInChaos: นอกจากนั้นยังมีเงื่อนไขการแข่งขันRandomที่ทำให้ส่งคืนค่า 0 ทั้งหมดเมื่อวัตถุเดียวกันถูกใช้จากหลายเธรด
BlueRaja - Danny Pflughoeft

3
@KristofferL: ดูความคิดเห็นด้านบนและดูคำตอบนี้ด้วย
BlueRaja - Danny Pflughoeft

66

นอกเหนือจากความเร็วและอินเทอร์เฟซที่มีประโยชน์มากขึ้นแล้ว ( NextDouble()ฯลฯ ) ยังสามารถสร้างลำดับสุ่มซ้ำได้โดยใช้ค่าเมล็ดพันธุ์คงที่ ซึ่งมีประโยชน์มากในระหว่างการทดสอบ

Random gen1 = new Random();     // auto seeded by the clock
Random gen2 = new Random(0);    // Next(10) always yields 7,8,7,5,2,....

2
และมีค่า BitConverter ToInt32 (Byte [], int startIndex) ซึ่งอาจเข้าใจง่ายกว่า ;)
sisve

7
Ian Bell และ David Braben ใช้เครื่องกำเนิดไฟฟ้าแบบสุ่มในเกมคอมพิวเตอร์ Elite เพื่อสร้างรายชื่อดาวเคราะห์และคุณลักษณะต่างๆมากมาย (ขนาด ฯลฯ ) โดยมีหน่วยความจำที่ จำกัด มาก นอกจากนี้ยังอาศัยเครื่องกำเนิดไฟฟ้าที่สร้างรูปแบบการกำหนด (จากเมล็ดพันธุ์) ซึ่งเห็นได้ชัดว่า Crypto ไม่มีให้ (โดยการออกแบบ) มีข้อมูลเพิ่มเติมเกี่ยวกับวิธีการที่พวกเขาทำที่นี่: wiki.alioth.net/index.php / Random_number_generator และหนังสือ "Infinite Game Universe: Mathematical Techniques" ISBN: 1584500581 มีการอภิปรายทั่วไปเกี่ยวกับเทคนิคดังกล่าว
Daniel James Bryars


2
@phoog "ด้วยเหตุนี้รหัสแอปพลิเคชันของคุณจึงไม่ควรคิดว่าเมล็ดพันธุ์เดียวกันจะส่งผลให้เกิดลำดับสุ่มหลอกเหมือนกันใน. NET Framework เวอร์ชันต่างๆ" - ฉันไม่รู้ดูเหมือนจะชัดเจนสำหรับฉัน อย่างไรก็ตามฉันจะไม่แปลกใจถ้าพวกเขาไม่สามารถเปลี่ยนแปลงได้ในทางปฏิบัติโดยไม่ทำลายโปรแกรมที่มีอยู่แม้จะมีคำเตือนนี้
Roman Starkov

2
@phoog: คุณกำลังพูดสิ่งหนึ่งแล้วตรงข้ามกับมัน คุณกำลังขัดแย้งกับตัวเองโดยตรง
Timwi

54

ก่อนอื่นการนำเสนอที่คุณเชื่อมโยงจะพูดถึงตัวเลขสุ่มเพื่อความปลอดภัยเท่านั้น ดังนั้นจึงไม่อ้างว่าRandomไม่ดีสำหรับวัตถุประสงค์ด้านความปลอดภัย

แต่ฉันอ้างว่ามันเป็น การใช้งาน. net 4 Randomมีข้อบกพร่องหลายประการ ฉันขอแนะนำให้ใช้เฉพาะในกรณีที่คุณไม่สนใจคุณภาพของตัวเลขสุ่มของคุณ ฉันขอแนะนำให้ใช้การใช้งานของบุคคลที่สามที่ดีกว่า

ข้อบกพร่อง 1: การเพาะเมล็ด

ตัวสร้างเริ่มต้นเริ่มต้นด้วยเวลาปัจจุบัน ดังนั้นอินสแตนซ์ทั้งหมดที่Randomสร้างด้วยตัวสร้างเริ่มต้นภายในกรอบเวลาสั้น ๆ (ประมาณ 10ms) จะส่งคืนลำดับเดียวกัน เอกสารนี้จัดทำเป็นเอกสารและ "ตามการออกแบบ" นี่เป็นเรื่องที่น่ารำคาญอย่างยิ่งหากคุณต้องการใช้หลายเธรดโค้ดของคุณเนื่องจากคุณไม่สามารถสร้างอินสแตนซ์ของRandomการทำงานของเธรดแต่ละชุดได้

วิธีแก้ปัญหาคือต้องระมัดระวังเป็นพิเศษเมื่อใช้ตัวสร้างเริ่มต้นและเริ่มต้นด้วยตนเองเมื่อจำเป็น

ปัญหาอีกประการหนึ่งคือเนื้อที่เมล็ดค่อนข้างเล็ก (31 บิต) ดังนั้นหากคุณสร้างอินสแตนซ์ 50k Randomด้วยเมล็ดสุ่มที่สมบูรณ์แบบคุณอาจจะได้รับหมายเลขสุ่มหนึ่งลำดับสองครั้ง (เนื่องจากความขัดแย้งของวันเกิด ) ดังนั้นการเพาะเมล็ดด้วยตนเองจึงไม่ใช่เรื่องง่ายเช่นกัน

ข้อบกพร่อง 2: การแจกแจงของตัวเลขสุ่มที่ส่งคืนโดยNext(int maxValue)มีความเอนเอียง

มีพารามิเตอร์ที่Next(int maxValue)ไม่สม่ำเสมออย่างชัดเจน ตัวอย่างเช่นถ้าคุณคำนวณr.Next(1431655765) % 2คุณจะได้0ตัวอย่างประมาณ 2/3 ของตัวอย่าง (โค้ดตัวอย่างท้ายคำตอบ)

ข้อบกพร่อง 3: NextBytes()วิธีนี้ไม่มีประสิทธิภาพ

ต้นทุนต่อไบต์ของ NextBytes()Next()เป็นเรื่องที่ใหญ่เป็นค่าใช้จ่ายในการสร้างตัวอย่างเต็มรูปแบบกับจำนวนเต็ม จากนี้ฉันสงสัยว่าพวกเขาสร้างหนึ่งตัวอย่างต่อไบต์

การนำไปใช้งานที่ดีขึ้นโดยใช้ 3 ไบต์จากแต่ละตัวอย่างจะเร็วNextBytes()ขึ้นเกือบเป็นปัจจัย 3

ขอบคุณข้อบกพร่องนี้ Random.NextBytes()นี้เร็วกว่าSystem.Security.Cryptography.RNGCryptoServiceProvider.GetBytesเครื่องของฉันประมาณ 25% (Win7, Core i3 2600MHz)

ฉันแน่ใจว่ามีใครตรวจสอบรหัสไบต์ต้นทาง / ถอดรหัสแล้วพวกเขาจะพบข้อบกพร่องมากกว่าที่ฉันพบจากการวิเคราะห์กล่องดำของฉัน


ตัวอย่างโค้ด

r.Next(0x55555555) % 2 มีความลำเอียงอย่างมาก:

Random r = new Random();
const int mod = 2;
int[] hist = new int[mod];
for(int i = 0; i < 10000000; i++)
{
    int num = r.Next(0x55555555);
    int num2 = num % 2;
    hist[num2]++;
}
for(int i=0;i<mod;i++)
    Console.WriteLine(hist[i]);

ประสิทธิภาพ:

byte[] bytes=new byte[8*1024];
var cr=new System.Security.Cryptography.RNGCryptoServiceProvider();
Random r=new Random();

// Random.NextBytes
for(int i=0;i<100000;i++)
{
    r.NextBytes(bytes);
}

//One sample per byte
for(int i=0;i<100000;i++)
{   
    for(int j=0;j<bytes.Length;j++)
      bytes[j]=(byte)r.Next();
}

//One sample per 3 bytes
for(int i=0;i<100000;i++)
{
    for(int j=0;j+2<bytes.Length;j+=3)
    {
        int num=r.Next();
        bytes[j+2]=(byte)(num>>16);   
        bytes[j+1]=(byte)(num>>8);
        bytes[j]=(byte)num;
    }
    //Yes I know I'm not handling the last few bytes, but that won't have a noticeable impact on performance
}

//Crypto
for(int i=0;i<100000;i++)
{
    cr.GetBytes(bytes);
}

1
น่าสนใจสามารถยืนยันการค้นพบของคุณ: บนเครื่องของฉัน Next (1431655765) ยังให้ 2/3 กับการเพาะใด ๆ 1431655765 วิเศษอะไร คุณมาถึงหมายเลขนี้ได้อย่างไร?
citykid

1
@citykid ดูที่ตัวเลขเป็นฐานสิบหกหรือบิต เวทมนตร์เกิดขึ้นจากวิธีที่น่าสงสัยที่Randomใช้ในการแปลงจำนวนเต็ม 31 บิตให้เป็นตัวเลขที่มีขอบเขตบนที่ระบุ ฉันลืมรายละเอียด randomValue * max / 2^{31}แต่มันเป็นสิ่งที่ชอบ
CodesInChaos

1431655765_10 = 1010101010101010101010101010101_2
Tim S.

6
หืม. คุณแนะนำให้ใช้ Random สำหรับ C # แบบใด?
Arsen Zahray

1
วัวศักดิ์สิทธิ์ความไม่สม่ำเสมอของการกระจายตัวของNext()คุณที่นี่เป็นข้อผิดพลาดที่น่าทึ่งมากและยังคงมีอยู่ในปัจจุบัน 6 ปีหลังจากที่คุณเขียนการค้นพบครั้งแรก (ฉันพูดว่า "จุดบกพร่อง" แทนที่จะเป็นเพียง "ข้อบกพร่อง" เนื่องจากเอกสารอ้างว่า"หมายเลขสุ่มหลอกถูกเลือกโดยมีความน่าจะเป็นเท่ากันจากชุดตัวเลขที่ จำกัด "ไม่เป็นเช่นนั้นและรหัสของคุณที่นี่พิสูจน์ได้)
Mark Amery

24

System.Random มีประสิทธิภาพมากกว่าเนื่องจากไม่สร้างตัวเลขสุ่มที่ปลอดภัยในการเข้ารหัส

การทดสอบง่ายๆบนเครื่องของฉันเติมบัฟเฟอร์ 4 ไบต์พร้อมข้อมูลสุ่ม 1,000,000 ครั้งใช้เวลา 49 ms สำหรับ Random แต่ 2845 ms สำหรับ RNGCryptoServiceProvider โปรดทราบว่าหากคุณเพิ่มขนาดของบัฟเฟอร์ที่คุณกำลังเติมความแตกต่างจะแคบลงเนื่องจากค่าใช้จ่ายสำหรับ RNGCryptoServiceProvider มีความเกี่ยวข้องน้อยกว่า


2
ขอบคุณสำหรับการสาธิตด้วยการทดสอบจริง
Lernkurve

3
คุณอาจคิดว่านี่เป็นเรื่องที่รุนแรง แต่ -1 สำหรับการโพสต์ผลลัพธ์ของเกณฑ์มาตรฐานประสิทธิภาพโดยไม่รวมรหัสของเกณฑ์มาตรฐาน แม้ว่าลักษณะการทำงานของRandomและRNGCryptoServiceProviderไม่ได้เปลี่ยนแปลงในช่วง 8 ปีที่ผ่านมา (ซึ่งสำหรับทุกสิ่งที่ฉันรู้ว่าพวกเขาอาจจะมี) ฉันได้เห็นการวัดประสิทธิภาพที่เสียหายอย่างสมบูรณ์เพียงพอที่ใช้กับ Stack Overflow ไม่ให้เชื่อถือผลลัพธ์ของเกณฑ์มาตรฐานที่มีรหัส ไม่เปิดเผยต่อสาธารณะ
Mark Amery

21

เหตุผลที่ชัดเจนที่สุดได้ถูกกล่าวถึงไปแล้วดังนั้นนี่คือเหตุผลที่คลุมเครือมากขึ้น: โดยทั่วไปแล้ว PRNG ที่เข้ารหัสจะต้องได้รับการแก้ไขซ้ำอย่างต่อเนื่องด้วยเอนโทรปี "จริง" ดังนั้นหากคุณใช้ CPRNG บ่อยเกินไปคุณอาจทำให้พูลเอนโทรปีของระบบหมดลงได้ซึ่ง (ขึ้นอยู่กับการใช้ CPRNG) อาจทำให้มันลดลง (ทำให้ผู้โจมตีสามารถคาดเดาได้) หรือมันจะบล็อกขณะพยายามเติม เอนโทรปีพูลของมัน (จึงกลายเป็นเวกเตอร์การโจมตีสำหรับการโจมตี DoS)

ไม่ว่าจะด้วยวิธีใดแอปพลิเคชันของคุณได้กลายเป็นเวกเตอร์การโจมตีสำหรับแอปพลิเคชันอื่น ๆ ที่ไม่เกี่ยวข้องโดยสิ้นเชิงซึ่งแตกต่างจากของคุณโดยแท้จริงแล้วขึ้นอยู่กับคุณสมบัติการเข้ารหัสของ CPRNG

นี่เป็นปัญหาในโลกแห่งความเป็นจริง BTW ที่พบในเซิร์ฟเวอร์ headless (ซึ่งโดยปกติแล้วจะมีเอนโทรปีพูลค่อนข้างเล็กเนื่องจากไม่มีแหล่งเอนโทรปีเช่นอินพุตเมาส์และคีย์บอร์ด) ที่ใช้ Linux ซึ่งแอปพลิเคชันใช้/dev/randomเคอร์เนล CPRNG อย่างไม่ถูกต้องสำหรับทุกประเภท ของตัวเลขสุ่มในขณะที่พฤติกรรมที่ถูกต้องคือการอ่านค่าเมล็ดพันธุ์เล็ก ๆ/dev/urandomและใช้ค่านั้นในการเพาะเมล็ดPRNG ของตัวเอง


ฉันอ่านบทความ Wikipedia และแหล่งข้อมูลทางอินเทอร์เน็ตอื่น ๆ เกี่ยวกับการพร่องเอนโทรปีและเอนโทรปีและฉันไม่ค่อยเข้าใจ ฉันจะทำให้เอนโทรปีพูลหมดไปได้อย่างไรเมื่อตัวสร้างตัวเลขสุ่มถูกป้อนด้วยเวลาของระบบจำนวนไบต์ว่าง ฯลฯ คนอื่นจะใช้มันเป็นเวกเตอร์โจมตีเพื่อทำนายตัวเลขสุ่มได้อย่างไร? คุณสามารถยกตัวอย่างง่ายๆได้หรือไม่? บางทีการสนทนานี้อาจต้องออฟไลน์ en.wikipedia.org/wiki/Entropy_%28computing%29
Lernkurve

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

ฉันเข้าใจดีว่าหากมีเครื่องกำเนิดไฟฟ้าแบบสุ่มหลอกที่ป้อนด้วยเช่นเมล็ดพันธุ์ 32 บิตการโจมตีด้วยกำลังเดรัจฉานมักจะค่อนข้างง่าย แม้แต่เมล็ดพันธุ์ 64 บิตก็อาจถูกโจมตีในวันเกิดได้ เมื่อเมล็ดมีขนาดใหญ่กว่านั้นมากฉันก็ไม่ค่อยเห็นความเสี่ยง หากมีเครื่องกำเนิดไฟฟ้าแบบสุ่มซึ่งสำหรับแต่ละไบต์ของเอาต์พุตจะส่งผ่านสถานะ 128 บิตผ่านอัลกอริธึมการเข้ารหัสบล็อกจากนั้นส่งออก 8 บิตด้านล่างผู้โจมตีจะเป็นไปได้อย่างไรแม้จะมีจำนวนไบต์เอาต์พุตที่ต่อเนื่องกันก็สามารถอนุมานสถานะได้โดยไม่มีจุดอ่อนใน อัลกอริทึมการเข้ารหัสเอง?
supercat

11

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


9

สิ่งนี้ได้รับการกล่าวถึงในระยะยาว แต่ในที่สุดปัญหาของประสิทธิภาพเป็นข้อพิจารณารองเมื่อเลือก RNG มี RNG มากมายอยู่ที่นั่นและ Lehmer LCG กระป๋องที่ RNG ของระบบส่วนใหญ่ประกอบด้วยนั้นไม่ใช่สิ่งที่ดีที่สุดหรือไม่จำเป็นต้องเร็วที่สุดด้วยซ้ำ ในระบบเก่าและช้ามันเป็นการประนีประนอมที่ยอดเยี่ยม การประนีประนอมนั้นแทบไม่เคยมีความเกี่ยวข้องกันเลยในทุกวันนี้ สิ่งนี้ยังคงอยู่ในระบบปัจจุบันเป็นหลักเนื่องจาก A) สิ่งนั้นถูกสร้างขึ้นแล้วและไม่มีเหตุผลที่แท้จริงที่จะ "สร้างล้อใหม่" ในกรณีนี้และ B) สำหรับสิ่งที่คนจำนวนมากจะใช้มัน 'ดีพอแล้ว'.

ท้ายที่สุดแล้วการเลือก RNG จะลดลงตามอัตราส่วนความเสี่ยง / รางวัล ในบางแอปพลิเคชันเช่นวิดีโอเกมไม่มีความเสี่ยงใด ๆ Lehmer RNG นั้นเพียงพอมากกว่าและมีขนาดเล็กกระชับรวดเร็วเข้าใจดีและ 'อยู่ในกล่อง'

ตัวอย่างเช่นหากแอปพลิเคชันเป็นเกมโป๊กเกอร์ออนไลน์หรือลอตเตอรีที่มีรางวัลจริงเกี่ยวข้องและเงินจริงเข้ามามีบทบาทในสมการบางจุด 'ในกล่อง' Lehmer จะไม่เพียงพออีกต่อไป ในรุ่น 32 บิตมีเพียง 2 ^ 32 รัฐที่ถูกต้องไปได้ก่อนที่มันจะเริ่มรอบที่ดีที่สุด ทุกวันนี้นั่นเป็นประตูที่เปิดกว้างสำหรับการโจมตีด้วยกำลังดุร้าย ในกรณีเช่นนี้ผู้พัฒนาจะต้องการไปที่บางสิ่งบางอย่างเช่นช่วงเวลาที่ยาวนานมาก RNG ของบางสายพันธุ์และอาจเริ่มต้นจากผู้ให้บริการที่แข็งแกร่งในการเข้ารหัส สิ่งนี้ทำให้เกิดการประนีประนอมที่ดีระหว่างความเร็วและความปลอดภัย ในกรณีเช่นนี้บุคคลนั้นจะมองหาบางสิ่งเช่นMersenne Twisterหรือเครื่องกำเนิดซ้ำหลายๆ ชนิด

หากแอปพลิเคชันเป็นสิ่งที่ต้องการสื่อสารข้อมูลทางการเงินจำนวนมากผ่านเครือข่ายตอนนี้มีความเสี่ยงสูงและมีมากกว่ารางวัลที่เป็นไปได้ ยังคงมีรถหุ้มเกราะเพราะบางครั้งคนติดอาวุธหนักคือความปลอดภัยเพียงอย่างเดียวที่เพียงพอและเชื่อฉันเถอะถ้ากองพลพิเศษที่มีรถถังเครื่องบินรบและเฮลิคอปเตอร์มีความเป็นไปได้ทางการเงินก็จะเป็นวิธีการเลือก ในกรณีเช่นนี้การใช้ RNG ที่มีความแข็งแกร่งในการเข้ารหัสก็สมเหตุสมผลดีเพราะไม่ว่าคุณจะได้รับความปลอดภัยในระดับใดมันก็ไม่มากเท่าที่คุณต้องการ ดังนั้นคุณจะใช้เวลาให้มากที่สุดเท่าที่จะหาได้และค่าใช้จ่ายเป็นปัญหาอันดับสองที่ห่างไกลมากไม่ว่าจะเป็นเวลาหรือเงิน และถ้านั่นหมายความว่าทุกลำดับการสุ่มใช้เวลา 3 วินาทีในการสร้างบนคอมพิวเตอร์ที่ทรงพลังมากคุณจะต้องรอ 3 วินาที


3
ฉันคิดว่าคุณคิดผิดเกี่ยวกับขนาดของคุณ การส่งข้อมูลทางการเงินจะต้องรวดเร็วมาก หากอัลกอริทึมการซื้อขายของคุณสามารถเข้าถึงผลลัพธ์ได้เร็วกว่าคู่แข่ง 0.1 มิลลิวินาทีคุณจะได้รับคำสั่งซื้อ / ขาย / หยุดขาดทุน / ใบเสนอราคาที่ดีกว่า 3 วินาทีคือนิรันดร์ นี่คือเหตุผลที่เทรดเดอร์ลงทุนในคอมพิวเตอร์ที่ดีอย่างไม่น่าเชื่อ ดูคำตอบก่อนหน้านี้ Crypt.RNG ใช้เวลาเพียง 0,0028 ms ต่อหมายเลขใหม่ 0.0000028 วินาทีดังนั้นคุณจึงปิด 9 คำสั่งของขนาดในแง่ของการประมวลผลที่ต้องใช้และความเร็วนั้นสำคัญเพียงใด
Henrik

9

โปรดทราบว่าคลาส System.Random ใน C # ถูกเข้ารหัสอย่างไม่ถูกต้องดังนั้นควรหลีกเลี่ยง

https://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug#tabs


... และดูเหมือนจะไม่สามารถแก้ไขได้เลย
ผู้ใช้จ่าย

2
ดูเหมือนว่าลิงก์จะหยุดทำงานเนื่องจาก Microsoft ยกเลิกการ "เชื่อมต่อ"
MSeifert

4

ไม่ใช่ทุกคนที่ต้องการตัวเลขสุ่มที่ปลอดภัยในการเข้ารหัสและอาจได้รับประโยชน์มากขึ้นจาก prng ธรรมดาที่เร็วขึ้น ที่สำคัญกว่านั้นคือคุณสามารถควบคุมลำดับสำหรับหมายเลข System.Random

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


2

ถ้าฉันไม่ต้องการความปลอดภัยนั่นคือฉันแค่ต้องการค่าที่ค่อนข้างไม่แน่นอนไม่ใช่ค่าที่แข็งแกร่งในการเข้ารหัส Random มีอินเทอร์เฟซที่ใช้งานง่ายกว่ามาก


2

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


1
ถ้าเพียง System.Random ทำอย่างใดอย่างหนึ่ง .. โอ้ดี
user2864740

2

Random ไม่ใช่ตัวสร้างตัวเลขสุ่มมันเป็นตัวสร้างลำดับสุ่มหลอกที่กำหนดขึ้นซึ่งใช้ชื่อของมันด้วยเหตุผลทางประวัติศาสตร์

เหตุผลที่ต้องใช้ System.Randomคือถ้าคุณต้องการคุณสมบัติเหล่านี้คือลำดับดีเทอร์มินิสติกซึ่งรับประกันว่าจะให้ผลลัพธ์ลำดับเดียวกันเมื่อเริ่มต้นด้วยเมล็ดพันธุ์เดียวกัน

หากคุณต้องการปรับปรุง "การสุ่ม" โดยไม่ต้องเสียสละอินเทอร์เฟซคุณสามารถสืบทอดจากการSystem.Randomลบล้างวิธีการต่างๆ

ทำไมคุณถึงต้องการลำดับที่กำหนด

เหตุผลหนึ่งที่ต้องมีลำดับที่กำหนดมากกว่าการสุ่มที่แท้จริงเพราะมันทำซ้ำได้

ตัวอย่างเช่นหากคุณกำลังเรียกใช้การจำลองตัวเลขคุณสามารถเริ่มต้นลำดับด้วยตัวเลขสุ่ม (จริง) และบันทึกว่าใช้หมายเลขใด

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

ทำไมคุณถึงต้องการสิ่งนี้โดยเฉพาะลำดับที่ไม่ค่อยดีนัก

เหตุผลเดียวที่ฉันคิดได้คือเพื่อความเข้ากันได้แบบย้อนหลังกับโค้ดที่มีอยู่ซึ่งใช้คลาสนี้

ในระยะสั้นหากคุณต้องการปรับปรุงลำดับโดยไม่ต้องเปลี่ยนโค้ดที่เหลือให้ดำเนินการต่อ


1

ฉันเขียนเกม (Crystal Sliders บน iPhone: ที่นี่ ) ที่จะวางอัญมณี (ภาพ) แบบ "สุ่ม" ไว้บนแผนที่และคุณจะหมุนแผนที่ตามที่คุณต้องการและเลือกและพวกมันก็จากไป - คล้ายกับ Bejeweled ฉันใช้ Random () และมันถูกสร้างขึ้นด้วยจำนวน 100ns เห็บตั้งแต่โทรศัพท์บูทซึ่งเป็นเมล็ดสุ่มที่ค่อนข้างสวย

ฉันพบว่ามันน่าทึ่งมากที่มันสามารถสร้างเกมที่เกือบจะเหมือนกัน - จาก 90 อัญมณีหรือมากกว่านั้นจาก 2 สีฉันจะได้สองสีที่เหมือนกันทุกประการยกเว้น 1 ถึง 3 อัญมณี! หากคุณพลิก 90 เหรียญและได้รับรูปแบบเดียวกันยกเว้น 1-3 พลิกนั่นไม่น่าเป็นไปได้มาก! ฉันมีภาพหน้าจอหลายภาพที่แสดงเหมือนกัน ฉันตกใจมากที่ System.Random () แย่แค่ไหน! ฉันคิดว่าฉันต้องเขียนบางอย่างผิดอย่างน่ากลัวในรหัสของฉันและใช้มันผิด ฉันคิดผิดมันเป็นเครื่องกำเนิดไฟฟ้า

ในการทดลอง - และวิธีแก้ปัญหาสุดท้ายฉันกลับไปที่ตัวสร้างตัวเลขสุ่มที่ฉันใช้มาตั้งแต่ปี 2528 ซึ่งดีกว่ามาก เร็วกว่ามีระยะเวลา 1.3 * 10 ^ 154 (2 ^ 521) ก่อนที่จะเกิดซ้ำ อัลกอริทึมดั้งเดิมได้รับการเพาะเมล็ดด้วยหมายเลข 16 บิต แต่ฉันเปลี่ยนเป็นหมายเลข 32 บิตและปรับปรุงการเริ่มต้นเริ่มต้น

ต้นฉบับอยู่ที่นี่:

ftp://ftp.grnet.gr/pub/lang/algorithms/c/jpl-c/random.c

ในช่วงหลายปีที่ผ่านมาฉันได้ทำการทดสอบตัวเลขแบบสุ่มทุกครั้งที่ฉันคิดได้และมันก็ผ่านมาทั้งหมด ฉันไม่ได้คาดหวังว่ามันจะมีค่าใด ๆ เท่ากับการเข้ารหัส แต่จะส่งคืนตัวเลขเร็วพอ ๆ กับ "return * p ++;" จนกว่าจะหมด 521 บิตจากนั้นจะรันกระบวนการอย่างรวดเร็วบนบิตเพื่อสร้างใหม่แบบสุ่ม

ฉันสร้าง C # wrapper - เรียกมันว่า JPLRandom () ใช้อินเทอร์เฟซเดียวกับ Random () และเปลี่ยนตำแหน่งทั้งหมดที่ฉันเรียกมันในโค้ด

ความแตกต่างนั้นดีขึ้นอย่างมาก - OMG ฉันรู้สึกประหลาดใจ - ไม่น่าจะมีวิธีใดที่ฉันสามารถบอกได้จากการดูหน้าจอของอัญมณี 90 หรือมากกว่านั้นในรูปแบบ แต่ฉันได้เปิดตัวเกมในกรณีฉุกเฉินหลังจากนี้

และฉันจะไม่ใช้ System.Random () เพื่ออะไรอีกเลย ฉันตกใจที่เวอร์ชั่นของพวกเขาปลิวไปกับสิ่งที่ตอนนี้อายุ 30 ปี!

-Traderhut เกม


3
ฉันเดาอย่างแรกคือคุณสร้างใหม่Randomบ่อยเกินไป ควรสร้างขึ้นเมื่อเรียกNextอินสแตนซ์นั้นหลาย ๆ ครั้งเท่านั้น Randomไม่ดี แต่ไม่ได้ว่าไม่ดี คุณสามารถโพสต์โปรแกรมตัวอย่างพร้อมกับเมล็ดพันธุ์ที่มีปัญหานี้ได้หรือไม่?
CodesInChaos

รหัสจะสร้าง Random () ที่จุดเริ่มต้นของแต่ละระดับ (แต่มันเป็นปัญหาใหญ่กับระดับ 1 มากกว่าระดับที่ใหม่กว่า) โค้ดมีดังนี้:
Traderhut Games

Rnd = สุ่มใหม่ ((uint) GameSeed); NextGameSeed = Rnd.Next (2000000000); แต่ละระดับใช้การสุ่มใหม่ที่สร้างขึ้นด้วยเมล็ดพันธุ์ใหม่ - เมล็ดพันธุ์ได้รับการบันทึกไว้สำหรับแต่ละระดับดังนั้นฉันจะสามารถสร้างแผนที่ขึ้นใหม่ได้และยังยืนยันลำดับของเมล็ดแบบสุ่มที่ตรงกัน สิ่งนี้ช่วยให้ฉันยืนยันได้ว่าเกมนี้เป็นชุดแผนที่ที่ถูกต้องซึ่งได้รับการแก้ไขและสร้างเกมขึ้นใหม่
Traderhut Games

และเริ่มแรก Random ถูกสร้างขึ้นตาม System.DateTime.Now.Ticks (หรือ 0) จากนั้น GameSeed จะถูกเลือกโดยใช้การเรียกเดียวกันกับ Rnd.Next () ด้านบน ถ้าฉันทำไม่ได้แสดงว่ามีปัญหาร้ายแรงกับการเริ่มต้นของเครื่องสร้างตัวเลขสุ่ม
Traderhut Games

นี่ไม่ใช่คำตอบสำหรับคำถามเดิม!
Mike Dinescu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.