ฉันจะสร้างหมายเลข int สุ่มได้อย่างไร


คำตอบ:


2501

Randomระดับใช้ในการสร้างตัวเลขสุ่ม (สุ่มหลอกว่าเป็นของหลักสูตร.)

ตัวอย่าง:

Random rnd = new Random();
int month  = rnd.Next(1, 13);  // creates a number between 1 and 12
int dice   = rnd.Next(1, 7);   // creates a number between 1 and 6
int card   = rnd.Next(52);     // creates a number between 0 and 51

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


184
เพียงบันทึกสำหรับผู้ใช้ Unity C # คุณต้องระบุ "System.Random ()" เป็น Unity มี "UnityEngine.Random ()" ซึ่งขัดแย้งกัน (โปรดทราบว่า "UnityEngine.Random ()" ไม่มีความสามารถในการสร้างแบบสุ่ม ตัวเลข) เนื่องจากความเป็นเอกภาพไม่ได้นำเข้าระบบเป็นค่าเริ่มต้นเสมอซึ่งอาจทำให้เกิดความสับสนได้
Joehot200

2
เพื่อนำมาใช้ซ้ำคุณสามารถประกาศrndเป็นstaticและ / หรือตั้งค่าเพียงครั้งเดียวเมื่อเริ่มต้นรหัส
Junior Mayhé

4
@JuniorM: ใช่คุณสามารถทำให้เป็นแบบคงที่เพื่อนำมาใช้ใหม่ได้ แต่คุณต้องระวังเพื่อที่คุณจะไม่สามารถเข้าถึงได้จากหลาย ๆ เธรดเนื่องจากมันไม่ปลอดภัยสำหรับเธรด (ตามปกติสำหรับชั้นเรียนใด ๆ ที่ไม่ได้สร้างหัวข้อปลอดภัยโดยเฉพาะ )
Guffa

8
ฉันคิดว่ามันจะมีประโยชน์ในการเพิ่มข้อจำกัดความรับผิดชอบที่ไม่ปลอดภัยด้วยการเข้ารหัสเพราะนี่เป็นคำถามยอดนิยมในกรณีที่มีคนพยายามทำการเข้ารหัสด้วยสุ่มสี่สุ่มห้าRandom...
Daniel García Rubio

1
คำตอบที่ยอดเยี่ยม มี "การปรับปรุง" ที่ดีบางอย่างRandomเพื่อทำให้การสุ่มของคุณมีประสิทธิภาพมากขึ้น: ericlippert.com/2019/02/04/fixing-random-part-2และcodeblog.jonskeet.uk/2009/11/04/revisiting -randomness
Jesse C. Slicer

280

คำถามดูง่ายมาก แต่คำตอบนั้นซับซ้อนเล็กน้อย หากคุณเห็นเกือบทุกคนแนะนำให้ใช้คลาส Random และบางคนแนะนำให้ใช้คลาส Crypto RNG แต่เมื่อไหร่จะเลือกอะไร

เพื่อที่เราจะต้องเข้าใจคำว่า RANDOMNESS และปรัชญาที่อยู่เบื้องหลัง

ฉันอยากจะแนะนำให้คุณดูวิดีโอนี้ซึ่งลึกลงไปในปรัชญาของ RANDOMNESS โดยใช้ C # https://www.youtube.com/watch?v=tCYxc-2-3fY

สิ่งแรกให้เราเข้าใจปรัชญาของความสุ่ม เมื่อเราบอกคนให้เลือกระหว่างสีแดงสีเขียวและสีเหลืองสิ่งที่เกิดขึ้นภายใน อะไรทำให้คนเลือกแดงหรือเหลืองหรือเขียว

c # สุ่ม

ความคิดเริ่มต้นบางอย่างเข้ามาในใจของคนที่ตัดสินใจเลือกของเขามันอาจเป็นสีที่ชื่นชอบสีที่โชคดีและอื่น ๆ กล่าวอีกนัยหนึ่งบางอย่างเริ่มต้นที่เราเรียกในสุ่มเป็น SEED นี่คือจุดเริ่มต้นเรียกที่กระตุ้นให้เขาเลือกค่า RANDOM

