Вы можете попробовать использовать навигационную карту с распределением вероятностей. В отличие от обычных карт, NaviableMap определяет абсолютный порядок своих ключей. И если ключ отсутствует на карте, он может сказать вам, какой ключ ближе всего, или какой самый маленький ключ больше аргумента. Я использовал ceilingEntry
, который возвращает запись карты с наименьшим ключом, который больше или равен данному ключу.
Если вы используете TreeMap в качестве реализации NavigableMap, то поиск распределений со многими классами будет быстрее, поскольку он выполняет двоичный поиск, а не начинает с первого ключа, а затем проверяет каждый ключ по очереди.
Другим преимуществом NaviableMap является то, что вы получаете интересующий вас класс данных, а не индекс для другого массива или списка, что может сделать код чище.
В моем примере я использовал BigDecimals, поскольку я не особо люблю использовать числа с плавающей запятой, поскольку вы не можете указать необходимую точность. Но вы можете использовать поплавки, двойные или любые другие.
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.NavigableMap;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
String[] classes = {"A", "B", "C", "D"};
BigDecimal[] probabilities = createProbabilities(classes.length);
BigDecimal[] distribution = createDistribution(probabilities);
System.out.println("probabilities: "+Arrays.toString(probabilities));
System.out.println("distribution: "+Arrays.toString(distribution)+"\n");
NavigableMap<BigDecimal, String> map = new TreeMap<BigDecimal, String>();
for (int i = 0; i < distribution.length; i++) {
map.put(distribution[i], classes[i]);
}
BigDecimal d = new BigDecimal(Math.random());
System.out.println("probability: "+d);
System.out.println("result: "+map.ceilingEntry(d).getValue());
}
private static BigDecimal[] createDistribution(BigDecimal[] probabilities) {
BigDecimal[] distribution = new BigDecimal[probabilities.length];
distribution[0] = probabilities[0];
for (int i = 1; i < distribution.length; i++) {
distribution[i] = distribution[i-1].add(probabilities[i]);
}
return distribution;
}
private static BigDecimal[] createProbabilities(int n) {
BigDecimal[] probabilities = new BigDecimal[n];
for (int i = 0; i < probabilities.length; i++) {
probabilities[i] = F(i+1, n);
}
return probabilities;
}
private static BigDecimal F(int i, int n) {
// 6i(n-i) / (n3 - n)
BigDecimal j = new BigDecimal(i);
BigDecimal m = new BigDecimal(n);
BigDecimal six = new BigDecimal(6);
BigDecimal dividend = m.subtract(j).multiply(j).multiply(six);
BigDecimal divisor = m.pow(3).subtract(m);
return dividend.divide(divisor, 64, RoundingMode.HALF_UP);
}
}