Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
Danikkkk
0 / 0 / 0
Регистрация: 23.10.2015
Сообщений: 4
#1

Генерация псевдослучайных чисел в заданном диапазоне

15.04.2016, 11:46. Просмотров 920. Ответов 20
Метки нет (Все метки)

Датчики случайных чисел можно привлекать при подборе проверочных исходных данных для программ.
Получить с помощью датчика случайных чисел:35 неотрицательных целых чисел, не превосходящих 1000;
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.04.2016, 11:46
Ответы с готовыми решениями:

Вывести нечетные числа сгенерированные с помощью генератора псевдослучайных чисел в заданном диапазоне
С помощью генератора случайных чисел получить 30 целых чисел, лежащих в...

Генерация случайных чисел в заданном диапазоне.
Здесь сказано Почему?

Генерация случайных чисел на заданном диапазоне
Здравствуйте, прошу прощения, если такая тема уже проскакивала. Есть простой...

Рандом: генерация случайных чисел в заданном диапазоне
Вобщем такая задача: пользователь должен вводить верхнюю границу диапазона...

C++11 генерация псевдослучайных чисел
Хотел заполнить матрицу максимального потребления ресурсов процессами (алгоритм...

20
mimicria
return (true);
1960 / 1097 / 219
Регистрация: 19.04.2011
Сообщений: 2,345
15.04.2016, 12:08 #2
C++
1
2
3
4
5
6
7
8
9
10
#include <stdlib.h>
#include <iostream>
using namespace std;
 
int main()
{
 for (short i=0; i<35; i++)
  cout << rand()%1000 << " ";
 return 0;
}
0
Babysitter
208 / 125 / 50
Регистрация: 23.11.2015
Сообщений: 369
Завершенные тесты: 2
15.04.2016, 12:34 #3
mimicria, знаю, что просто придирка, но вроде как делать остаток от деления не всегда хорошо.
ломаются немного статистические свойства функции, наверное вот так нормально:
C++
1
2
3
4
5
6
7
8
int random(unsigned N)
{
    int border = (RAND_MAX / N) * N;
    int r = 0;
    do r = rand();
    while (r >= border);
    return r % N;
}
0
mimicria
return (true);
1960 / 1097 / 219
Регистрация: 19.04.2011
Сообщений: 2,345
15.04.2016, 12:40 #4
Цитата Сообщение от Babysitter Посмотреть сообщение
вроде как
Цитата Сообщение от Babysitter Посмотреть сообщение
немного
Цитата Сообщение от Babysitter Посмотреть сообщение
наверное
Надо нести ерунду с большей уверенностью
0
grizlik78
Эксперт С++
1983 / 1476 / 191
Регистрация: 29.05.2011
Сообщений: 3,050
15.04.2016, 12:43 #5
В современном языке это было бы как-нибудь так
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <random>
#include <iostream>
 
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 1000);
    for (int n = 0; n < 35; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}
Хотя современному языку мало где учат.
2
Babysitter
208 / 125 / 50
Регистрация: 23.11.2015
Сообщений: 369
Завершенные тесты: 2
15.04.2016, 12:45 #6
mimicria, спасибо за подробное разъяснение моей неправоты.


вот вариант кеннинга 7.4.4
You might think that it would suffice to compute rand() % n, which is the remainder when dividing the random integer by n. In practice, this technique fails for two reasons.

The most important reason is pragmatic: rand() really returns only pseudo-random numbers. Many C++ implementations pseudo-random number generators give remainders that aren't very random when the quotients are small integers. For example, it is not uncommon for successive results of rand() to be alternately even or odd. In that case, if n is 2, successive results of rand() % n will alternate between 0 and 1.

There is another, more stable reason to avoid using rand() % n: If the value of n is large, and RAND_MAX is not evenly divisible by n, some remainders will appear more often than others. For example, suppose that RAND_MAX is 32767 (the smallest permissible value of RAND_MAX for any implementation) and n is 20000. In that case, tehre would be two distinct values of rand() tha wold cause rand() % n to be 10000 (namely 10000 and 30000), but only one value of rand() that would cause rand() % n to be 15000 (namely, 15000). Therefore, the naive implementation of nrand would yield 10000 as a value of nrand(20000) twice as often as it would yield 15000.