ตอนนี้ถ้าเมล็ดเป็นเรื่องง่ายที่จะคาดเดาแล้วชนิดของการสุ่มตัวเลขเหล่านี้จะเรียกว่าเป็นเทียมและเมื่อเมล็ดเป็นเรื่องยากที่จะคาดเดาตัวเลขสุ่มเหล่านี้จะเรียกว่า ที่ปลอดภัยตัวเลขสุ่ม

ตัวอย่างเช่นคนที่เลือกเป็นสีขึ้นอยู่กับสภาพอากาศและการรวมกันของเสียงแล้วมันจะเป็นการยากที่จะเดาเมล็ดเริ่มต้น

c # สุ่ม

ตอนนี้ให้ฉันทำคำสั่งที่สำคัญ: -

* คลาส“ Random” สร้างเฉพาะหมายเลขสุ่ม PSEUDO และเพื่อสร้างหมายเลขสุ่มที่ปลอดภัยเราต้องใช้คลาส“ RNGCryptoServiceProvider”

c # สุ่ม

คลาสสุ่มรับค่าเมล็ดจากนาฬิกา CPU ของคุณซึ่งสามารถคาดการณ์ได้อย่างมาก ดังนั้นในคำอื่น ๆ คลาส RANDOM ของ C # สร้างตัวเลขสุ่มหลอกด้านล่างเป็นรหัสสำหรับเดียวกัน

** หมายเหตุ: ** .NET Core 2.0.0+ใช้เมล็ดพันธุ์ที่แตกต่างกันใน constructor parameterless: แทนนาฬิกา CPU Guid.NewGuid().GetHashCode()จะใช้

var random = new Random();
int randomnumber = random.Next()

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

using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider()) 
{ 
    byte[] rno = new byte[5];    
    rg.GetBytes(rno);    
    int randomvalue = BitConverter.ToInt32(rno, 0); 
}

หากต้องการทำความเข้าใจกับเอนโทรปีของระบบปฏิบัติการโปรดดูวิดีโอนี้จาก 14:30 https://www.youtube.com/watch?v=tCYxc-2-3fYซึ่งอธิบายตรรกะของเอนโทรปีของระบบปฏิบัติการ ดังนั้นการใส่คำง่ายๆ RNG Crypto จึงสร้างตัวเลขสุ่มที่ปลอดภัย


9
ไม่ควรเป็นไบต์ [5] เพียง [4] ของคุณเป็น ToInt32 แยกวิเคราะห์เพียง 4 ไบต์หรือไม่
Bernhard

6
เป็นประโยชน์เสมอที่จะทราบว่าคลาสเหล่านี้อยู่ที่ใด System.Security.Cryptography
Elton

1
ขอแนะนำให้ใช้RandomNumberGenerator.Create()แทนการเรียกตัวสร้างRNGCryptoServiceProviderเพราะมันไม่สามารถใช้ได้กับแพลตฟอร์มทั้งหมด
dzitkowskik

ฉันต้องการเพียงแค่ให้แม่นยำว่า SecureRandom IS หลอกสุ่มสร้าง
Nùménor

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

231

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

//Function to get random number
private static readonly Random getrandom = new Random();

public static int GetRandomNumber(int min, int max)
{
    lock(getrandom) // synchronize
    {
        return getrandom.Next(min, max);
    }
}

3
นี่ไม่ใช่สิ่งที่ @Guffa พูดในคำตอบของเขา 6 เดือนที่ผ่านมาหรือ "ถ้าคุณสร้างอินสแตนซ์ใหม่ในเวลาใกล้เกินไปพวกเขาจะสร้างหมายเลขสุ่มชุดเดียวกัน"
Chris

3
@ Chris- ถูกต้องสิ่งที่คุณพูด ในที่นี้ฉันได้ให้การดำเนินการที่ ฉันคิดว่ามันเป็นวิธีที่ดีในการทำมัน มันทำงานได้ดีขึ้น
Pankaj Mishra

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

