1. Nombor pseudorandom

Kadangkala pengaturcara menghadapi tugas yang kelihatan mudah: "pilih filem rawak daripada senarai tertentu", "pilih pemenang loteri", "kocok senarai main apabila pengguna menggoncang telefon pintarnya", "pilih nombor rawak untuk menyulitkan mesej" , dsb. Dalam setiap kes, pembangun bertanya soalan logik: bagaimana untuk mendapatkan nombor rawak?

Sebenarnya, mendapatkan nombor yang benar-benar rawak agak sukar dilakukan. Sebenarnya, adalah sangat sukar bahawa koprosesor matematik khas dibina ke dalam beberapa komputer untuk menjana nombor yang memenuhi semua keperluan untuk rawak sebenar.

Pengaturcara menghasilkan penyelesaian mereka sendiri: nombor pseudorandom . Nombor pseudorandom ialah sejenis urutan, yang nombornya kelihatan rawak. Walau bagaimanapun, dengan melakukan analisis yang teliti, pakar boleh mencari corak tertentu dalam urutan. Nombor sedemikian tidak sesuai untuk menyulitkan dokumen rahsia, tetapi ia cukup untuk mensimulasikan gulungan dadu dalam permainan.

Terdapat banyak algoritma untuk menghasilkan urutan nombor pseudorandom. Hampir kesemuanya menjana nombor rawak seterusnya berdasarkan nombor sebelumnya dan beberapa nombor pembantu tambahan.

Sebagai contoh, program ini akan memaparkan 1000nombor tidak berulang:

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

Dengan cara ini, kita tidak bercakap tentang nombor pseudorandom di sini. Kita bercakap tentang urutan nombor pseudorandom. Melihat kepada satu nombor, adalah mustahil untuk mengetahui sama ada ia rawak atau tidak.

Sesungguhnya, terdapat pelbagai cara untuk mendapatkan nombor rawak:

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

2.Math.random()

Di Java, Mathkelas mempunyai kaedah khas yang mengembalikan nombor rawak. Dan seperti yang anda mungkin rasa, kaedahnya dipanggil random. Secara umum, inilah yang kelihatan seperti untuk memanggil kaedah ini:

Math.random()

Kaedah ini tidak mengambil parameter dan mengembalikan nombor nyata pseudorandom dalam julat dari 0hingga 1. Nombor 1 itu sendiri tidak termasuk dalam julat.

Contoh:

Kod Output konsol
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

Tetapi bagaimana jika kaedah ini tidak cukup seperti yang anda perlukan? Katakan, anda ingin menulis program yang menyerupai menggolek dadu bermuka enam. Bagaimanakah anda mendapatkan integer rawak dalam julat 1..6, bukannya nombor nyata dalam julat 0..1?

Ia sebenarnya agak mudah.

Mula-mula, anda perlu memetakan julat [0, 1)ke [0, 6). Untuk melakukan ini, hanya darabkan hasil yang dikembalikan random()dengan 6. Sudah tentu, untuk mendapatkan integer, anda perlu membulatkan:

Kod Output konsol
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

Mengembalikan getRandomDieNumber()integer rawak dalam julat 0..5termasuk. Tetapi ia tidak akan menjadi nombor dalam set 1, 2, 3, 4, 5, 6. Ia akan menjadi nombor dalam set 0, 1, 2, 3, 4, 5.

Jika yang anda perlukan ialah nombor dalam set 1, 2, 3, 4, 5, 6, maka tambahkan satu pada nombor rawak:

Kod Output konsol
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

Sekarang itu sempurna!



3. Randomkelas

Java mempunyai Randomkelas khas yang merangkum urutan nombor pseudorandom. Anda boleh mencipta beberapa objek kelas Random. Setiap objek ini akan menjana urutan nombor pseudorandomnya sendiri.

Ini adalah kelas yang sangat menarik dengan banyak kaedah yang menarik. Mari kita mulakan dengan yang paling mudah.

double nextDouble()

Kaedah ini mengembalikan nombor nyata rawak dalam julat 0.0- 1.0. Ia sangat serupa dengan Math.random()kaedah. Dan tidak hairanlah, kerana Math.random()kaedah itu hanya memanggil nextDouble()kaedah pada Randomobjek.

float nextFloat()

Kaedah ini sangat serupa dengan nextDouble()kaedah, tetapi nombor rawak yang dikembalikan ialah a float. Ia juga terletak dalam julat 0.0- 1.0. Dan, seperti biasa di Jawa, julat tidak termasuk nombor itu 1.0sendiri.

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

int nextInt(int max)

Kaedah ini mengembalikan integer rawak dalam julat [0, max). 0termasuk dalam julat, tetapi maxtidak.

Dalam erti kata lain, jika anda ingin mendapatkan nombor rawak dalam set 1, 2, 3, 4, 5, 6, maka anda perlu menambah satu pada nombor rawak yang dikembalikan:

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

int nextInt()

Kaedah ini serupa dengan yang sebelumnya, tetapi ia tidak mengambil sebarang parameter. Jadi apakah julat untuk nilai pulangannya? Dari -2 billionkepada +2 billion.

Nah, lebih tepatnya, dari -2147483648hingga +2147483647.

long nextLong()

Kaedah ini serupa dengan nextInt()kaedah, tetapi nilai pulangan akan jatuh di suatu tempat dalam keseluruhan julat longs yang mungkin.

boolean nextBoolean()

Kaedah ini mengembalikan nilai rawak boolean: falseatau true. Ini sangat mudah apabila anda perlu mendapatkan jujukan panjang nilai boolean rawak.

void nextBytes(byte[] data)

Kaedah ini tidak mengembalikan apa-apa (kerana jenis pulangan ialah void). Sebaliknya, ia mengisi tatasusunan yang diluluskan dengan nilai rawak. Ini sangat berguna apabila anda memerlukan penimbal besar yang diisi dengan data rawak.

double nextGaussian()

Kaedah ini mengembalikan nombor nyata rawak dalam julat 0.0- 1.0. Walau bagaimanapun, bilangannya tidak diagihkan sama rata dalam julat ini. Sebaliknya, mereka mengikut taburan normal .

Nilai berhampiran pertengahan julat ( 0.5) akan berlaku lebih kerap daripada nilai di hujung julat.

Kelas rawak

Dalam kes kami, kemuncak pengagihan nilai adalah pada0.5