JavaRush /Java Blog /Random-TL /Probability theory in practice o alam mo ba ang tungkol s...

Probability theory in practice o alam mo ba ang tungkol sa Random

Nai-publish sa grupo
Probability theory in practice o alam mo ba ang tungkol sa Random - 1

Panimula

Maraming mga agham sa mundo na nag-aaral ng teorya ng posibilidad. At ang mga agham ay binubuo ng iba't ibang mga seksyon. Halimbawa, sa matematika mayroong isang hiwalay na seksyon na nakatuon sa pag-aaral ng mga random na kaganapan, dami, atbp. Ngunit hindi basta-basta ang agham. Sa kasong ito, nagsimulang mabuo ang teorya ng probabilidad nang sinubukan ng mga tao na maunawaan kung anong mga pattern ang mayroon sa paghagis ng dice kapag naglalaro ng pagkakataon. Kung titingnang mabuti, maraming mga tila random na bagay sa paligid natin. Ngunit ang lahat ng random ay hindi ganap na random. Ngunit higit pa sa na mamaya. Ang Java programming language ay mayroon ding suporta para sa mga random na numero, simula sa unang bersyon ng JDK. Maaaring gamitin ang mga random na numero sa Java gamit ang java.util.Random na klase . Para sa pagsubok, gagamitin namin ang tutorialspoint java online compiler . Narito ang isang primitive na halimbawa ng paggamit ng Random upang tularan ang paghagis ng "dice", o mga cube sa Russian:
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        Random rnd = new Random();
        int number = rnd.nextInt(6) + 1;
        System.out.println("Random number: " + number);
    }
}
Mukhang ito na ang katapusan ng paglalarawan ng Random , ngunit hindi ito ganoon kasimple. Buksan natin ang paglalarawan ng java.util.Random na klase sa Java API. At dito nakikita natin ang mga kawili-wiling bagay. Ang Random na klase ay gumagamit ng mga pseudo-random na numero. Paano kaya? Ito ay lumiliko na ang mga random na numero ay hindi gaanong random?
Probability theory in practice o alam mo ba ang Random - 2

Pseudo-randomness java.util.Random

Ang dokumentasyon para sa klase ng java.util.Random ay nagsasabi na kung ang mga instance ng Random ay ginawa gamit ang parehong parameter ng seed at ang parehong mga pagkakasunud-sunod ng mga aksyon ay ginanap sa mga pagkakataon, ibinabalik nila ang magkaparehong pagkakasunud-sunod ng mga numero. At kung titingnan nating mabuti, makikita natin na ang Random ay talagang mayroong isang constructor na tumatagal ng ilang mahabang halaga bilang isang binhi:
Random rnd1 = new Random(1L);
Random rnd2 = new Random(1L);
boolean test = rnd1.nextInt(6) == rnd2.nextInt(6);
System.out.println("Test: " + test);
Ang halimbawang ito ay babalik ng totoo dahil ang binhi ng parehong mga pagkakataon ay pareho. Anong gagawin? Ang default na tagabuo ay bahagyang nalulutas ang problema. Nasa ibaba ang isang halimbawa ng mga nilalaman ng Random constructor :
public Random() {
	this(seedUniquifier() ^ System.nanoTime());
}
Ang default na tagabuo ay gumagamit ng bitwise na eksklusibong OR na operasyon . At gumagamit ng mahabang kumakatawan sa kasalukuyang oras at ilang binhi para dito :
private static long seedUniquifier() {
	for (;;) {
		long current = seedUniquifier.get();
		long next = current * 181783497276652981L;
		if (seedUniquifier.compareAndSet(current, next))
			return next;
	}
}
Ang isa pang kawili-wiling bagay dito ay ang bawat tawag sa seedUniquifier getter method ay nagbabago sa halaga ng seedUniquifier . Iyon ay, ang klase ay idinisenyo upang pumili ng mga random na numero nang mahusay hangga't maaari. Gayunpaman, tulad ng sinasabi ng dokumentasyon, sila ay "hindi ligtas sa cryptographically ". Iyon ay, para sa ilang layunin ng paggamit para sa cryptographic na layunin (pagbuo ng password, atbp.) hindi ito angkop, dahil hinuhulaan ang pagkakasunod-sunod na may wastong diskarte. May mga halimbawa sa paksang ito sa Internet, halimbawa dito: " Predicting the next Math.random() in Java ". O halimbawa ang source code dito: " Vulnerability Weak Crypto ". Ang java.util.Random (random number generator) ay may isang tiyak na "shortcut", iyon ay , isang pinaikling bersyon ng tawag na isinasagawa sa pamamagitan ng Math.random:
public static void main(String []args){
	int random_number = 1 + (int) (Math.random() * 6);
	System.out.println("Value: " + random_number);
}
Ngunit kung titingnan mong mabuti, ang parehong Random ay nasa loob:
public static double random() {
	return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
	static final Random randomNumberGenerator = new Random();
}
Ang JavaDoc ay nagpapayo sa paggamit ng SecureRandom class para sa isang " cryptographically secure pseudo-random number generator ".
Probability theory in practice o alam mo ba ang tungkol sa Random - 3

