Има ли хубав начин да получите произволно генерирани цели числа с нормално разпределение?
Първият метод, който ми идва наум:
int rndi = (int)Math.floor(random.nextGaussian()*std);
Има ли по-добър начин?
Има ли хубав начин да получите произволно генерирани цели числа с нормално разпределение?
Първият метод, който ми идва наум:
int rndi = (int)Math.floor(random.nextGaussian()*std);
Има ли по-добър начин?
Трябва да актуализирате въпроса, за да изясните какъв точно е вашият случай на употреба.
Според вашия коментар изобщо не трябва да използвате нормално разпределение. Вместо това опитайте едно от многото дискретни разпределения, тъй като искате цели числа в края. Има много от тях, но бих препоръчал един - много прост. Той използва стохастичен вектор като дискретно вероятностно разпределение.
Ето примерна реализация:
public class DiscreteRandom {
private final double[] probDist;
public DiscreteRandom(double... probs) {
this.probDist = makeDistribution(probs);
}
private double[] makeDistribution(double[] probs) {
double[] distribution = new double[probs.length];
double sum = 0;
for (int i = 0; i < probs.length; i++) {
sum += probs[i];
distribution[i] = sum;
}
return distribution;
}
public int nextInt() {
double rand = Math.random();
int i = 0;
while (rand > probDist[i]) i++;
return i;
}
/**
* Simple test
*/
public static void main(String[] args) {
// We want 0 to come 3 times more often than 1.
// The implementation requires normalized probability
// distribution thus testProbs elements sum up to 1.0d.
double[] testProbs = {0.75d, 0.25d};
DiscreteRandom randGen = new DiscreteRandom(testProbs);
// Loop 1000 times, we expect:
// sum0 ~ 750
// sum1 ~ 250
int sum0 = 0, sum1 = 0, rand;
for (int i = 0; i < 1000; i++) {
rand = randGen.nextInt();
if (rand == 0) sum0++;
else sum1++;
}
System.out.println("sum0 = " + sum0 + "sum1 = " + sum1);
}
}
Строго погледнато, не можете да имате нормално разпределени цели числа. Може би това, което искате, е изходът от нормално разпределение, сортиран в кофи. В такъв случай вероятно искате да изместите и мащабирате нормалното си разпределение според размера на вашия масив. Ако просто вземете проби от стандартно нормално разпределение (средно = 0 и мащаб = 1), ще получите проби между -2 и 2 около 99% от времето.
Да предположим, че искате произволни извадки от масив с размер N. Искате записите в средата да се избират по-често от извадките в края, но искате извадките близо до краищата да се появяват от време на време, да речем 1% от времето . Тогава може да поискате да изчислите нещо като N/2 + N*z/4, където z е вашата стандартна норма, след което преобразувайте тези числа в цяло число. Ако направите това, понякога ще получавате индекс извън вашия масив. Просто тествайте за това и получете нова стойност, когато това се случи.
Това зависи от това какво се опитвате да направите с тези произволни числа.
java.util.Random
има някои недостатъци. Както е посочено в JavaDoc, методът nextGaussian()
използва Box Muller Transform. Зависи от Random.nextDouble()
, който се реализира с помощта на линеен конгруентен генератор. И изпълнението не е най-доброто, както е посочено в предложение за корекция на грешки:
Методът на Sun използва 48-битово начално число и (що се отнася до долния бит) има достъп само до 17 бита от това - което води до изключително сериозна неслучайност.
Така че, ако се интересувате от високо статистическо качество, наистина трябва да избягвате внедряването на Sun. Разгледайте този "Не толкова случаен" аплет за визуално доказателство колко е лошо .
Ако статистическото качество ви притеснява, най-доброто, което можете да направите, е да използвате външна PRNG библиотека.
java.util.Random
осигурява приемливи резултати за много приложения. en.wikipedia.org/wiki/Linear_congruential_generator
- person trashgod; 19.07.2010
Можете предварително да изчислите списък от „случайни“ цели числа, след което ръчно да промените този списък, за да получите разпределението, което искате.
След това, когато искате "произволен" номер, просто издърпайте следващия наличен от списъка...
По този начин гарантирате разпределението и следователно вероятността определен артикул да бъде избран. За забавление можете просто да „разбъркате“ списъка си, когато имате нужда.