PDA

Показать полную графическую версию : [решено] Как сгенерировать случайное число на всем диапазоне значений int?


Michael
29-05-2009, 13:50
Добрый день.
Необходимо сгенерировать одномерный массив случайных чисел в диапазоне от INT_MIN до INT_MAX. С генерацией массива проблем нет, а как получить случайное число на всем диапазоне значений целочисленного типа int (от INT_MIN до INT_MAX)?
Спасибо

Coutty
29-05-2009, 16:59
Генерируете случайное число с плавающей точкой от 0 до 1 стандартным способом. Умножаете на (INT_MAX минус INT_MIN), округляете и прибавляете INT_MIN.

Это первое, что приходит в голову. Возможно, есть специальная функция.

P.S. Похоже, я немного неверно понял задание. Алгоритм был написан для генерации числа, скажем от 100 до 500. А если от 0 до "условно 1000", то просто произвольное от 0 до 1 умножить на 1000.

Второе дополнение: если диапазон от -1000 до 1000, то создаётся число от 0 до 1, умножается на тысячу и на "случайный знак". Правда здесь дополнительное ветвление появляется... Что-то вроде этого:
rand() * 1000 * ( (rand() >= 0.5) ? 1 : -1 )

Pliomera
29-05-2009, 20:29
если диапазон от -1000 до 1000, то создаётся число от 0 до 1, умножается на тысячу и на "случайный знак". Правда здесь дополнительное ветвление появляется... »

rand() * 2000 - 1000 :)

PS. В С/С++ ни ухом ни рылом...

Coutty
29-05-2009, 20:33
rand() * 2000 - 1000 »
Это понятно. А если использовать INT_MAX вместо тысячи? Тогда числа "2000" не будет, т.к. оно выходит за границы диапазона.
Я тоже С/С++ не знаю, но не суть :)

Drongo
30-05-2009, 09:49
В общем есть кое-какая идея, почти сумасбродная и имеющая некий изврат, :whitevoid: но вполне работоспособная при правильном подходе. Изложу суть.

У нас INT_MAX = 2 147 483 647 (в числе 10 цифр и не больше). Используем несколько масивов

