Подтвердить что ты не робот

Генерирование случайного числа между [-1, 1] в C?

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

Я хотел создать случайное число между [-1, 1]. Как я могу это сделать?

4b9b3361

Ответ 1

Используйте -1+2*((float)rand())/RAND_MAX

rand() генерирует целые числа в диапазоне [0,RAND_MAX] включительно, поэтому ((float)rand())/RAND_MAX возвращает число с плавающей запятой в [0,1]. Мы получаем случайные числа из [-1,1], добавляя его к -1.

EDIT: (добавление соответствующих частей раздела комментариев)

Об ограничениях этого метода:

((float)rand())/RAND_MAX возвращает процент (доля от 0 до 1). Так как диапазон от -1 до 1 равен 2 целым числам, я умножаю эту долю на 2, а затем добавляю ее к минимальному числу, которое вы хотите, -1. Это также говорит о качестве ваших случайных чисел, так как у вас будут только RAND_MAX уникальные случайные числа.

Ответ 2

Если у вас есть библиотека Standard C, тогда ответы других людей разумны. Если у вас есть возможности POSIX, вы можете использовать drand48() семейство функций. В частности:

#define _XOPEN_SOURCE 600  /* Request non-standard functions */
#include <stdlib.h>

double f = +1.0 - 2.0 * drand48();
double g = -1.0 + 2.0 * drand48();

Обратите внимание, что в руководстве написано:

Функции drand48() и erand48() должны возвращать неотрицательные значения с плавающей точкой с двойной точностью, равномерно распределенные по интервалу [0.0,1.0].

Если вам строго нужно [-1.0,+1.0] (в отличие от [-1.0,+1.0)), вы сталкиваетесь с очень деликатной проблемой с расширением диапазона.

Функции drand48() дают вам значительно больше случайности, чем типичная реализация rand(). Однако, если вам нужна криптографическая случайность, ни одна из них не подходит; вам нужно искать "криптографически сильный PRNG" (PRNG = генератор псевдослучайных чисел).

Ответ 3

У меня был подобный вопрос некоторое время назад и подумал, что было бы более эффективно просто генерировать дробную часть напрямую. Я сделал несколько поисков и наткнулся на интересный быстрый с плавающей точкой rand, который не использует деление или умножение с плавающей запятой, или int- > float cast может быть сделано с помощью интимное знание внутреннего представления float:

float sfrand( void )
{
    unsigned int a=(rand()<<16)|rand();  //we use the bottom 23 bits of the int, so one
                                         //16 bit rand() won't cut it.
    a=(a&0x007fffff) | 0x40000000;  

    return( *((float*)&a) - 3.0f );
}

Первая часть генерирует случайный поплавок из [2 ^ 1,2 ^ 2), вычитает 3, и вы имеете [-1, 1). Конечно, это может быть слишком интимным для некоторых приложений/разработчиков, но это было именно то, что я искал. Этот механизм хорошо работает для любого диапазона, который имеет мощность в 2 раза.

Ответ 4

Для начала вам понадобится функция библиотеки C rand(). Это находится в заголовочном файле stdlib.h, поэтому вы должны поставить:

#include <stdlib.h>

рядом с началом вашего кода. rand() будет генерировать случайное целое число от нуля до RAND_MAX, поэтому деление на RAND_MAX / 2 даст вам число от нуля до 2 включительно. Вычитайте один, и вы попадете в целевой диапазон от -1 до 1.

Однако, если вы просто выполняете int n = rand() / (RAND_MAX / 2), вы обнаружите, что не получите ответ, который вы ожидаете. Это связано с тем, что как rand(), так и RAND_MAX / 2 являются целыми числами, поэтому используется целочисленная арифметика. Чтобы это не произошло, некоторые люди используют прилив с плавающей точкой, но я бы рекомендовал избегать приведения путем умножения на 1.0.

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

Итак, в целом мы имеем:

#include <stdlib.h>
srand(time(0);
double r = 1.0 * rand() / (RAND_MAX / 2) - 1;

Ответ 5

В то время как принятый ответ во многих случаях прекрасен, он не будет содержать "любое другое число", потому что он расширяет диапазон уже дискретных значений на 2, чтобы покрыть интервал [-1, 1]. Аналогичным образом, если у вас есть генератор случайных чисел, который может генерировать целое число от [0, 10], и вы хотели сгенерировать [0, 20], просто умножение на 2 будет охватывать диапазон, но не сможет охватить диапазон (он оставил бы все нечетные числа).

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

Метод, который способен генерировать любое представляемое число с плавающей запятой от -1 до 1 включительно, должно основываться на генерации последовательности a1.a2 a3 a4 a5... до предела вашей точности с плавающей запятой, что является единственным способом чтобы иметь возможность генерировать любые возможные поплавки в диапазоне. (т.е. после определения действительных чисел)

Ответ 6

Из "Стандартной библиотеки C"

int rand(void) - возвращает псевдослучайное число в диапазоне от 0 до RAND_MAX

RAND_MAX - Максимальное значение, возвращаемое rand().

Итак:

rand() вернет псевдослучайное число в диапазоне от 0 до RAND_MAX

rand() / RANDMAX вернет псевдослучайное число в диапазоне от 0 до 1

2*( rand() / RANDMAX ) вернет псевдослучайное число в диапазоне от 0 до 2

2*( rand() / RANDMAX ) -1 вернет псевдослучайное число в диапазоне от -1 до 1

Ответ 7

Как уже отмечалось, любые попытки простого преобразования диапазона функции "rand()" из [0, RAND_MAX] в желаемый [-1, +1] будут генерировать генератор случайных чисел, который может генерировать только дискретные набор значений с плавающей запятой. Для генератора с плавающей точкой плотность этих значений может быть недостаточной в некоторых приложениях (если значение RAND_MAX, определенное реализацией, недостаточно велико). Если это проблема, можно увеличить указанную плотность экспоненциально, используя два или более вызова rand() вместо одного.

Например, комбинируя результаты двух последовательных вызовов с "rand()" , можно получить псевдослучайное число в [0, (RAND_MAX + 1) ^ 2 - 1] диапазоне

#define RAND_MAX2 ((RAND_MAX + 1ul) * (RAND_MAX + 1) - 1)

unsigned long r2 = (unsigned long) rand() * (RAND_MAX + 1) + rand();

а затем использовать тот же метод, чтобы преобразовать его в число с плавающей запятой в диапазоне [-1, +1]

double dr2 = r2 * 2.0 / RAND_MAX2 - 1;

Используя этот метод, вы можете наращивать столько вызовов rand(), сколько необходимо, следя за целым переполнением.

В качестве побочного примечания этот метод объединения последовательных вызовов "rand()" не генерирует генераторы псевдослучайных чисел очень высокого качества, но он может работать отлично для многих целей.