@SeanWorle: ก่อนอื่นฉันลองด้วยวิธีการจาก Guffa จากนั้นฉันพยายามเก็บRandomวัตถุเดียวกัน ในทั้งสองกรณีฉันได้รับหมายเลขสุ่มเหมือนกัน ด้วยวิธีการจาก Pankaj มันไม่ได้เกิดขึ้น บางทีนี่อาจเป็นการสุ่มแต่ฉันสงสัยในตอนนี้ ฉันกำลังสอบถามหมายเลขสุ่มในวินาทีเดียวกันจากกระทู้ที่แตกต่างกัน
ทดสอบ

1
@ การทดสอบ: ฉันยอมรับว่าวิธีการของ Pankaj นั้นเป็นวิธีที่ถูกต้องที่จะใช้ สิ่งที่ฉันกำลังพูดคือมันสามารถทำให้สิ่งนี้ง่ายขึ้น: // ฟังก์ชันเพื่อรับหมายเลขสุ่มส่วนตัวแบบคงที่อ่านอย่างสุ่ม getrandom = new Random (); สาธารณะคงที่ int GetRandomNumber (int ขั้นต่ำสูงสุด int) {ล็อค (getrandom) {// ประสานผลตอบแทน getrandom.Next (ต่ำสุดสูงสุด); }}
Sean Worle

92

ระวังให้ดี new Random() seeded บนเวลาปัจจุบัน

หากคุณต้องการสร้างเพียงหมายเลขเดียวคุณสามารถใช้:

new Random().Next( int.MinValue, int.MaxValue )

สำหรับข้อมูลเพิ่มเติมให้ดูที่คลาสRandomแต่โปรดทราบว่า:

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

ดังนั้นอย่าใช้รหัสนี้เพื่อสร้างชุดหมายเลขสุ่ม


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

21
เฮ้นั่นไม่ยุติธรรมเลย คำถามคือวิธีสร้างหมายเลข int แบบสุ่ม ไม่มีการพูดถึงลูปหรือซีรีส์
Fyodor Soikin

26
ตกลงจุดยุติธรรม งด แม้ว่าฉันจะยังคงคิดว่าการไม่ใช้new Random()วงเป็นจุดสำคัญ
Bevan

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


30

ฉันต้องการเพิ่มรุ่นที่ปลอดภัยด้วยการเข้ารหัส:

RNGCryptoServiceProvider Class ( MSDNหรือdotnetperls )

มันใช้ IDisposable

using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
   byte[] randomNumber = new byte[4];//4 for int32
   rng.GetBytes(randomNumber);
   int value = BitConverter.ToInt32(randomNumber, 0);
}

15

คุณสามารถใช้วิธีการStaticRandomของ Jon Skeet ภายในไลบรารีคลาส MiscUtil ที่เขาสร้างขึ้นสำหรับตัวเลขสุ่มหลอก

using MiscUtil;
...

for (int i = 0; i < 100; 
    Console.WriteLine(StaticRandom.Next());

31
ฉันเพิ่งได้ดูซอร์สโค้ดและฟังก์ชั่นนี้ใช้เอนจินตัวเลขสุ่มตัวเดียวกันหนึ่งตัว "รวม" ใน C # แต่ให้แน่ใจว่าใช้ "แม่" เมล็ด "/" วัตถุแม่ "เดียวกันสำหรับการโทรทั้งหมด (ผมขอโทษที่ผมไม่ทราบว่า C # คำศัพท์ แต่จุดของฉันก็คือฟังก์ชั่นนี้ไม่ได้ทำให้ตัวเลขสุ่มที่ดีขึ้นกว่าใด ๆ ฟังก์ชั่นมาตรฐาน..)
แอนเดรี Rejbrand

5
มันเป็นไปไม่ได้สำหรับสิ่งใดที่จะ 'สุ่มอย่างแท้จริง' เนื่องจากมีปัจจัย จำกัด หรืออคติอยู่เสมอซึ่งรวมอยู่ในตัวตนของมัน คุณไม่ฟังอาจารย์ในชั้นเรียนวิทยาศาสตร์หรือไม่? ;-)
Phill Healey

สมมติว่าตามที่เขาคิดนี่เป็น 'สุ่มอย่างแท้จริง' ตามที่ได้รับ
มิตราบอย

ลิงก์เสีย นี่คือเหตุผลที่คุณรวมข้อมูลที่คุณพบในคำตอบของคุณ
vapcguy