Secure Random Java

Ang SecureRandom class ay isang subclass ng java.util.Random at matatagpuan sa java.security package . Ang paghahambing ng dalawang klase na ito ay mababasa sa artikulong " Pagkakaiba sa pagitan ng java.util.Random at java.security.SecureRandom ". Bakit napakahusay ng SecureRandom na ito? Ang katotohanan ay para sa kanya ang pinagmulan ng mga random na numero ay tulad ng isang mahiwagang-tunog na bagay bilang ang "core entropy pool". Ito ay parehong plus at minus. Mababasa mo ang tungkol sa mga disadvantages nito sa artikulong: “ The dangers of java.security.SecureRandom ”. Sa madaling salita, ang Linux ay may kernel random number generator (RNG). Bumubuo ang RNG ng mga random na numero batay sa data mula sa entropy pool, na pinupunan batay sa mga random na kaganapan sa system, tulad ng mga timing ng keyboard at disk, paggalaw ng mouse, mga interrupt, at trapiko sa network. Ang higit pang impormasyon tungkol sa entropy pool ay inilarawan sa materyal na " Mga random na numero sa Linux (RNG) o kung paano "punan" /dev/random at /dev/urandom ". Sa mga Windows system, ginagamit ang SHA1PRNG, na ipinatupad sa sun.security.provider.SecureRandom. Sa pag-unlad ng Java, nagbago din ang SecureRandom, na sulit na basahin sa pagsusuri na " Mga update ng Java SecureRandom noong Abril 2016 " para sa isang kumpletong larawan.
Probability theory in practice o alam mo ba ang tungkol sa Random - 4

Multithreading o maging tulad ni Caesar

Kung titingnan mo ang code ng Random class , tila walang nagpapahiwatig ng problema. Ang mga pamamaraan ay hindi namarkahang naka-synchronize . Ngunit may isang PERO: kapag gumagawa ng Random na may default na constructor sa ilang mga thread, ibabahagi namin ang parehong instance seed sa pagitan nila , kung saan ang Random ay gagawin . At kapag may natanggap na bagong random na numero, nagbabago rin ang panloob na AtomicLong ng instance . Sa isang banda, walang mali dito mula sa lohikal na pananaw, dahil... Ginagamit ang AtomicLong . Sa kabilang banda, kailangan mong bayaran ang lahat, kabilang ang pagiging produktibo. At para din dito. Samakatuwid, kahit na ang opisyal na dokumentasyon para sa java.util.Random ay nagsasabing: " Ang mga pagkakataon ng java.util.Random ay threadsafe. Gayunpaman, ang sabay-sabay na paggamit ng parehong java.util.Random na instance sa mga thread ay maaaring makatagpo ng pagtatalo at kahihinatnang hindi magandang pagganap. Isaalang-alang sa halip ay gumagamit ng ThreadLocalRandom sa mga multithreaded na disenyo ". Iyon ay, sa mga multi-threaded na application kapag aktibong gumagamit ng Random mula sa ilang mga thread, mas mainam na gamitin ang ThreadLocalRandom class . Ang paggamit nito ay bahagyang naiiba sa karaniwang Random :
public static void main(String []args){
	int rand = ThreadLocalRandom.current().nextInt(1,7);
	System.out.println("Value: " + rand);
}
Gaya ng nakikita mo, hindi kami nagsasaad ng binhi para dito . Ang halimbawang ito ay inilarawan sa opisyal na tutorial mula sa Oracle: Concurrent Random Numbers . Maaari mong basahin ang higit pa tungkol sa klase na ito sa pagsusuri: " Gabay sa ThreadLocalRandom sa Java ".
Probability theory in practice o alam mo ba ang tungkol sa Random - 5

StreamAPI at Random

Sa paglabas ng Java 8, marami kaming bagong feature. Kasama ang Stream API. At naapektuhan din ng mga pagbabago ang pagbuo ng mga Random na halaga. Halimbawa, ang Random na klase ay may mga bagong pamamaraan na nagbibigay-daan sa iyong makakuha ng Stream na may mga random na halaga tulad ng int, doubleo long. Halimbawa:
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        new Random().ints(10, 1, 7).forEach(n -> System.out.println(n));
    }
}
Mayroon ding bagong klase na SplittableRandom :
import java.util.SplittableRandom;

public class HelloWorld{
    public static void main(String []args){
        new SplittableRandom().ints(10, 1, 7).forEach(n -> System.out.println(n));
    }
}
Maaari kang magbasa nang higit pa tungkol sa pagkakaiba sa pagitan ng SplittableRandom at iba pang mga klase dito: " Iba't ibang paraan upang lumikha ng mga Random na numero sa Java ".

Konklusyon

Sa tingin ko ito ay nagkakahalaga ng pagguhit ng isang konklusyon. Kailangan mong maingat na basahin ang JavaDoc para sa mga klase na ginamit. Sa likod ng isang bagay na kasing simple sa unang tingin gaya ng Random ay may mga nuances na maaaring maglaro ng malupit na biro. #Viacheslav
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION