Вопрос

Я боролся с этим весь день, пытаюсь получить генератор случайных чисел для потоков в моем коде CUDA.Я просмотрел все форумы и да, эта тема встречается довольно часто, но я потратил часы, пытаясь разгадать все виды кодов, но безрезультатно.Если кто-нибудь знает простой метод, возможно, устройство ядро, которое можно вызвать, чтобы вернуть случайное число с плавающей запятой от 0 до 1 или целое число, которое я могу преобразовать, я был бы очень благодарен.

Опять же, я надеюсь использовать случайное число в ядре, как, например, rand().

заранее спасибо

Это было полезно?

Решение

Я не уверен, что понимаю, зачем вам что-то особенное.Любой традиционный PRNG должен переноситься более или менее напрямую.А линейный конгруэнтный должно работать нормально.Есть ли у вас какие-то особые свойства, которые вы пытаетесь создать?

Другие советы

Кому интересно, теперь вы можете сделать это через куранд.

Я думаю, что любое обсуждение этого вопроса должно отвечать на первоначальный запрос Зенны, и это для уровень потока выполнение.В частности функция устройства который можно вызвать изнутри ядро или поток.Извините, если я переусердствовал с фразами, выделенными жирным шрифтом, но я действительно думаю, что ответы пока не совсем соответствуют тому, что здесь ищут.

Библиотека cuRAND — ваш лучший выбор.Я понимаю, что люди хотят изобрести велосипед (это заставляет ценить и более правильно использовать сторонние библиотеки), но высокопроизводительных высококачественных генераторов чисел много и они хорошо протестированы.Лучшая информация, которую я могу порекомендовать, - это документация по библиотеке GSL для различных генераторов здесь:http://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html

Для любого серьезного кода лучше всего использовать один из основных алгоритмов, которые математики/компьютерщики постоянно используют в поисках системных недостатков.«Твистер Мерсенна» — это что-то с периодом (повторяющийся цикл) порядка 10 ^ 6000 (алгоритм MT19997 означает «Твистер Мерсенна 2 ^ 19997»), которое было специально адаптировано для Nvidia для использования на уровне потока внутри потоков та же деформация, использующая вызовы идентификаторов потоков в качестве семян.См. статью здесь:http://developer.download.nvidia.com/compute/cuda/2_2/sdk/website/projects/MersenneTwister/doc/MersenneTwister.pdf.На самом деле я работаю над кое-чем, используя эту библиотеку, и ЕСЛИ я заставлю ее работать правильно, я опубликую свой код.На сайте документации Nvidia есть несколько примеров текущего набора инструментов CUDA.

ПРИМЕЧАНИЕ:Для справки: я не работаю в Nvidia, но признаю, что их документация и абстракционный дизайн для CUDA до сих пор меня впечатлили.


В зависимости от вашего приложения вам следует с осторожностью использовать LCG, не учитывая, будут ли потоки (один поток на поток) перекрываться.Вы могли бы реализовать чехарду с помощью LCG, но тогда вам понадобится достаточно длительный период LCG, чтобы гарантировать, что последовательность не повторится.

Примером чехарды может быть:

template <typename ValueType>
__device__ void leapfrog(unsigned long &a, unsigned long &c, int leap)
{
    unsigned long an = a;
    for (int i = 1 ; i < leap ; i++)
        an *= a;
    c = c * ((an - 1) / (a - 1));
    a = an;
}

template <typename ValueType>
__device__ ValueType quickrand(unsigned long &seed, const unsigned long a, const unsigned long c)
{
    seed = seed * a;
    return seed;
}

template <typename ValueType>
__global__ void mykernel(
    unsigned long *d_seeds)
{
    // RNG parameters
    unsigned long a = 1664525L;
    unsigned long c = 1013904223L;
    unsigned long ainit = a;
    unsigned long cinit = c;
    unsigned long seed;

    // Generate local seed
    seed = d_seeds[bid];
    leapfrog<ValueType>(ainit, cinit, tid);
    quickrand<ValueType>(seed, ainit, cinit);
    leapfrog<ValueType>(a, c, blockDim.x);

    ...
}

Но тогда период этого генератора, вероятно, в большинстве случаев недостаточен.

Честно говоря, я бы посмотрел на использование сторонней библиотеки, такой как НАГ.В SDK также есть несколько пакетных генераторов, но в данном случае, вероятно, это не то, что вам нужно.

РЕДАКТИРОВАТЬ

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

Лучший способ для этого — написать свой собственный устройство функция, вот она

void RNG()
{   
    unsigned int m_w = 150;
    unsigned int m_z = 40;

    for(int i=0; i < 100; i++)
    {
        m_z = 36969 * (m_z & 65535) + (m_z >> 16);
        m_w = 18000 * (m_w & 65535) + (m_w >> 16);

        cout <<(m_z << 16) + m_w << endl;  /* 32-bit result */
    }
}

Это даст вам 100 случайных чисел с 32-битным результатом.

Если вам нужны случайные числа от 1 до 1000, вы также можете воспользоваться result%1000, либо в точке потребления, либо в точке генерации:

((m_z << 16) + m_w)%1000

Изменение начальных значений m_w и m_z (в примере 150 и 40) позволяет каждый раз получать разные результаты.Вы можете использовать threadIdx.x как один из них, который должен каждый раз давать вам разные псевдослучайные серии.

Хотел добавить, что она работает в 2 раза быстрее, чем функция rand(), и работает отлично ;)

Существует пакет MDGPU (GPL), который включает реализацию функции GNU rand48() для CUDA. здесь.

Я нашел его (довольно легко, с помощью Google, что, я полагаю, вы и пробовали :-) на форумах NVidia. здесь.

Я не нашел хорошего генератора параллельных чисел для CUDA, однако я нашел параллельный генератор случайных чисел, основанный на научных исследованиях, здесь: http://sprng.cs.fsu.edu/

Вы могли бы попробовать Mersenne Twister для графических процессоров

Он основан на SIMD-ориентированном Fast Mersenne Twister (SFMT), который является довольно быстрым и надежным генератором случайных чисел.Он проходит тесты Marsaglias DIEHARD для генераторов случайных чисел.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top