Где в этом коде генерируется случайное число?

#c #random #floating-point

#c #Случайный #значение с плавающей запятой

Вопрос:

Я наткнулся на генератор случайных чисел с плавающей запятой rgba:

http://rgba.org/articles/sfrand/sfrand.htm

Объяснение понятно, а код прост. Есть одна проблема: я не могу понять, откуда берутся случайные биты. Фрагмент кода ниже:

 static unsigned int mirand = 1;

float sfrand( void )
{
    unsigned int a;
    mirand *= 16807;
    a = (mirandamp;0x007fffff) | 0x40000000;
    return( *((float*)amp;a) - 3.0f );
}
  

Я пытался скомпилировать эту функцию и всегда получаю результат -0.995993 , который имеет смысл, если mirand начинается как 1 . Чего мне не хватает, или это mirand просто начальное значение?

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

1. Это не всегда возвращает одно и то же число. Если вы вызовете его несколько раз подряд, вы увидите, что каждый раз он возвращает другое число. Конечно, эта последовательность будет одинаковой при каждом запуске вашей программы.

2. @Gabe: Сначала я скомпилировал его на codepad.org, ideone.com и моя собственная машина. Я получил -0.995993 на обоих, за исключением ideone.com, которое выдало меня -3 (и является неправильным). Я запускал эту функцию уже много раз, и ответ @aleph_null помог мне понять цель использования.

3. Вы хотите сказать, что если вы запускаете функцию в цикле, вы каждый раз получаете один и тот же результат?

4. Нет, я запускал функцию в цикле, и результат отличается на каждой итерации. codepad.org/d96GzyBV

5. Хорошо, тогда вы не получаете один и тот же результат при каждом запуске функции.

Ответ №1:

Правда в том, что этот код не генерирует случайные числа… он генерирует псевдослучайные числа. Предполагая, что вы начинаете с одного и того же начального значения, непрофессионал может представить, что происходит, так это то, что вы просто просматриваете ОГРОМНЫЙ список «случайных» чисел. В конечном итоге числа будут повторяться, но хорошая формула — это та, которая позволяет этому повторению происходить с большим интервалом.

Для пояснения взгляните на формулу rand, используемую Excel: http://support.microsoft.com/kb/828795

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

1. Это имеет смысл! Спасибо. Я только что подтвердил ваш ответ здесь: codepad.org/d96GzyBV Примет ваш ответ, когда закончится таймер. :]

Ответ №2:

Причина, по которой вы получаете одно и то же число каждый раз, заключается в том, что на самом деле это генератор псевдослучайных чисел, такой же, как обычные. У него нет начального значения, поэтому вы всегда будете получать одно и то же значение при n-м вызове. Если вы выполните несколько последующих вызовов sfrand, вы увидите результаты, которые одинаковы между -1 и 1:

 -0.995993
0.347347
-0.130602
0.970146
-0.749159
0.883045
  

Точно так же, как если бы вы вызвали обычную функцию rand () без ее заполнения, вы бы увидели ту же последовательность. Как обсуждалось, число 16807 было выбрано не зря, поэтому вы можете заполнить это число, вызвав функцию случайное число раз:

 static unsigned int mirand = 1;

float sfrand(double seed)
{
    unsigned int a;
    mirand *= seed;
    a = (mirandamp;0x007fffff) | 0x40000000;
    return( *((float*)amp;a) - 3.0f );
}

int main()
{
    srand(time(NULL));
    int count = rand() % 1000   1
    for(int i = 0; i < count;   i)
        sfrand();
}
  

Это просто отбросит первые значения count, все еще предоставляя вам случайное начальное значение, и все последующие вызовы все равно получат повышение производительности, предусмотренное функцией. Последующие вызовы теперь возвращают уникальные значения:

 codys-macbook-pro:~ cody$ ./a.out
0.166836
codys-macbook-pro:~ cody$ ./a.out
0.256372
codys-macbook-pro:~ cody$ ./a.out
-0.194259
codys-macbook-pro:~ cody$ ./a.out
-0.556834
  

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

1. На самом деле, возможно, вы захотите перечитать статью. Они подобраны вручную 16807 по уважительной причине. Тем не менее, ваше объяснение согласуется с нашим пониманием. :]

2. Что они и сделали, я отредактирую свой ответ, чтобы включить рабочее случайное начальное значение.

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