13

ฉันได้ลองใช้วิธีแก้ไขปัญหาทั้งหมดนี้แล้วโดยไม่รวมคำตอบของ COBOL ... lol

วิธีแก้ปัญหาเหล่านี้ไม่ดีพอ ฉันต้องการ randoms อย่างรวดเร็วสำหรับ int loop และฉันได้รับค่าที่ซ้ำกันมากมายแม้ในช่วงที่กว้างมาก หลังจากตัดสินใจเลือกผลลัพธ์แบบสุ่มนานเกินไปฉันก็ตัดสินใจแก้ปัญหานี้ในที่สุด

มันคือทั้งหมดที่เกี่ยวกับเมล็ด

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

public int GenerateRandom(int min, int max)
{
    var seed = Convert.ToInt32(Regex.Match(Guid.NewGuid().ToString(), @"\d+").Value);
    return new Random(seed).Next(min, max);
}

อัปเดต : การสร้างไม่จำเป็นถ้าคุณสร้างอินสแตนซ์ของคลาสสุ่มหนึ่งครั้ง ดังนั้นจะเป็นการดีที่สุดถ้าสร้างคลาสสแตติกและเรียกใช้เมธอดนั้น

public static class IntUtil
{
   private static Random random;

   private static void Init()
   {
      if (random == null) random = new Random();
   }

   public static int Random(int min, int max)
   {
      Init();
      return random.Next(min, max);
   }
}

จากนั้นคุณสามารถใช้คลาสคงที่เช่นนี้ ..

for(var i = 0; i < 1000; i++)
{
   int randomNumber = IntUtil.Random(1,100);
   Console.WriteLine(randomNumber); 
}

ฉันยอมรับว่าฉันชอบวิธีนี้ดีกว่า


6
Guid ไม่ได้สุ่มมันไม่ใช่เมล็ดที่ดี GUID ไม่ได้รับประกันเกี่ยวกับการสุ่ม แต่รับประกันได้ว่ามีเอกลักษณ์ stackoverflow.com/questions/2621563/…
Magu

2
Guid เป็นเมล็ดพันธุ์ที่ดี ฉันใช้ตัวเลขใน Guid เท่านั้น ลองวิธีด้วยตัวคุณเอง ใส่มันไว้เป็นเวลานานสำหรับการวนซ้ำและดูผลลัพธ์ด้วยตัวคุณเอง
Proximo

1
อืมข้าคิดอย่างที่สอง .. เมล็ดไม่จำเป็นเลย กำลังอัปเดตคำตอบ
Proximo

1
จุดที่ดีในการปรับปรุง ฉันไม่เคยคิดที่จะทำให้มันเป็นสนามคงที่ด้วยวิธีนี้ทำงานได้ดีขึ้นและสะอาดขึ้น
JCisar

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

11

ตัวเลขที่สร้างโดย inbuilt Randomคลาส (System.Random) สร้างตัวเลขสุ่มหลอก

หากคุณต้องการตัวเลขสุ่มจริงที่ใกล้เคียงที่สุดที่เราจะได้คือ "secure Pseudo Random Generator" ซึ่งสามารถสร้างขึ้นได้โดยใช้คลาส Cryptographic ใน C # เช่น RNGCryptoServiceProviderเช่น

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


11

สร้างวัตถุสุ่ม

Random rand = new Random();

และใช้มัน

int randomNumber = rand.Next(min, max);

คุณไม่จำเป็นต้องเริ่มต้นnew Random()ทุกครั้งที่คุณต้องการหมายเลขสุ่มเริ่มต้นหนึ่งสุ่มแล้วใช้มันหลายครั้งเท่าที่คุณต้องการภายในวงหรืออะไรก็ตาม


5
new Random()ใช้เห็บปัจจุบันเป็นเมล็ด เมื่อคุณสร้างอินสแตนซ์หลายอินสแตนซ์ภายในมิลลิวินาทีเดียวกัน (ซึ่งตรงข้ามกับติ๊ก) คุณจะได้รับค่าเดิมที่ส่งคืน
Hans Ke ในวันที่