...
int array1[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Единицы
int array2[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; // Десятки
int array3[10] = {0, 100, 200, 300, 400, 500, 600, 700, 800, 900}; // Сотни
int array4[10] = {0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000}; // Тысячи
int array5[10] = {0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000}; // Десятки тысяч
int array6[10] = {0, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000}; // Сотни тысяч
int array7[10] = {0, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000}; // Миллион
int array8[10] = {0, 10000000, 20000000, 30000000, 40000000, 50000000, 60000000, 70000000, 80000000, 90000000}; // Десятки миллионов
int array9[10] = {0, 100000000}; // Сотни миллионов. Потому что в значении 2 147 483 647. Максимальное.
int array10[10] = {0, 100000000, 200000000}; // Миллиард. Потому что в значении 2 147 483 647. Максимальное.
int array_rand[size] = {0}; // Массив куда будем записывать числа (от INT_MIN до INT_MAX)

int index1,
index2,
index3,
index4,
index5,
index6,
index7,
index8,
index9,
index10,
SumNumber;

Далее используем генерацию случайных чисел от '0' до '9'

#include <stdlib.h>
#include <ctime.h>
using std::time;

...

srand(time(0));

for(int i = 0; i < size; i++){
index1 = rand() % 9; // Значения от '0' до '9' Всего 10 значений. Для индекса массива.
index2 = rand() % 9;
index3 = rand() % 9;
index4 = rand() % 9;
index5 = rand() % 9;
index6 = rand() % 9;
index7 = rand() % 9;
index8 = rand() % 9;
index9 = rand() % 1;
index10 = rand() % 2;

...
// Проверяем, чтобы 2 147 483 647 не вышел за диапазон значения
if(index10 == 2){
// Проверяем, чтобы 2 147 483 647 не вышел за диапазон значения.
if(index9 == 1){
// Выполняем суммирование только для этих случаев
SumNumber = array10[index10] + array9[index9] + array8[index8] ... + ... array2[index2] + array1[index1];
}
}

....
// В итоге и правильном алгоритме, мы получаем
SumNumber = array10[index10] + array9[index9] + array8[index8] ... + ... array2[index2] + array1[index1];
array_rand[i] = SumNumber;
}

А чтобы отрицательное получить, ну, ещё один рандом прикрутить, с диапазоном значений от '0' до '1', если ноль - значит выполняем положительные числа, если единица - ставим к полученому числу - "—". Будет отрицательное.

В тех местах где я выделил зелёным цветом, слегка запутался, так как в числе 2 147 483 647, может быть и так - 2 047 483 647. Но пока ничего не могу придумать. :durak:

Michael
31-05-2009, 12:42
Спасибо - идея понятна. Вот только с реализацией возник вопрос.
Стандартный int rand(void) возвращает случайное целое число в диапазоне от 0 до RAND_MAX, где RAND_MAX=32767. Если получать случайное число в интервале от 0 до 1 вот таким образом - double(rand())/RAND_MAX, то идеологически это будет верно?

Coutty
31-05-2009, 13:00
Вполне. Можно сразу умножать на (INT_MAX/RAND_MAX). Если часто используется генерация, то сохраните это число как константу.

Michael
31-05-2009, 17:06
А как часто надо проводить инициализацию генератора случайных силел - srand(time(0))? Один раз или каждый раз перед использованием rand()?

Drongo
31-05-2009, 18:52
А как часто надо проводить инициализацию генератора случайных силел - srand(time(0))? Один раз или каждый раз перед использованием rand()? »Достаточно одного раза.

pva
01-06-2009, 07:54
чему в вашей системе равны INT_MIN и INT_MAX?

Syntax

#include <stdlib.h>
int rand(void);

Description

Random number generator.

rand uses a multiplicative congruential random number generator with period 2 to the 32nd power to return successive pseudorandom numbers in the range from 0 to RAND_MAX. The symbolic constant RAND_MAX is defined in stdlib.h.

stdlib.h:

/* Maximum value returned by "rand" function
*/
#define RAND_MAX 0x7FFFU

Используем идею Drongo»
, только в 2-ичной системе, и представление 32-разрядного int в памяти:

int big_rand = (rand() << 30) | (rand() << 15) | rand();

Drongo
01-06-2009, 18:48
Спасибо - идея понятна. Вот только с реализацией возник вопрос. »Если это вопрос в мою сторону, то там и реализации как таковой нет, объеденить две написаные части и всё. Пример ниже.

pva, Я правильно понял, что ваш код, всего одна строка
int big_rand = (rand() << 30) | (rand() << 15) | rand(); »полноценно заменяет мой вариант ниже? Я проверил, работает зашибенно. :up:

// Генерация случайных значений
// от INT_MIN = -2 147 483 647
// до INT_MAX = 2 147 483 647
//---------------------------------------------------------------------------
#include <iostream>
using namespace std;
#include <conio.h>
#include <stdlib.h>
#include <ctime.h>
using std::time;

int main()
{
int SumNumber;
srand(time(0));
for(int i = 0; i < 1000; i++){
int big_rand = (rand() << 30) | (rand() << 15) | rand();
cout<<"SumNumber = "<<big_rand<<endl;
}
//cin>>SumNumber;
getch();

return 0;
}
//---------------------------------------------------------------------------

// Генерация случайных значений
// от INT_MIN = -2 147 483 647
// до INT_MAX = 2 147 483 647
//---------------------------------------------------------------------------
#include <iostream>
using namespace std;
#include <conio.h>
#include <stdlib.h>
#include <ctime.h>
using std::time;

int main()
{
const int size = 10;
const int arrayRandSize = 1000;

int array1[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Единицы
int array2[size] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; // Десятки
int array3[size] = {0, 100, 200, 300, 400, 500, 600, 700, 800, 900}; // Сотни
int array4[size] = {0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000}; // Тысячи
int array5[size] = {0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000}; // Десятки тысяч
int array6[size] = {0, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000}; // Сотни тысяч
int array7[size] = {0, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000}; // Миллион
int array8[size] = {0, 10000000, 20000000, 30000000, 40000000, 50000000, 60000000, 70000000, 80000000, 90000000}; // Десятки миллионов
int array9[size] = {0, 100000000}; // Сотни миллионов. Потому что в значении 2 147 483 647. Максимальное.
int array10[size] = {0, 1000000000, 2000000000}; // Миллиард. Потому что в значении 2 147 483 647. Максимальное.
int array_rand[arrayRandSize] = {0}; // Массив куда будем записывать числа (от INT_MIN до INT_MAX)

int index1, index2, index3, index4, index5,
index6, index7, index8, index9, index10,
SumNumber;

srand(time(0));

for(int i = 0; i < arrayRandSize; i++){
index9 = rand() % 1;
index10 = rand() % 2;

// Проверяем, чтобы 2 147 483 647 не вышел за диапазон значения
if(index10 == 2 && index9 == 1){
index1 = rand() % 7; // Значения от '0' до '9' Для индекса массива.
index2 = rand() % 4;
index3 = rand() % 6;
index4 = rand() % 3;
index5 = rand() % 8;
index6 = rand() % 4;
index7 = rand() % 7;
index8 = rand() % 4;
}
else{
index1 = rand() % 9; // Значения от '0' до '9'. Для индекса массива.
index2 = rand() % 9;
index3 = rand() % 9;
index4 = rand() % 9;
index5 = rand() % 9;
index6 = rand() % 9;
index7 = rand() % 9;
index8 = rand() % 9;
}

// В итоге и правильном алгоритме, мы получаем
SumNumber = array10[index10] + array9[index9] + array8[index8]
+ array7[index7] + array6[index6] + array5[index5]
+ array4[index4] + array3[index3] + array2[index2]
+ array1[index1];

// Делаем знаковое число...
if((1 + rand() % 2) == 1)
array_rand[i] = SumNumber;
else
array_rand[i] = -SumNumber;

//cout<<"SumNumber = "<<SumNumber<<endl;
}

for(int i = 0; i < arrayRandSize; i++){
cout<<"SumNumber = "<<array_rand[i]<<endl;
}

//cin>>SumNumber;
getch();

return 0;
}
//---------------------------------------------------------------------------

Michael
01-06-2009, 20:58
pva, INT_MAX=2147483647, INT_MIN=-2147483648
Drongo, не, я там про другую реализацию говорил - все вышеописанное опиралось на сгенерированное случайное число в интервале от 0 до 1, а стандартный int rand(void) возвращает случайное целое число в диапазоне от 0 до 32767. И меня интересовало, если получать случайное число в интервале от 0 до 1 следующим образом - double(rand())/RAND_MAX, то будет ли это верно с точки зрения идеологии программирования.

Xucyc
12-01-2011, 03:23
Интересные вы =)))



