Std:: piecewise_linear_distribution не работает в VS2012?

Я решил лучше узнать С++ 11 <random>, поэтому я написал такой код:

std::mt19937 gen(10);
std::piecewise_linear_distribution<> d(Range.begin(), Range.end(),
                                       RangeValues.begin());

std::map<int, unsigned int> hist;
for (int n = 0; ++n != iterations;)
    ++hist[std::round(d(gen))];

for (auto p : hist)
   std::cout << std::setw(2) << p.first << ": "
             << std::string(p.second/(iterations/200), '*') << '\n';

По какой-то причине std::random_device, похоже, не работает на Coliru, поэтому вместо этого я ввел пробное семя. Я предполагаю, что это UB, следовательно, IIRC сильно базируется на оборудовании, и почему он не поддерживается на Coliru (исправьте меня, если я ошибаюсь). На Ideone он действительно работает.

Затем я поместил его для запуска на VS2012, единственное отличие которого - это собственная реализация std::round:

return number < 0.0 ? std::ceil(number - 0.5) : std::floor(number + 0.5);

Он отлично работает на Coliru, но когда я компилирую и запускаю его на VS2012, выход просто неверен.

Любая идея, как исправить это, и что еще более важно, почему это происходит? Я делаю что-то замедленное, или VS2012 не умный здесь?

Ответ 1

Кажется, что это проблема с Visual Studio. Я пробовал программу ниже (адаптирован из OP), а результат, созданный GCC 4.7.2, Clang 3.2 и Intel 13.1.0, очень разумен, тогда как тот, который генерируется Visual CTP для Visual Studio, ноябрь 2012 года, полностью отличается.

Плотность вероятности кусочно-линейная и определяется массивами x и p следующим образом. Кусочно-линейная функция, соединяющая точки (x [i], p [i]) для я = 0,..., N (где N = x.size() - 1) построена. Тогда эта функция нормирована (деля ее на ее интеграл), чтобы получить плотность вероятности.

#include <iostream>
#include <iomanip>
#include <string>
#include <random>
#include <array>

int main() {

    std::mt19937 gen(10);

    std::array<double, 3> x = {{0, 20, 40}};
    std::array<double, 3> p = {{0,  1,  0}};
    std::piecewise_linear_distribution<> dist(x.begin(), x.end(), p.begin());

    std::array<int, 40> hist = {{0}};

    for (size_t i = 0; i < 200000; ++i)
        ++hist[static_cast<size_t>(dist(gen))];

    for (size_t n = 0; n < hist.size(); ++n)
        std::cout << std::setfill('0') << std::setw(2) << n << ' ' << 
          std::string(hist[n] / 200, '*') << std::endl;

    std::cout << "\nValues in interval [20, 21[ : " << hist[20] << std::endl;
}

В нашем примере полигональная функция соединяет (0, 0), (20, 1) и (40, 0). Следовательно, его форма представляет собой равнобедренный треугольник с основанием 40 и высотой 1, который дает площадь 20. Следовательно, плотность вероятности f соединяется (0, 0), (20, 1/20) и (40, 0). Отсюда следует, что в интервале [20, 21 [мы могли бы ожидать около f (20) * (21-20) = 1/20 * 1 = 1/20 результатов розыгрыша. Всего мы набираем 200 000 значений, и тогда мы можем ожидать около 10 000 точек в [20, 21 [.

GCC, Clang и Intel сообщают 9734 точки в [20, 21 [и отображают шаблон, который очень похож на равнобедренный треугольник:

00 *
01 ***
02 *****
03 ********
04 ***********
05 **************
06 ***************
07 ******************
08 ********************
09 ************************
10 **************************
11 ****************************
12 *******************************
13 *********************************
14 ***********************************
15 ***************************************
16 *****************************************
17 ******************************************
18 **********************************************
19 ************************************************
20 ************************************************
21 *********************************************
22 *******************************************
23 *****************************************
24 **************************************
25 ************************************
26 **********************************
27 ******************************
28 ****************************
29 **************************
30 ***********************
31 ********************
32 ******************
33 ****************
34 *************
35 ***********
36 *********
37 ******
38 ***
39 *

Values in interval [20, 21[ : 9734

К сожалению, Visual Studio Nov 2012 CTP дает следующее:

00 ********************************************** [truncated]
01 **********************************************
02 ***********************************
03 *****************************
04 **************************
05 ***********************
06 *********************
07 ********************
08 *******************
09 ******************
10 *****************
11 ****************
12 ***************
13 **************
14 **************
15 **************
16 *************
17 *************
18 *************
19 ************
20 ************
21 *************
22 *************
23 *************
24 *************
25 **************
26 ***************
27 ***************
28 ****************
29 *****************
30 ******************
31 *******************
32 *******************
33 *********************
34 ***********************
35 **************************
36 *****************************
37 ***********************************
38 **********************************************
39 ********************************************** [truncated]

Values in interval [20, 21[ : 2496

Примечания:

  • Я урезал вывод Visual Studio для лучшего отображения.
  • Лучшая оценка количества точек в [20, 21 [составляет 200 000 * (0,5 * (f (20) + f (21))) * (21-20) = 100 000 * (1/20 + 1/20 - 1/400) = 10 000 - 250 = 9750.