10
นี่มันแย่มาก DateTime.Now.Millisecond (ซึ่งแตกต่างจาก DateTime.Now.Ticks) คือตัวเลขระหว่าง 0 ถึง 999 หากคุณสร้างขึ้นใหม่หนึ่งรายการสำหรับแต่ละหมายเลขสุ่มคุณจะมีความเป็นไปได้เพียง 1,000 ข้อเท่านั้น
Oren Melzer

มี 24 คนที่คิดจะตอบคำถามนี้ ... ?
Enigmativity

10

ดัดแปลงคำตอบจากที่นี่

หากคุณเข้าถึง CPU ที่เข้ากันได้กับ Intel Secure Key คุณสามารถสร้างตัวเลขและสตริงแบบสุ่มโดยใช้ไลบรารีเหล่านี้: https://github.com/JebteK/RdRandและhttps://www.rdrand.com/

เพียงดาวน์โหลดเวอร์ชันล่าสุดจากที่นี่รวม Jebtek.RdRand และเพิ่มคำสั่งที่ใช้สำหรับมัน จากนั้นสิ่งที่คุณต้องทำคือ:

// Check to see if this is a compatible CPU
bool isAvailable = RdRandom.GeneratorAvailable();

// Generate 10 random characters
string key       = RdRandom.GenerateKey(10);

 // Generate 64 random characters, useful for API keys 
string apiKey    = RdRandom.GenerateAPIKey();

// Generate an array of 10 random bytes
byte[] b         = RdRandom.GenerateBytes(10);

// Generate a random unsigned int
uint i           = RdRandom.GenerateUnsignedInt();

หากคุณไม่มีซีพียูที่ใช้งานร่วมกันได้เพื่อรันโค้ดบนเพียงแค่ใช้บริการ RESTful ที่ rdrand.com ด้วยไลบรารี wrapper RdRandom ที่รวมอยู่ในโครงการของคุณคุณจะต้องทำสิ่งนี้ (คุณจะได้รับ 1,000 การโทรฟรีเมื่อคุณสมัคร):

string ret = Randomizer.GenerateKey(<length>, "<key>");
uint ret   = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");

7

ฉันใช้โค้ดด้านล่างเพื่อมีหมายเลขสุ่ม (ไม่แนะนำ):

var random = new Random((int)DateTime.Now.Ticks);
var randomValue = random.Next(startValue, endValue + 1);

4

ในขณะนี้ก็โอเค:

Random random = new Random();
int randomNumber = random.Next()

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

Next()วิธีการรับสองพารามิเตอร์นาทีและแม็กซ์

ดังนั้นถ้าฉันต้องการให้เลขสุ่มอยู่ระหว่าง 5 ถึง 15 ฉันจะทำ

int randomNumber = random.Next(5, 16)

4

นี่คือคลาสที่ฉันใช้ ทำงานเหมือนRandomNumber.GenerateRandom(1, 666)

internal static class RandomNumber
{
    private static Random r = new Random();
    private static object l = new object();
    private static Random globalRandom = new Random();
    [ThreadStatic]
    private static Random localRandom;
    public static int GenerateNewRandom(int min, int max)
    {
        return new Random().Next(min, max);
    }
    public static int GenerateLockedRandom(int min, int max)
    {
        int result;
        lock (RandomNumber.l)
        {
            result = RandomNumber.r.Next(min, max);
        }
        return result;
    }
    public static int GenerateRandom(int min, int max)
    {
        Random random = RandomNumber.localRandom;
        if (random == null)
        {
            int seed;
            lock (RandomNumber.globalRandom)
            {
                seed = RandomNumber.globalRandom.Next();
            }
            random = (RandomNumber.localRandom = new Random(seed));
        }
        return random.Next(min, max);
    }
}

คลาส GenerateRandom ของคุณจะไม่ส่งคืนหมายเลข 666 เพียง 665 เท่านั้นนี่เป็นความเข้าใจผิดทั่วไป (คุณสมบัติ) ของค่า Random.Next สูงสุด
Gordon Bell

3

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

public class A
{
    public A()
    {
        var rnd=new Random();
        ID=rnd.Next();
    }
    public int ID { get; private set; }
}
public class B
{
    public B()
    {
        var rnd=new Random();
        ID=rnd.Next();
    }
    public int ID { get; private set; }
}