rand() % (max- min + 1) + min;

pva
12-01-2011, 22:31
INT_MAX=2147483647, INT_MIN=-2147483648 »
всё зависит от представления числа в памяти

(rand() << 30) | (rand() << 15) | rand();

заполнит все биты 32-битного числа, в т.ч. и старший 31-й бит, который отвечает за знак. Таким образом будет сгенерировано число в диапазоне от -0x80000000 до 0x7fffffff. Если же воспринимать заполненные 32 бита памяти как беззнаковое число, то получится диапазон от 0 до 0xffffffff.

Вариант
double(rand())/RAND_MAX*INT_MAX »
не годится по той причине, что он не может сгенерировать число 2. Потому что (0.0/RAND_MAX)*INT_MAX = 0, а (1.0/RAND_MAX)*INT_MAX >32786

так же не годится вариант
rand() % (max- min + 1) + min; »
в данном случае max- min + 1 = 0

Onyma
04-02-2011, 17:08
Допустим что у нас есть функция rnd(), которая возвращает случайное, равномерно распределённое число в диапазоне от rnd_min до rnd_max.
Наша задача: написать функцию my_rnd(), которая будет возвращать случайное, равномерно распределённое число в диапазоне от my_min до my_max.
Решение:
1. Для начала мы приведём имеющееся у нас случайное число к интервалу [0, 1]:

float tmp_rnd = float(rnd() - rnd_min) / (rnd_max - rnd_min);


2. Теперь мы приведём полученное в диапазон [my_min, my_max]:

my_int result = tmp_rnd * (my_max - my_min) + my_min;


3. Ну и возвращаем результат:

return result;


Здесь предполагается что точности всех применяемых типов хватает для хранения получаемых величин, а так же, что мощность (количество возможных чисел) области значений функции rnd() больше или равно мощности области значений функции my_rnd(); в противном случае некоторые числа из нужного нам диапазона ни когда не будут появляться.

в данном случае max- min + 1 = 0 »

1. max - min + 1 = 0 => max + 1 = min => min > max. не согласен: всегда max > min.
2. конструкция rand() % (max- min + 1) + min; будет работать при условии, что функция rand() имеет область определения достаточной мощности: RAND_MAX >= (max - min)




© OSzone.net 2001-2012