To aviod these pitfalls, we'll use a different strategy, by dividing the range of available randomnumbers into buckets of exactly equal size. Then we compute a random number and return the number of the coorresponding bucket. Because the buckets are of equal size, some random numbers may not fall into any bucket at all. In that case, we keep asking for random numbers until we get one that fits.
C++
1
2
3
4
5
6
7
8
9
10
11
// return a random integer in the range [0, n)
int nrand(int n)
{
    if (n <= 0 || n > RAND_MAX)
        throw domain_error("Argument to nrand is out of range");
    const int bucket_size = RAND_MAX / n;
    int r;
    do r = rand() / bucket_size;
    while (r >= n);
    return r;
}
0
Renji
2102 / 1543 / 470
Регистрация: 05.06.2014
Сообщений: 4,472
15.04.2016, 13:22 #7
Цитата Сообщение от Babysitter Посмотреть сообщение
вот вариант кеннинга 7.4.4
Если уж кеннингу охота докапываться до случая когда n сопоставимо с RAND_MAX, то его крутой алгоритм грохнется при n равном RAND_MAX+1 (bucket_size уйдет в ноль и здравствуй division by zero).
r=(rand()*RAND_MAX+rand())%n; Для игрушки вполне хватит, а для приличной криптографии псевдослучайные числа один фиг не годятся.
0
Babysitter
208 / 125 / 50
Регистрация: 23.11.2015
Сообщений: 369
Завершенные тесты: 2
15.04.2016, 13:32 #8
Renji, этот случай же учтен, какой-то странный наезд.
C++
1
2
if (n <= 0 || n > RAND_MAX)
    throw domain_error("Argument to nrand is out of range");
попытка получить рандомное число больше RAND_MAX при помощи обычного rand - это вообще задача такая нетривиальная.

Добавлено через 1 минуту
делать серьезную криптографию на основе стандартного rand - это тоже классная затея.
0
mimicria
return (true);
1960 / 1097 / 219
Регистрация: 19.04.2011
Сообщений: 2,345
15.04.2016, 13:50 #9
Вы серьёзно? В задачке на генерацию 35 чисел кто-то будет заморачиваться правильными интервалами равномерного распределения?
0
mimicria
return (true);
1960 / 1097 / 219
Регистрация: 19.04.2011
Сообщений: 2,345
15.04.2016, 16:02 #10
Цитата Сообщение от Babysitter Посмотреть сообщение
if n is 2, successive results of rand() % n will alternate between 0 and 1.
Вот ради интереса проверил, уже в этом авторитет неправ.
C++
1
2
 for (short i=0; i<1000; i++)
  cout << rand()%2 << " ";
Генерация псевдослучайных чисел в заданном диапазоне
0
nmcf
6271 / 5577 / 2537
Регистрация: 14.04.2014
Сообщений: 23,468
15.04.2016, 19:14 #11
mimicria, в чём он неправ? Нули и единицы.
0
hoggy
Заблокирован
Эксперт С++
15.04.2016, 19:24 #12
Цитата Сообщение от Babysitter Посмотреть сообщение
знаю, что просто придирка, но вроде как делать остаток от деления не всегда хорошо.
ломаются немного статистические свойства функции
ломается немного генератор, ага.

Цитата Сообщение от mimicria Посмотреть сообщение
Надо нести ерунду с большей уверенностью
окай

с большей, так с большей:

http://rextester.com/ZIW83899

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//-------------------------------------------------------------------------        
//----------------- генератор случайных чисел -----------------------------
//-------------------------------------------------------------------------        
 
#include <cstdint>
#include <chrono>
#include <random>
#include <climits>
 
namespace detail{
 
    static std::default_random_engine rnd(
        static_cast<uint32_t>(
            std::chrono::system_clock::now().time_since_epoch().count()
        )
    );
    
}//namespace detail
 
 
inline uint32_t Random(uint32_t minvalue, uint32_t maxvalue)
{
    using std::swap;
    
    if(minvalue > maxvalue) 
        swap(minvalue, maxvalue);
 
    return detail::rnd() % (maxvalue - minvalue + 1) + minvalue;
}
//-------------------------------------------------------------------------        
//-------------------------------------------------------------------------        
//-------------------------------------------------------------------------        
 
