Генерация случайных приоритетов для трэпа в C ++ - PullRequest
1 голос
/ 02 мая 2019

Я создаю треп, и я хочу знать, какой генератор случайных чисел наиболее подходит для генерации приоритетов при вставке.

Длина набора данных составляет около 6000 единиц.

Я изменяю существующий класс шаблона (в основном только объявленные методы без определений), который был нам передан. Предопределенный генератор - std::default_random_engine, который генерирует только псевдослучайные числа. Я хотел бы знать, достаточно ли этого генератора, а если нет, каковы альтернативы? Данные будут прочитаны сразу из файла.

Генератор случайных чисел объявлен как:

std::default_random_engine* generator_;

Используется только при создании в конструкторе класса-оболочки

TreapItem<K, T>(key, data, (*generator_)())

Я бы хотел иметь как можно меньше коллизий. Достаточно ли std::default_random_engine* generator_;, чтобы избежать столкновений, или нужен какой-то другой генератор?

РЕДАКТИРОВАТЬ : Я бы предпочел равномерное распределение или что-то, что близко к нему. Однако нормальное распределение может также работать.

Указатель на генератор был в данном коде, на первый взгляд он не выглядел как недостаток.

1 Ответ

2 голосов
/ 03 мая 2019

Это простой (но не исчерпывающий!) Тест для генераторов случайных чисел c ++ плюс древняя функция C rand и простой генератор rot-xor.

Существует простой тест дыма, который занимает несколько битот середины числа, но ни в коем случае не крипто-доказательство.

Я думаю, что все они будут хорошо работать для рандомизированного бинарного дерева поиска.

#include <random>
#include <iostream>
#include <chrono>
#include <stdlib.h>

struct rot_xor {
  int32_t seed = 0x95abcfad;
  inline uint32_t operator() () {
    return seed = (seed << 1) ^ ((seed >> 31) & 0xa53a9be9);
  }
};

struct crand {
  int32_t seed = 0x95abcfad;
  inline uint32_t operator() () {
    return rand();
  }
};

template <class Generator>
void benchmark(std::vector<int> &histo) {
  Generator r;
  int mask = histo.size() - 1;
  for (int i = 0; i != 10000000; ++i) {
    uint32_t val = (uint32_t)r();
    histo[(val>>16) & mask]++;
  }
}

int main() {
  using std::chrono::high_resolution_clock;
  using std::chrono::duration_cast;
  using std::chrono::microseconds;

  for (int i = 0; i != 9; ++i) {
    std::vector<int> histo(0x100);
    auto t0 = high_resolution_clock::now();
    switch (i) {
      case 0: benchmark<std::minstd_rand0>(histo); break;
      case 1: benchmark<std::minstd_rand>(histo); break;
      case 2: benchmark<std::mt19937>(histo); break;
      case 3: benchmark<std::mt19937_64>(histo); break;
      case 4: benchmark<std::ranlux24_base>(histo); break;
      case 5: benchmark<std::ranlux48_base>(histo); break;
      case 6: benchmark<std::default_random_engine>(histo); break;
      case 7: benchmark<crand>(histo); break;
      case 8: benchmark<rot_xor>(histo); break;
    }
    auto t1 = high_resolution_clock::now();

    int min_histo = histo[0];
    int max_histo = histo[0];
    for (auto h : histo) {
      min_histo = std::min(min_histo, h);
      max_histo = std::max(max_histo, h);
    }
    std::cout << "test " << i << " took " << duration_cast<microseconds>(t1-t0).count() << "us\n";
    std::cout << " smoke test = " << min_histo << " .. " << max_histo << "\n";
  }
}

Результаты показывают удивительную производительность длядовольно сложные C ++ значения по умолчанию, только в 3-5 раз медленнее, чем простой RNG.Лучшим из стандартных, кажется, является вычитание с керри-версиями ranlux_ *.Старая функция C rand (), которая, я думаю, содержит делитель, неудивительно, что самая медленная.

test 0 took 58066us
 smoke test = 38486 .. 39685
test 1 took 39310us
 smoke test = 38533 .. 39604
test 2 took 26382us
 smoke test = 38503 .. 39591
test 3 took 29146us
 smoke test = 38591 .. 39670
test 4 took 27721us <- not bad, ranlux24
 smoke test = 38419 .. 39597
test 5 took 27310us
 smoke test = 38608 .. 39622
test 6 took 38629us
 smoke test = 38486 .. 39685
test 7 took 65377us
 smoke test = 38551 .. 39541
test 8 took 10984us <-- fastest (rot-xor)
 smoke test = 38656 .. 39710
...