Если вы заинтересованы в использовании дистрибутива Zipfian (который часто используется при моделировании процессов из области науки или социальной сферы), вы должны сделать что-то вроде:
- Выберите ваш k (перекос) для распределения
- Предварительный расчет домена кумулятивного распределения (это всего лишь оптимизация)
- Генерация случайных значений для распределения путем нахождения ближайшего значения из домена
Пример кода:
List<int> domain = Enumerable.Range(0,1000); // generate your domain
double skew = 0.37; // select a skew appropriate to your domain
double sigma = domain.Aggregate(0.0d, (z,x) => x + 1.0 / Math.Pow(z+1, skew));
List<double> cummDist = domain.Select(
x => domain.Aggregate(0.0d, (z,y) => z + 1.0/Math.Pow(y, skew) * sigma));
Теперь вы можете генерировать случайные значения, выбирая ближайшее значение из домена:
Random rand = new Random();
double seek = rand.NextDouble();
int searchIndex = cummDist.BinarySearch(seek);
// return the index of the closest value from the distribution domain
return searchIndex < 0 ? (~searchIndex)-1 : searchIndex-1;
Конечно, вы можете обобщить весь этот процесс, выделив логику, которая материализует область распределения, из процесса, который отображает и возвращает значение из этой области.