Дискретное распределение не симметрично

Я пытаюсь сэмплировать дискретное распределение, используя std::discrete_distribution функция. Вот мве:

// discrete_distribution
#include <iostream>
#include <random>

int main()
{
const int nrolls = 10000; // number of experiments
const int nstars = 100;   // maximum number of stars to distribute
std::vector<double> weights;
weights = {1.28503e-22, 1.67881e-17, 8.99861e-13, 1.70418e-08, 9.27031e-05,
0.106935, 16.1967, 140.325, 16.1967, 0.106935, 9.27031e-05, 1.70418e-08,
8.99861e-13, 1.67881e-17, 1.28503e-22};

std::default_random_engine generator;
std::discrete_distribution<int> distribution(weights.begin(), weights.end());

for (double x:distribution.probabilities()) std::cout << x << " ";
std::cout << std::endl;

int p[15]={};

for (int i=0; i<nrolls; ++i) {
int number = distribution(generator);
++p[number];
}

std::cout << "a discrete_distribution:" << std::endl;
for (int i=0; i<15; ++i)
std::cout << i << ": " << std::string(p[i]*nstars/nrolls,'*') << std::endl;

return 0;
}

это дает:

7.43082e-25 9.70789e-20 5.20354e-15 9.8546e-11 5.36065e-07
0.000618363 0.0936591 0.811444 0.0936591 0.000618363 5.36065e-07
9.85459e-11 5.10703e-15 0 0

a discrete_distribution:
0:
1:
2:
3:
4:
5:
6: *********
7: ********************************************************************************
8: *********
9:
10:
11:
12:
13:
14:

Обратите внимание на асимметрию, особенно нули в конце. Я не вижу, что я сделал не так. Что-то не так с кодом или происходит какое-то округление, которое я не вижу. Благодарю.

0

Решение

Проблема, кажется, математика с плавающей точкой. В частности, кажется вероятным, что распределение сохраняет промежуточный итог при нормализации его весов, что приводит к потере крошечной вероятности в конце. В простом примере предположим, что double может хранить только 2 значащие цифры (реальность ближе к 16), а ваши веса были 0,001, 1,0, 1,0 и 0,001:

Он суммирует весовые коэффициенты до 2,002 (которые он может представлять только как 2,00), а затем идет вперед и нормализует весовые коэффициенты. Первый становится 0,001 / 2,00 = 0,0005. Затем следующий равен 0,5, итоговое значение 0,5005 (то есть 5,00). Третий вес тоже 0,5, итого 1,00 уже. Разница с допустимой суммой составляет 0,00, поэтому она не может дать положительный вес последнему событию.

Я знаю, что это не идеальный пример (потому что весовые коэффициенты все еще не суммируются полностью), но я надеюсь, что вы поняли — ваша реализация стандартной библиотеки и / или ваши настройки с плавающей точкой портят ваши результаты из-за отмена. Не то чтобы ваше событие с вероятностью 1e-20 когда-либо происходило в пределах разумного, но вы правы в том, что теоретически оно должно сохранять симметрию.

Для тех, кто говорит «не хватило точности для печати»: я не согласен, потому что в идеале значения должны быть симметричными, а первое значение не печатается как 0, в отличие от последнего. Видеть как только эти значения, меньшие чем один ULP около 1, печатаются как ноль, я поддерживаю отмену как проблему.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]