คุณคิดว่าคุณจะได้รับ ID ที่แตกต่างกันสองรายการหรือไม่? NOPE

class Program
{
    static void Main(string[] args)
    {
        A a=new A();
        B b=new B();

        int ida=a.ID, idb=b.ID;
        // ida = 1452879101
        // idb = 1452879101
    }
}

การแก้ปัญหาคือมักจะใช้เครื่องกำเนิดไฟฟ้าแบบสุ่มเดียวคง แบบนี้:

public static class Utils
{
    public static readonly Random random=new Random();
}

public class A
{
    public A()
    {
        ID=Utils.random.Next();
    }
    public int ID { get; private set; }
}
public class B
{
    public B()
    {
        ID=Utils.random.Next();
    }
    public int ID { get; private set; }
}

คุณเลือกเมล็ดอย่างปลอดภัยได้อย่างไร?
ja72

ก่อนอื่นถ้าวัตถุของคุณถูกสร้างขึ้นแยกกัน 10 ms ตัวเลขสุ่มที่สร้างจะแตกต่างกับเมล็ดเริ่มต้น ประการที่สองคุณสามารถบดข้อมูลสิ่งแวดล้อมแบบสุ่มหรือประมวลผลข้อมูลที่คุณมีอยู่รอบ ๆ เพื่อรับเมล็ด จากนั้นมีการแลกเปลี่ยนว่าคุณต้องการหมายเลขลำดับที่ยาวอย่างใดอย่างหนึ่งที่น่าจะเริ่มต้นทำซ้ำตัวเองหรือสตรีมหลายรายการแม้ว่าสตรีมสองสตรีมจะจบลงเหมือนกัน และถ้าคุณกังวลเรื่องความปลอดภัยRNGCryptoServiceProviderก็เป็นการโทรที่ดีกว่าอยู่ดี
Millie Smith

มันจะเจ๋งที่จะมีชิปสุ่มที่มีอนุภาคกัมมันตภาพรังสีแอลฟาขนาดเล็กและเครื่องตรวจจับ (เครื่องตรวจจับควันทำงาน) เพื่อสุ่มตัวเลขตามการสลายตัวของกัมมันตภาพรังสี (ซึ่งสุ่มมาก)
ja72

3

สำหรับเมล็ดพันธุ์แบบสุ่มที่แข็งแกร่งฉันมักจะใช้ CryptoRNG ไม่ใช่ Time

using System;
using System.Security.Cryptography;

public class Program
{
    public static void Main()
    {
        var random = new Random(GetSeed());
        Console.WriteLine(random.Next());
    }

    public static int GetSeed() 
    {
        using (var rng = new RNGCryptoServiceProvider())
        {
            var intBytes = new byte[4];
            rng.GetBytes(intBytes);
            return BitConverter.ToInt32(intBytes, 0);
        }
    }
}

3
Random random = new Random ();
int randomNumber = random.Next (lowerBound,upperBound);

1
ในขณะที่รหัสนี้อาจตอบคำถามได้ดีกว่าที่จะอธิบายวิธีการแก้ปัญหาและให้รหัสเป็นตัวอย่างหรือการอ้างอิง คำตอบที่ใช้รหัสเท่านั้นอาจทำให้สับสนและไม่มีบริบท
Robert Columbia

3

เช่นเดียวกับบันทึกสำหรับการอ้างอิงในอนาคต

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

คุณอาจอ้างถึงคำถามนี้ที่ฉันทำกลับมาได้สักพัก:

Microsoft เปลี่ยนเมล็ดเริ่มต้นแบบสุ่มหรือไม่

โดยพื้นฐานแล้วพวกเขาเปลี่ยนเมล็ดเริ่มต้นจากEnvironment.TickCountเป็นGuid.NewGuid().GetHashCode()ดังนั้นถ้าคุณสร้างสุ่ม 2 อินสแตนซ์จะไม่แสดงหมายเลขเดียวกัน

คุณสามารถดูไฟล์ได้จาก. NET Framework / .NET Core (2.0.0+) ที่นี่: https://github.com/dotnet/coreclr/pull/2192/commits/9f6a0b675e5ac0065a268554de49162c539ff66d

