2012-03-19 2 views
4

Я создал тестовое приложение, которое генерирует 10k случайных чисел в диапазоне от 0 до 250 000. Затем я вычислил значения MAX и min и заметил, что значение MAX всегда составляет около 32k ...Extend rand() max range

Вы не знаете, как расширить возможный диапазон? Мне нужен диапазон с MAX стоимостью около 250 000!

ответ

7

Это по определению рандов(), см:

http://cplusplus.com/reference/clibrary/cstdlib/rand/

http://cplusplus.com/reference/clibrary/cstdlib/RAND_MAX/

Если вам нужны большие случайные числа, вы можете использовать внешнюю библиотеку (например http://www.boost.org/doc/libs/1_49_0/doc/html/boost_random.html) или вычислить большие случайные числа из нескольких небольших случайных чисел самостоятельно.

Но обратите внимание на распределение, которое вы хотите получить. Если вы просто подытоживаете маленькие случайные числа, результат не будет равномерно распределен.

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

Принимая продукт случайных чисел также не работает.

Возможное решение следующие:

1) Take two random numbers a,b 
2) Calculate a*(RAND_MAX+1)+b 

Таким образом, вы получите одинаково распределенные случайные величины до (RAND_MAX + 1)^2-1

+2

Продукт также не будет линейным. И последнее решение должно быть «a * (RAND_MAX + 1) + b'. (Он будет работать для случайных значений в диапазоне '[0, (RAND_MAX + 1) * (RAND_MAX + 1))', обеспечивая отсутствие переполнения. –

+0

спасибо, я исправил его. – Heinzi

+0

Большое спасибо! –

0

Увеличьте свои номера на N/RAND_MAX, где N - ваш желаемый максимум. Если номера подходят, вы можете сделать что-то вроде этого:

unsigned long long int r = rand() * N/RAND_MAX; 

Очевидно, что если начальная часть перетекает вы не можете сделать это, но с N = 250000 вы должны быть хорошо. RAND_MAX 32K на многих популярных платформах.

В более общем плане, чтобы получить случайное число равномерно в интервале [A, B], использование:

A + rand() * (B - A)/RAND_MAX; 

Конечно, вы, вероятно, следует использовать правильный C++ - стиль <random> библиотека; найдите этот сайт для многих подобных вопросов, объясняя, как его использовать.


Edit: В надежде на предотвращение эскалации комментариев, вот еще одна копия/вставить надлежащего C++ решение для действительно равномерного распределения на интервале [A, B]:

#include <random> 

typedef std::mt19937 rng_type; 
typedef unsigned long int int_type; // anything you like 

std::uniform_int_distribution<int_type> udist(A, B); 
rng_type rng; 

int main() 
{ 
    // seed rng first: 
    rng_type::result_type const seedval = get_seed(); 
    rng.seed(seedval); 

    int_type random_number = udist(rng); 
    // use random_number 
} 

Не стоит забывать отменить ГРП! Если вы сохраните начальное значение, вы можете повторить ту же случайную последовательность позже.

+0

'(rand() * RAND_MAX + rand())/(RAND_MAX * RAND_MAX/250000);'? –

+1

Наиболее частое значение «RAND_MAX» - это что-то вроде 2^31 (хотя, очевидно, это не тот случай, с которым он сталкивается). И что-то вроде 'rand() * N/RAND_MAX' не даст равного распределения: без принуждения чего-либо к плавающей точке, будет большое количество отверстий и даже выполнение промежуточных вычислений в плавающей точке, а затем возврат к целому числу , вы никогда не сможете получить больше значений RAND_MAX. –

+1

Ваш «более общий» алгоритм обычно не работает. Вероятность переполнения 'rand() * (B - A)' велика. В моем ящике Linux он будет переполняться, как только «(B - A)> 1'. (Еще одна проблема заключается в том, что вы должны использовать 'RAND_MAX + 1' всюду, так как это число различных значений, возвращаемых« rand() ». За исключением, конечно, того, что на моем Linux-поле переполняется« RAND_MAX + 1 ».) –

3

Предположительно, вы также хотите, равномерное распределение по этому поводу расширенный область. Единственный способ, которым вы можете эффективно это сделать, - создать последовательность меньших чисел и масштабировать их так, как если бы вы работали в другой базе .Например, для 250000, вы можете 4 случайные числа в диапазоне [0,10) и один в диапазоне [0,25), вдоль линий:

int 
random250000() 
{ 
    return randomInt(10) + 10 * randomInt(10) 
     + 100 * randomInt(10) + 1000 * randomInt(10) 
     + 10000 * randomInt(25); 
} 

Для этого, чтобы работать, ваш генератор случайных чисел должно быть хорошо; многие реализация rand() не были (или, по крайней мере, не были — Я не проверил ситуацию недавно). Вы также захотите устранить смещение , которое вы получите, когда вы нанесете RAND_MAX + 1 различные значения в 10 или 25 разные значения. Если RAND_MAX + 1 не кратен 10 и 25 (например, является точным кратным 50), вам нужно что-то как:

int 
randomInt(int upperLimit) 
{ 
    int const limit = (RAND_MAX + 1) - (RAND_MAX + 1) % upperLimit; 
    int result = rand(); 
    while (result >= limit) { 
     result = rand(); 
    return result % upperLimit; 
} 

(Внимание при этом: есть некоторые машины, где RAND_MAX + 1 будет переполнение;., если портативность является проблемой, вам необходимо принять дополнительные меры предосторожности )

Все это, конечно, предполагает хорошее качество генератора, которое далеко от данность.

+0

Почему бы просто не сделать 'randomInt' рекурсивным, если' upperLimit' находится над RAND_MAX, и не беспокоить ненужным медленным 'random250000()'? (Или в _least_ дать 'randomInt'' assert', чтобы предотвратить недопустимый ввод. –

+2

@ Это возможность. Моя цель состояла не в том, чтобы обеспечить оптимальное решение, а в том, чтобы предложить эффективный подход, я выбрал '10' просто потому, что все (Я надеюсь) знаком с арифметикой 10-го уровня и узнал бы основную идею. Также: вы должны следить, когда 'limit' в' randomInt' становится большим, вы можете в конечном итоге отбросить значительный процент результатов ' rand() '. –

1

Вы можете просто манипулировать своим номером поразрядным путем создания меньших случайных чисел.

Например, если вам нужно 32-разрядное случайное число а:

int32 x = 0; 
for (int i = 0; i < 4; ++i) { // 4 == 32/8 
    int8 tmp = 8bit_random_number_generator(); 
    x <<= 8*i; x |= tmp; 
} 

Если вам не нужна хорошая хаотичность в ваших номеров, вы можете просто использовать RAND() & 0xff для 8-битных генератор случайных чисел. В противном случае вам понадобится нечто лучшее.

+0

На самом деле, если' RAND_MAX' имеет форму '2^n-1' (часто случай),' rand() & 0xFF' не будет вводить никакого смещения. (Конечно, способ реализации получает «RAND_MAX» этой формы, может привести к смещению.) –

+0

правильный, но быстрее использовать «RAND_MAX», чем любой '8bit_random_number_generator' –

+0

. Вы оба правы, я просто указывал на другую реализацию. Если вы используете rand () вообще, скорее всего, вы не собираетесь на самом деле жесткие ограничения, но вам, конечно, может понадобиться как минимум время работы. Лучшим решением является использование хорошей внешней библиотеки, такой как [Boost] (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_random.html). –

0

Вы используете короткие функции? Если это так, вы увидите 32 767 в качестве вашего максимального числа, потому что что-то большее будет переполнять короткий int.