Функция random.uniform() в Python на C ?

#c #random #uniform

#c #Случайный #Униформа

Вопрос:

Я уже некоторое время ломаю голову над этими случайными числами в C .

В Python у меня была потрясающая:

 random.uniform(0, 1)
  

Который выдавал новое случайное число каждый раз, когда я его вызывал.

В C должно быть что-то подобное. Я долго гуглил и нашел erand48() , который я планирую внедрить в свой raytracer (я перевожу его с Python на C ).

Я попробовал простой тестовый пример, но я надеялся создать random_uniform() функцию, которая всегда выдает новое случайное число (использование time() не сработает, так как это будет выполняться действительно быстро)

 unsigned short Xi[3] = {0, 1, 27};
std::cout << erand48(Xi);
  

И результат был (и будет при каждом вызове программы):

 0.174529
  

Я попытался использовать предыдущий вывод в качестве нового Xi , вот так ( Xi было определено начальное значение):

 float random_uniform() {
  long generated = erand48(Xi);
  int temp = generated * 1000000;

  unsigned short Xi[3] = {temp - 16, temp - 7, temp - 18};

  return generated;
}
  

Но не похоже, что это сгенерирует достаточно случайных чисел (и это только выдает 0 . Я ‘, не уверен, почему …).

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

Ответ №1:

Не будучи знакомым с python, я собираюсь предположить, что random.uniform (0, 1) выдает случайное число из равномерного распределения между 0 и 1?

Если это так, попробуйте следующее:

 srand(time(NULL));
float myRand = ((float) rand( )) / RAND_MAX;
  

Обратите внимание, что ваш пробег может варьироваться — rand () не гарантированно является источником случайных чисел очень высокого качества. Вы можете получить визуальные артефакты в зависимости от реализации и того, как вы ее используете. Я использую генератор случайных чисел Mersenne Twister в моем raytracer.

РЕДАКТИРОВАТЬ: просто чтобы было немного понятнее, это:

 ...
void init_program ( )
{
    ...
    srand(time(NULL));
    ...
}
...
float random_uniform ( )
{
    return ((float) rand( )) / RAND_MAX;
}
...
  

Если вы вызываете оба srand и rand одновременно, вы, вероятно, будете получать одно и то же «случайное» число каждый раз, потому что, если time за это время оно не изменилось, вы будете заполнять генератор точно таким же начальным значением и, следовательно, получите точно такое же первое случайное число.

Комментарии:

1. Я почти уверен, что это то srand , чего не хватало в OP.

2. Я просматривал smallpt (Google it), и этот raytracer использовал только erand48 . Я вызываю эту функцию каждый раз, когда луч попадает на диффузную поверхность (в основном для каждого пикселя, когда я создаю свой Cornell box), поэтому я не уверен, что у time() функции правильная скорость обновления.

3. @Blender: вам нужно вызвать srand только один раз, чтобы запустить генератор случайных чисел, а не каждый раз, когда вам нужно случайное число. Вызовите srand(time(NULL)) один раз в начале вашей программы, и вам не нужно повторять. Извините — мог бы сделать это понятнее! Отредактированный ответ для демонстрации.

4. Спасибо, теперь это немного более поучительно. Я попробую реализовать это и отправлю ответ через несколько минут, если это сработает.

5. И это работает! Спасибо за информацию. Я не уверен, почему я не использовал rand() раньше (facepalm)!

Ответ №2:

Есть ли причина, по которой вы не просто используете rand() , которая является частью стандартной библиотеки C ? Функция, на которую вы ссылаетесь, является частью единой спецификации UNIX, но, вероятно, не переносима…

Причина, по которой вы получаете одно и то же значение снова и снова, заключается в том, что вы не заполняете генератор случайных чисел, поэтому он ведет себя детерминированно. Используйте srand() or srand48() , если вас устраивают функции, специфичные для UNIX, и вам нужна 48-битная точность. Вызывайте его только один раз в начале вашей программы и передавайте time(NULL) . Не беспокойтесь об использовании time() , поскольку вы вызываете эту функцию только один раз, вам не нужно беспокоиться о том, чтобы всегда получать одно и то же значение времени.

Возможно, вы также захотите обратиться к этой странице о том, как взять возвращаемое значение из rand() и эффективно масштабировать его до нужного диапазона:

С ИСПОЛЬЗОВАНИЕМ ФУНКЦИИ C ИЛИ C rand()


РЕДАКТИРОВАТЬ: Вернитесь назад и снова прочитайте документы для erand48 . Вы заметите, что она возвращает значение double в диапазоне [0, 1). Вы помещаете это в long , вероятно, поэтому вы всегда видите ноль (значение усекается до целого числа). Я также думаю, что это, вероятно, обновление значений unsigned long массива для вас с текущим номером в последовательности — вы предоставляете хранилище, оно использует его для «отслеживания» последовательности.

Попробуйте:

 unsigned short xsubi[3] = { 0, 1, 27 };
for (int i = 0; i < 10;   i)
{
   double value = erand48(xsubi);
   printf("%fn", value);
}
  

Ответ №3:

Да — это называется std::rand() , входит в стандартную комплектацию и поставляется в <cstdlib> .

http://msdn.microsoft.com/en-us/library/398ax69y (v = VS.100).aspx

Комментарии:

1. @Blender, да, это часть стандартной библиотеки C , поэтому она должна поддерживаться любой платформой, соответствующей стандартам.

Ответ №4:

Возможно, стоит изучить Boost.Случайный.