มันไม่ปลอดภัยเท่ากับ RNGCryptoServiceProvider แต่อย่างน้อยก็ไม่ได้ให้ผลลัพธ์ที่แปลก ๆ


นี่เป็นสิ่งที่ล้าสมัยแล้ว มีฟันเฟืองจำนวนมากเมื่อใช้ Guids Interop.GetRandomBytes((byte*)&result, sizeof(int));รหัสอยู่ในขณะนี้
Enigmativity

2

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

หากคุณต้องการตัวเลขสุ่มของแท้การสุ่มจะมาจากเสียงรบกวนจากบรรยากาศหรือการสลายตัวของกัมมันตภาพรังสี

คุณสามารถลองเช่น RANDOM.ORG (ลดประสิทธิภาพ)


2
Random rand = new Random();
int name = rand.Next()

ใส่ค่าใด ๆ ที่คุณต้องการในวงเล็บที่สองตรวจสอบให้แน่ใจว่าคุณได้ตั้งชื่อโดยการเขียน prop และแท็บสองครั้งเพื่อสร้างรหัส


1
เสาและแท็บสองครั้ง?
DCShannon

ทำไมต้องprop และ double tab ? ที่คุณพูดโดยไม่ต้องแป้นพิมพ์ลัดที่ซึ่งเป็นสั้นมือสำหรับทรัพย์สินรหัสของคุณจะไม่ทำงานหรือไม่
Sнаđошƒаӽ

2

หากคุณต้องการให้ CSRNG สร้างตัวเลขสุ่มระหว่างนาทีและสูงสุดนี่คือสิ่งที่คุณต้องการ มันจะเริ่มต้นRandomเรียนด้วยเมล็ดสุ่มที่ปลอดภัย

    class SecureRandom : Random
    {
        public static byte[] GetBytes(ulong length)
        {
            RNGCryptoServiceProvider RNG = new RNGCryptoServiceProvider();
            byte[] bytes = new byte[length];
            RNG.GetBytes(bytes);
            RNG.Dispose();
            return bytes;
        }
        public SecureRandom() : base(BitConverter.ToInt32(GetBytes(4), 0))
        {

        }
        public int GetRandomInt(int min, int max)
        {
            int treashold = max - min;
            if(treashold != Math.Abs(treashold))
            {
                throw new ArithmeticException("The minimum value can't exceed the maximum value!");
            }
            if (treashold == 0)
            {
                throw new ArithmeticException("The minimum value can't be the same as the maximum value!");
            }
            return min + (Next() % treashold);
        }
        public static int GetRandomIntStatic(int min, int max)
        {
            int treashold = max - min;
            if (treashold != Math.Abs(treashold))
            {
                throw new ArithmeticException("The minimum value can't exceed the maximum value!");
            }
            if(treashold == 0)
            {
                throw new ArithmeticException("The minimum value can't be the same as the maximum value!");
            }
            return min + (BitConverter.ToInt32(GetBytes(4), 0) % treashold);
        }
    }

1

ขออภัย OP ต้องการintค่าสุ่มแต่เพื่อจุดประสงค์ในการแบ่งปันความรู้หากคุณต้องการBigIntegerค่าสุ่มคุณสามารถใช้คำสั่งต่อไปนี้:

BigInteger randomVal = BigInteger.Abs(BigInteger.Parse(Guid.NewGuid().ToString().Replace("-",""), NumberStyles.AllowHexSpecifier));

0

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

int GetRandomNumber(int min, int max)
{
    Random rand = new Random((int)DateTime.Now.Ticks);
    return rand.Next(min, max);
}

หากคุณกำลังมองหาตัวสร้างตัวเลขแบบสุ่มสำหรับการแจกแจงแบบปกติคุณอาจใช้การแปลง Box-Muller ตรวจสอบคำตอบของ yoyoyoyosef ในคำถามสุ่มตัวแปรเกาส์เซียน เนื่องจากคุณต้องการจำนวนเต็มคุณต้องแปลงค่าเป็นจำนวนเต็มตอนท้าย

Random rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-rand.NextDouble(); //uniform(0,1] random doubles
double u2 = 1.0-rand.NextDouble();
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
         Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
