1. เลขสุ่มเทียม

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

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

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

มีอัลกอริธึมมากมายสำหรับสร้างลำดับของตัวเลขสุ่มเทียม เกือบทั้งหมดสร้างหมายเลขสุ่มถัดไปตามหมายเลขก่อนหน้าและหมายเลขตัวช่วยเพิ่มเติม

ตัวอย่างเช่น โปรแกรมนี้จะแสดง1000ตัวเลขที่ไม่ซ้ำ:

public class Main
{
   public static int a = 41;
   public static int c = 11119;
   public static int m = 11113;
   public static int seed = 1;

   public static int getNextRandom()
   {
     seed = (a * seed + c) % m;
     return seed;
   }

   public static void main(String[] args)
   {
     for (int i = 0; i < 1000; i++)
     {
       System.out.println(getNextRandom());
     }
   }
}

อย่างไรก็ตาม เราไม่ได้พูดถึงตัวเลขสุ่มเทียมที่นี่ เรากำลังพูดถึงลำดับของเลขสุ่มเทียม เมื่อดูที่ตัวเลขตัวเดียวไม่สามารถบอกได้ว่าเป็นแบบสุ่มหรือไม่

มีหลายวิธีในการรับหมายเลขสุ่ม:

public static int getRandomNumber()
{
   return 4; // Here's a random number (we got it by rolling a die)
}

2.Math.random()

ใน Java Mathคลาสมีเมธอดพิเศษที่ส่งคืนตัวเลขสุ่ม และอย่างที่คุณเดาได้ วิธีการนี้เรียกrandomว่า โดยทั่วไปแล้ว นี่คือลักษณะของการเรียกวิธีนี้:

Math.random()

วิธีนี้ไม่ใช้พารามิเตอร์และส่งกลับจำนวนจริงเทียมในช่วงจาก0ถึง 1หมายเลข 1 นั้นไม่รวมอยู่ในช่วง

ตัวอย่าง:

รหัส เอาต์พุตคอนโซล
public class Main
{
   public static void main(String[] args)
   {
     for (int i = 0; i < 10; i++)
     {
       System.out.println(Math.random());
     }
   }
}
0.9703753971734451
0.09979423801773157
0.994048474709053
0.2852203204171295
0.13551248551226025
0.3128547131272822
0.5342480554101412
0.6817369932044817
0.1840767788961758
0.06969563435451254

แต่ถ้าวิธีนี้ไม่ใช่สิ่งที่คุณต้องการล่ะ สมมติว่าคุณต้องการเขียนโปรแกรมจำลองการกลิ้งแม่พิมพ์หกด้าน คุณจะได้จำนวนเต็มสุ่มในช่วง 1..6 แทนที่จะเป็นจำนวนจริงในช่วง 0..1 ได้อย่างไร

มันค่อนข้างง่ายจริงๆ

ขั้น แรกคุณต้องแมปช่วง[0, 1)กับ ในการทำเช่น นี้[0, 6)เพียงคูณผลลัพธ์ที่ส่งกลับrandom()ด้วย 6แน่นอน ในการรับจำนวนเต็ม คุณต้องปัดขึ้น:

รหัส เอาต์พุตคอนโซล
public class Main
{
   public static int getRandomDieNumber()
   {
      return (int) (Math.random() * 6);
   }

   public static void main(String[] args)
   {
      for (int i = 0; i < 10; i++)
      {
         int x = getRandomDieNumber();
         System.out.println(x);
      }
   }
}
5
2
3
3
2
4
1
1
5
0

ส่งgetRandomDieNumber()กลับจำนวนเต็มสุ่มในช่วง0..5รวม 1, 2, 3, 4, 5, 6แต่จะ ไม่เป็นตัวเลขในชุด 0, 1, 2, 3, 4, 5มันจะเป็นตัวเลขในชุด