#include <iostream>
 
 
int main()
{
    std::cout << UINT_MAX;
    
    for(size_t i = 0, e = 10; i!=e; ++i)
        std::cout << Random(0,4294967295) << ", ";
    std::cout<<'\n';
}
мораль:
не используйте взятие остатка от деления.

Добавлено через 2 минуты
Цитата Сообщение от Renji Посмотреть сообщение
Если уж кеннингу охота докапываться до случая когда n сопоставимо с RAND_MAX, то его крутой алгоритм грохнется
не знаю, как насчет егошнего.
но этот - не грохнеццо:
Цитата Сообщение от grizlik78 Посмотреть сообщение
std::uniform_int_distribution<> dis(0, 1000);
1
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4424 / 2395 / 664
Регистрация: 18.10.2014
Сообщений: 4,051
15.04.2016, 22:01 #13
Цитата Сообщение от Babysitter Посмотреть сообщение
делать серьезную криптографию на основе стандартного rand - это тоже классная затея.
Так о том-то и речь. Если в задаче считается приемлемым использование простейшего rand() в качестве базового ПСЧ-оракула, то метод с взятием остатка от деления тоже прекрасно подойдет для этой задачи. Поэтому все эти разглагольствования о неприемлемости взятия остатка от деления - это формально корректно, но это бессмысленная трата времени.

Добавлено через 6 минут
Цитата Сообщение от mimicria Посмотреть сообщение
Вот ради интереса проверил, уже в этом авторитет неправ.
Тут невозможно быть "правым" или "не правым" в общем случае. Никакой стандартизованности в реализации rand() нет. В одной будут строго чередоваться нули и единицы в младшем бите, в другой - не будут. Авторитет говорил, скорее всего, о конкретной реализации rand(), которая, возможно, им даже явно приводилась.
2
Babysitter
208 / 125 / 50
Регистрация: 23.11.2015
Сообщений: 369
Завершенные тесты: 2
16.04.2016, 12:15 #14
снова здравствуйте.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
скорее всего
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
возможно
как бы деятель не упрекнул вас в недостатке уверенности.

естественно реализацию автор не приводил и просто предостерег, что такие реализации могут встретиться. книга то фундаментальная, издана около 2000 года. и формулировка была "it is not uncommon" на тот момент вполне оправдана.

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

если RAND_MAX большой, как в gcc или clang, то в принципе никто даже и не почувствует отличий, но в стандарте сказано, что минимальный RAND_MAX равен 32767. это же число использует мелкософт в своей реализации библиотеки. а это значит, что стратегия остатка от деления на 1000 будет сильно подсаживать вероятность выпадения чисел от 767 до 1000. вот банальный тест, скомпиленый в vs 2013, рисовал гнуплотом. сравнение моей наивной реализации "ерунды" с простым остатком:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstdlib>
using namespace std;
 
const int N = 1000;
unsigned int seed = 42;
 
int random(unsigned N)
{
    int border = (RAND_MAX / N) * N;
    int r = 0;
    do {
        r = rand();
    } while (r >= border);
    return r % N;
}
 
int plain(unsigned N)
{
    return rand() % N;
}
 
