Как создать огромное количество высококачественных случайных чисел?

Я работаю над моделированием случайных движений частиц, движущихся в решетке. По этой причине я должен создать огромное количество случайных чисел, около 10 ^ 12 и выше. В настоящее время я использую возможности, предоставляемые С++ 11 с помощью <random>. При профилировании моей программы я вижу, что в <random> проводится большое количество времени. Подавляющее большинство этих чисел составляет от 0 до 1, равномерно распределенных. Здесь a тогда мне нужно число из биномиального распределения. Но основное внимание уделяется номерам 0..1.

Вопрос: что я могу сделать, чтобы сократить время процессора, необходимое для генерации этих чисел, и каково влияние на их качество?

Как вы можете видеть, я пробовал разные двигатели, но это не оказало большого влияния на процессорное время. Далее, в чем разница между моими uniform01(gen) и generate_canonical<double,numeric_limits<double>::digits>(gen)?

Изменить: Прочитав ответы, я пришел к выводу, что для моей проблемы нет идеального решения. Таким образом, я решил сначала сделать свою программу многопоточными и запустить несколько RNG в разных потоках (засеянных одним номером random_device + индивидуальным приращением потока). В настоящее время эти швы являются наиболее неизбежным шагом (в любом случае потребуется многопоточность). В качестве еще одного шага, ожидающего рассмотрения точных требований, я перехожу к предлагаемому Intel RNG или Thrust. Это означает, что моя реализация RNG не должна быть сложной, и в настоящее время это не так. Но сейчас мне нравится фокусироваться на физической корректности моей модели, а не на программировании, это происходит, как только выход моей программы физически корректен. Thrust Относительно Intel RNG

Вот что я делаю сейчас:

class Generator {
public:
    Generator();
    virtual ~Generator();
    double rand01(); //random number [0,1)
    int binomial(int n, double p); //binomial distribution with n samples with probability p
private:
    std::random_device randev; //seed
    /*Engines*/
    std::mt19937_64 gen;
    //std::mt19937 gen;
    //std::default_random_engine gen;
    /*Distributions*/
    std::uniform_real_distribution<double> uniform01;
    std::binomial_distribution<> binomialdist;
};

Generator::Generator() : randev(), gen(randev()), uniform01(0.,1.), binomial(1,1.) {
}

Generator::~Generator() { }

double Generator::rand01() {
    //return uniform01(gen);
    return generate_canonical<double,numeric_limits<double>::digits>(gen);
}

int Generator::binomialdist(int n, double p) {
    binomial.param(binomial_distribution<>::param_type(n,p));
    return binomial(gen);
}

Ответ 1

Вы можете предварительно обработать случайные числа и использовать их, когда вам нужно.

Если вам нужны истинные случайные числа, я предлагаю вам использовать такую ​​услугу, как http://www.random.org/, которая обеспечивает случайные числа, вычисляемые окружающей средой, а не некоторый алгоритм.

И, говоря о случайных числах, вы также должны это проверить:

enter image description here

Ответ 2

Если вам нужно огромное количество случайных чисел, и я имею в виду MASSIVE, сделайте тщательный поиск в Интернете для генератора случайных чисел с плавающей запятой IBM, опубликованного, возможно, десять лет назад. Вам придется покупать либо машину PowerPC, либо новую машину Intel с плавным многократным добавлением. Они достигли случайных чисел со скоростью один за цикл на ядро. Поэтому, если вы купили новый Mac Pro, вы могли бы достичь, вероятно, 50 миллиардов случайных чисел в секунду.

Ответ 3

Возможно, вместо использования процессора вы можете использовать графический процессор для генерации множества чисел одновременно?

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch37.html

Ответ 4

На моем i3 следующая программа запускается примерно через пять секунд:

#include <random>
std::mt19937_64 foo;

double drand() {
  union {
    double d;
    long long l;
  } x;
  x.d = 1.0;
  x.l |= foo() & (1LL<<53)-1;
  return x.d-1;
}

int main() {
  double d;
  for (int i = 0; i < 1e9; i++)
    d += drand();
  printf("%g\n", d);
}

в то время как замена вызова drand() осуществляется с помощью следующих результатов в программе, которая работает примерно через десять секунд:

double drand2() {
  return std::generate_canonical<double,
      std::numeric_limits<double>::digits>(foo);
}

Использование следующего вместо drand() также приводит к программе, которая работает примерно через десять секунд:

std::uniform_real_distribution<double> uni;
double drand3() {
  return uni(foo);
}

Возможно, хакерский drand() выше подходит для ваших целей лучше, чем стандартные решения.

Ответ 5

Определение задачи

OP запрашивает ответ для

1. Скорость генерации - предполагая, что набор 10E+012 случайных чисел будет "массивным"

и

2. Качество генератора - со слабым предположением, что числа, равномерно распределенные по некоторому диапазону значений, также являются случайными

Тем не менее, есть больше кардинальных аспектов, которые необходимо решить и успешно решить для реальной системы:

A. Определите, должна ли ваша симуляция системы обеспечивать гарантию повторяемости последовательности случайных чисел для будущих повторных экспериментов.

Если это не так, повторные эксперименты с симулированным экспериментом будут давать в основном разные результаты, тогда процесс рандомизатора (или рандомизатор и рандомизированный селектор) не должен беспокоиться об их повторении -entrant, state-full mode of operation и будет намного проще реализовать.

B. Определите, на каком уровне вам нужно доказать качество случайности генерируемых случайных чисел (или должны быть созданы сгенерированные множества случайных чисел к некоторому конкретному закону статистической теории (некоторые известные синтетические распределения или по-настоящему случайные с предельной колмогоровской сложностью полученного набора случайных чисел)). Не нужно быть экспертом NSA, чтобы заявить, что числовые генераторы истинно-случайных последовательностей являются очень сложной проблемой и имеют вычислительные затраты, связанные с производством продуктов с высокой степенью хаотичности.

Гипер-хаотические и истинно-случайные последовательности являются вычислительно дорогостоящими. Использование генераторов с низкой или плохой случайностью не является вариантом для приложений, чувствительных к качеству случайности (независимо от того, что может сказать маркетинговая бумага, никакая система с MIL-STD или NSA никогда не будет пытаться использовать это скомпрометированное качество в окружающей среде, где результаты действительно имеют значение, так почему бы не согласиться на меньшее в научных симуляциях? Возможно, это не проблема, если вы не против пропустить так много "невидимых" состояний имитируемых явлений).

C. Проверьте, сколько случайных чисел ваша система моделирования должна "потреблять по [usec]" и является ли этот параметр требования к дизайну постоянным или может быть увеличен, потоковая, векторная, распределенная вычислительная инфраструктура на основе Grid/Cloud.

D. Требуется ли вашей симуляционной системе поддерживать глобальное или per-thread или perGrid/CloudNode индивидуальное управление доступом к пулам рандомизированных чисел в случае векторизации или Grid/Cloud основанную на вычислительной стратегии.

Подход к решению задачи

Самый быстрый [1] и лучший [2] решение с [A] и [B], а опции для [D] - предварительная генерация максимальной случайности (и оплачивать приемлемую стоимость [C] и [D] для контроля доступа и управления доступом для повторного чтения из пула, а не для повторного генерации).