หากสิ่งที่คุณต้องการคือตัวเลขในชุด1, 2, 3, 4, 5, 6ให้เพิ่มหนึ่งตัวในตัวเลขสุ่ม:

รหัส เอาต์พุตคอนโซล
public class Main
{
   public static int getRandomDieNumber()
   {
      return (int) (Math.random() * 6) + 1;
   }

   public static void main(String[] args)
   {
     for (int i = 0; i < 10; i++)
     {
       int x = getRandomDieNumber();
       System.out.println(x);
     }
   }
}
3
2
1
3
6
5
6
1
6
6

ตอนนี้สมบูรณ์แบบแล้ว!



3. Randomชั้นเรียน

Java มีRandomคลาสพิเศษที่ห่อหุ้มลำดับของตัวเลขสุ่มเทียม คุณสามารถสร้างหลายวัตถุของRandomชั้นเรียน แต่ละวัตถุเหล่านี้จะสร้างลำดับของตัวเลขสุ่มเทียมขึ้นมาเอง

นี่เป็นคลาสที่น่าสนใจสุด ๆ ด้วยวิธีการที่น่าสนใจมากมาย เริ่มจากสิ่งที่ง่ายที่สุดกันก่อน

double nextDouble()

วิธี นี้จะส่งกลับจำนวนจริงแบบสุ่มในช่วง0.0- 1.0มันคล้ายกันมากกับMath.random()วิธีการ และไม่น่าแปลกใจเนื่องจากMath.random()เมธอดเรียกnextDouble()เมธอดบนRandomวัตถุ

float nextFloat()

วิธีนี้คล้ายกับnextDouble()วิธีนี้มาก แต่ตัวเลขสุ่มที่ส่งคืนคือfloata นอกจากนี้ ยังอยู่ในช่วง0.0- 1.0และเช่นเคยใน Java ช่วงจะไม่รวม1.0ตัวเลข

Random r = new Random();
float f = r.nextFloat();

int nextInt(int max)

วิธีนี้จะส่งกลับจำนวนเต็มแบบสุ่มในช่วง รวมอยู่ในช่วง แต่ไม่[0, max)0max

กล่าวอีกนัยหนึ่ง ถ้าคุณต้องการรับตัวเลขสุ่มในชุด1, 2, 3, 4, 5, 6คุณต้องเพิ่มหนึ่งตัวในตัวเลขสุ่มที่ส่งคืน:

Random r = new Random();
int x = r.nextInt(6) + 1;

int nextInt()

วิธีนี้คล้ายกับวิธีก่อนหน้า แต่ไม่ใช้พารามิเตอร์ใด ๆ ดังนั้นช่วงของค่าส่งคืนคืออะไร? จาก-2 billionถึง+2 billion.

เอาตรงๆ จาก-2147483648ถึง+2147483647.

long nextLong()

วิธีนี้คล้ายกับnextInt()เมธอด แต่ค่าที่ส่งคืนจะตกอยู่ในช่วงที่เป็นไปได้ทั้งหมดของlongs

boolean nextBoolean()

เมธอด นี้ส่งคืนค่าสุ่มboolean: falseหรือ trueวิธีนี้จะสะดวกมากเมื่อคุณต้องการรับค่าบูลีนแบบสุ่มที่มีลำดับยาว

void nextBytes(byte[] data)

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

double nextGaussian()

วิธี นี้จะส่งกลับจำนวนจริงแบบสุ่มในช่วง0.0- 1.0อย่างไรก็ตาม ตัวเลขจะไม่กระจายอย่างสม่ำเสมอในช่วงนี้ แต่จะเป็นไปตาม การแจกแจง แบบปกติ

ค่าใกล้กึ่งกลางของช่วง ( 0.5) จะเกิดขึ้นบ่อยกว่าค่าที่ปลายช่วง

คลาสสุ่ม

ในกรณีของเรา จุดสูงสุดของการกระจายมูลค่าจะอยู่ที่0.5