double randNormal =
         mean + stdDev * randStdNormal; //random normal(mean,stdDev^2)

ตัวแปรสุ่มเกาส์


0

วิธีที่ง่ายที่สุดน่าจะเป็นเพียงแค่Random.range(1, 3)นี้จะสร้างตัวเลขระหว่าง 1 ถึง 2


-1

คุณสามารถลองกับค่าเมล็ดแบบสุ่มโดยใช้ด้านล่าง:

var rnd = new Random(11111111); //note: seed value is 11111111

string randomDigits = rnd.Next();

var requestNumber = $"SD-{randomDigits}";

ขอบคุณ @ MikaelDúiBolinderเพื่อดูตัวอย่างนี้
Rejwanul Reja

-2

ทำไมไม่ใช้int randomNumber = Random.Range(start_range, end_range)?


จริง ๆ แล้ว int randomNumber = Random.Range (start_range, end_range + 1)
Gordon Bell

3
มี Random.Range () หรือไม่ ฉันหามันไม่พบในเอกสาร MSDN
Phillip Ngan

ฉันไม่พบ Random.Range () ในเอกสาร MSDN ด้วย
user2455111

-2

ใช้หนึ่งตัวอย่างของการสุ่มซ้ำ ๆ

// Somewhat better code...
Random rng = new Random();
for (int i = 0; i < 100; i++)
{
    Console.WriteLine(GenerateDigit(rng));
}
...
static int GenerateDigit(Random rng)
{
    // Assume there'd be more logic here really
    return rng.Next(10);
}

บทความนี้จะดูว่าทำไมการสุ่มทำให้เกิดปัญหามากมายและวิธีการแก้ไข http://csharpindepth.com/Articles/Chapter12/Random.aspx


Randomไม่ใช่คลาสที่ปลอดภัยของเธรด หากคุณสร้างอินสแตนซ์เดียวคุณควร จำกัด การเข้าถึงไว้ข้างหลังกลไกการล็อค
แบรด M

-2

ลองขั้นตอนง่าย ๆ เหล่านี้เพื่อสร้างตัวเลขสุ่ม:

สร้างฟังก์ชั่น:

private int randomnumber(int min, int max)
{
    Random rnum = new Random();
    return rnum.Next(min, max);
}

ใช้ฟังก์ชั่นด้านบนในสถานที่ที่คุณต้องการใช้ตัวเลขสุ่ม สมมติว่าคุณต้องการใช้ในกล่องข้อความ

textBox1.Text = randomnumber(0, 999).ToString();

0 คือขั้นต่ำและ 999 คือสูงสุด คุณสามารถเปลี่ยนค่าเป็นสิ่งที่คุณต้องการ


นี้จะกลับหมายเลขเดียวกันเมื่อเรียกหลายครั้งใกล้ชิดร่วมกันที่จะใช้เวลาของระบบเป็นเมล็ดพันธุ์ ...
MOnsDaR

1
หมายเลขสุ่ม (0, 999) จะไม่ส่งคืนค่า 999 ค่าสูงสุดไม่รวม นี่เป็นความเข้าใจผิดทั่วไป (คุณสมบัติ) ของค่าสูงสุด Random.Next
Gordon Bell

-2

ฉันมักจะมีวิธีการที่จะสร้างตัวเลขสุ่มซึ่งช่วยในเรื่องต่างๆ ฉันหวังว่านี่อาจช่วยคุณได้เช่นกัน:

public class RandomGenerator  
{  
    public int RandomNumber(int min, int max)  
    {  
        var random = new Random();  
        return random.Next(min, max);  
    }  

    public string RandomString(int size, bool lowerCase)  
    {  
        var builder = new StringBuilder();  
        var random  = new Random();  
        char ch;  

        for (int i = 0; i < size; i++)  
        {  
            ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));  
            builder.Append(ch);  
        }  

        if (lowerCase)  
            return builder.ToString().ToLower();  
        return builder.ToString();  
    }  
}

-3

รวดเร็วและง่ายสำหรับการ inline ใช้รหัสร้อง:

new Random().Next(min, max);

// for example unique name
strName += "_" + new Random().Next(100, 999);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.