Зашифровать число с плавающей запятой? - PullRequest
4 голосов
/ 01 июня 2011

Мне нужна повторяемая псевдослучайная функция от чисел с плавающей точкой в ​​[0,1] до чисел с плавающей точкой в ​​[0,1]. То есть с учетом 32-разрядного числа с плавающей запятой IEEE вернуть «другой» (как можно более случайный, учитывая 24 бита мантиссы). Это должно быть повторяемым, поэтому сохранение тонны внутреннего состояния отсутствует. И, к сожалению, он должен работать только с 32-битной математикой типа int и single-float (без двойных и даже 32x32 = 64-битных умножений, хотя я мог бы эмулировать это при необходимости - в основном он должен работать на старом оборудовании CUDA). Конечно, чем лучше случайность, тем лучше в пределах этих довольно жестких ограничений. У кого-нибудь есть идеи?

(Я прошел через Парк-Миллера, который требует 64-битной математики, и CUDA-версию Парк-Миллера, которая требует двойников, Мерсенна Твистерса, который имеет много внутреннего состояния, и некоторых других вещей, которые не ' т работы.)

Ответы [ 3 ]

3 голосов
/ 01 июня 2011

NVIDIA CUDA Toolkit включает в себя библиотеку под названием CURAND , которая, как я считаю, соответствует вашим требованиям: она дает воспроизводимые результаты (при условии, что вы начинаете с того же начального числа), работает на графическом процессоре, поддерживает 32-разрядные операции с плавающей запятой ии должен работать на старых графических процессорах.Он также поддерживает множественные псевдослучайные и квазислучайные алгоритмы и распределения.

[Примечание: проблема с использованием функции rand () библиотеки C (кроме того, что она не запускается в CUDA на устройстве) заключается в том, что в Windows rand () возвращает только 16-битное значение,и, таким образом, любое число с плавающей точкой, созданное делением на RAND_MAX, имеет только 16 случайных битов точности.Более того, в linux / mac он возвращает 32-битное значение, поэтому код, использующий его, не является числовым переносимым.]

3 голосов
/ 02 июня 2011

Лучше всего я понимаю требования, хеш выполняет желаемую функциональность. Повторно интерпретируйте входные данные с плавающей точкой как целое число, примените хеш-функцию, чтобы получить целое число, приблизительно равномерно распределенное в [0,2 ^ 32), затем умножьте это целое число на 2 ^ -32, чтобы преобразовать полученное целое число обратно в число с плавающей точкой примерно равномерно распределяется в [0,1]. Одна подходящая хеш-функция, которая не требует умножения, - это микс Боба Дженкина (), который можно найти здесь: http://www.burtleburtle.net/bob/hash/doobs.html.

Чтобы заново интерпретировать биты с плавающей точкой как целое число, и наоборот, в CUDA есть два варианта. Используйте встроенные функции или приведите реинтерпретацию в стиле C ++:

float f;
int i;
i = __float_as_int(f);
f = __int_as_float(i);
i = reinterpret_cast<int&>(f);
f = reinterpret_cast<float&>(i);

Таким образом, как отдельная функция, весь процесс может выглядеть примерно так:

/* transform float in [0,1] into a different float in [0,1] */
float scramble_float (float f)
{
    unsigned int magic1 = 0x96f563ae; /* number of your choice */
    unsigned int magic2 = 0xb93c7563; /* number of your choice */
    unsigned int j;
    j = reinterpret_cast<unsigned int &>(f);
    mix (magic1, magic2, j);
    return 2.3283064365386963e-10f * j;
}
2 голосов
/ 01 июня 2011

Почему бы не использовать стандартную функцию библиотеки C rand() и разделить результат на RAND_MAX?

#include <stdlib.h>
float randf (void)
{
     return rand() / (float) RAND_MAX;
}
...