void test(int* A, int pred(unsigned), unsigned iter, ostream& out)
{
    // same seed
    srand(seed);
    // clean up
    for (size_t i = 0; i < N; ++i)
        A[i] = 0;
    // get data
    for (size_t i = 0; i < iter; ++i)
        ++A[pred(N)];
    // result to stream
    for (size_t i = 0; i < N; ++i)
        out << i << " " << A[i] << "\n";
}
int main()
{
    cout << "RAND_MAX = " << RAND_MAX << endl;
    cout << "border = " << (RAND_MAX / N) * N << endl;
    int hist[N];
    //////////////
    ofstream output("plain.dat");
    test(hist, plain, 1e7, output);
    output.close();
    //////////////
    output.open("mine.dat");
    test(hist, random, 1e7, output);
    output.close();
    return 0;
}
Bash
1
2
plot [0:] [9500:] 'plain.dat'
plot [0:] [9500:] 'mine.dat'
2
Миниатюры
Генерация псевдослучайных чисел в заданном диапазоне   Генерация псевдослучайных чисел в заданном диапазоне  
mimicria
return (true);
1960 / 1097 / 219
Регистрация: 19.04.2011
Сообщений: 2,345
19.04.2016, 08:48 #15
А у меня почему-то другие результаты.
C++
1
2
3
4
5
6
7
8
9
 int k=FileCreate("c:\\testrnd1.bin");
 short R;
 randomize();
 for (short i=0; i<10000; i++)
 {
  R=rand()%1000;
  FileWrite(k, &R, sizeof(R));
 }
 FileClose(k);
Чтобы не морщить голову гистограмма результатов в матлаб
Matlab M
1
2
3
4
5
6
7
8
9
clear all;
fname='c:\\testrnd1.bin';
fhandle = fopen(char(fname), 'r');
fseek(fhandle, 0, 'eof');
fsize = ftell(fhandle);
fseek(fhandle, 0, 'bof');
mas1 = fread(fhandle, fsize, 'uint16');
fclose(fhandle);
hist(mas1);
Вот гистограммы по трём разным реализациям, всё ровненько и случайно. RAND_MAX равен 32767.
Генерация псевдослучайных чисел в заданном диапазоне
Генерация псевдослучайных чисел в заданном диапазоне
Генерация псевдослучайных чисел в заданном диапазоне
0
nmcf
6271 / 5577 / 2537
Регистрация: 14.04.2014
Сообщений: 23,468
19.04.2016, 08:57 #16
mimicria, чисел сделай больше. Там выше 1e7 было.
0
Babysitter
19.04.2016, 09:19
  #17

Не по теме:

mimicria, это делфи? видимо что-то борландовское.

0
mimicria
return (true);
1960 / 1097 / 219
Регистрация: 19.04.2011
Сообщений: 2,345
19.04.2016, 10:46 #18
Цитата Сообщение от nmcf Посмотреть сообщение
чисел сделай больше. Там выше 1e7 было.
Какая разница? 10 тысяч вполне достаточно, чтобы увидеть такую просадку по статистике.
И опять же повторюсь: надо делить классы задач. В школьной задачке нет никакой необходимости фигачить какой-нибудь вихрь Мерсенна.
Цитата Сообщение от Babysitter Посмотреть сообщение
это делфи? видимо что-то борландовское.
Древний BCB6. Что закуплено, тем и пользуемся.
Кликните здесь для просмотра всего текста
Цитата Сообщение от Babysitter Посмотреть сообщение
забрало у меня всю мою карму
Нечего плаксу включать, раз первый начал
0
nmcf
6271 / 5577 / 2537
Регистрация: 14.04.2014
Сообщений: 23,468
19.04.2016, 20:19 #19
Цитата Сообщение от mimicria Посмотреть сообщение
Какая разница?
Разница есть. Вот для 10000000 и для 100000. Проявляется при большом количестве чисел.
1
Миниатюры
Генерация псевдослучайных чисел в заданном диапазоне   Генерация псевдослучайных чисел в заданном диапазоне  
Babysitter
208 / 125 / 50
Регистрация: 23.11.2015
Сообщений: 369
Завершенные тесты: 2
12.08.2016, 14:02 #20
случайно наткнулся. для тех, кто любит смотреть ( ͡° ͜ʖ ͡°)
Stephan T. Lavavej from Microsoft talks about rand() at Going Native
0
12.08.2016, 14:02
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.08.2016, 14:02

Генерация псевдослучайных чисел
Здравствуйте! Пишу программу, в ней мне нужно использовать случайные числа,...

Генерация псевдослучайных чисел.с++
Метод середины квадратов, у меня программа вычисляет одно число, а надо 125....

Генерация псевдослучайных чисел!!!
Помогите кто чем может!!пожалуйста! Составьте программу, реализующую линейный...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru