New_Pi
Гость
|
|
« : 08-12-2004 07:48 » |
|
Гененератор случайных чисел:
#include "stdafx.h" #include <iostream.h> #include <cstdlib> int main() { int x; for (x=0; x<5; x++) cout << '#' << x << '=' << rand()<<endl; return 0; }
Возможно вы скажите, что тут всё нормально, но есть две интересные для меня проблеммы: 1) Сама функция rand(), а именно: после запуска программы она выводит случайные значения - это верно, (допустим 45, 346, 5888, .....), если запустить программу повторно то получим те же самые числа !? (Хотя по-моему они не должны быть равны).
Если можно, обьясните пожалуста эту проблемму и ещё, чтобы числа генерировались в определённом диапазоне (я не знаю стандартный диапазон).
2) У меня, когда запускается программа (описанная выше) в консольном приложении она существует считанные миллисекунды. Ну эту проблему я научился обходить по-своему: cout << '#' << x << '=' << rand()<<endl; cin >> x; return 0; Но мой метод не очень актуален. Приходится постоянно вводить какое-то значение, чтобы программа "вылетела". Пока писал текст вспомнил cin.get. char a[2]; cin.get(a,2,'\n'); Так уже лучше, но не достаточно красиво.
Можно ли сделать что бы окно акрывалось с нажатием клавиши Enter и что бы в программе не было такой ерунды как у меня ?
|
|
|
Записан
|
|
|
|
PSD
Главный специалист
Offline
Пол:
|
|
« Ответ #1 : 08-12-2004 08:01 » |
|
1) Rand на самом деле это генератор псевдо случайных чисел, в некотром сегменте по тридевятому смещениею существует таблица псевдослучайных чисел в диапазоне от 0 до FFFF , rand возвращает их по очереди смечаясь c каждым вызовом на 1 шаг, таблица эта статична и генерится 1 раз, если есть не обходимость выпонить повторную генерацию таблицы используй randomize(timer). Если поставить randomize(timer) то при каждом запуске программы ты будешь получать разный набор псевдослучайных чисел.
кстати, поправочка: rand генерит псевдослучайные чисел в диапазоне от от 0 до RAND_MAX (==0x7fff)
|
|
« Последнее редактирование: 22-05-2009 13:48 от Алексей1153++ »
|
Записан
|
Да да нет нет все остальное от лукавого.
|
|
|
New_Pi
Гость
|
|
« Ответ #2 : 08-12-2004 08:37 » |
|
PSD, именно это я и хотел услышать на 1-й вопрос. Спасибо ! Можно более подробно объяснить randomize(timer), точнее как всунуть эту функцию в программу (и необходимые присоединяемые файлы для этого).
|
|
|
Записан
|
|
|
|
PSD
Главный специалист
Offline
Пол:
|
|
« Ответ #3 : 08-12-2004 08:52 » |
|
Помоему я тебя нагло обманул ... randomize это не в С :oops: . А паскаль и бейсик. Вот при мер для С++ #include <stdlib.h> #include <stdio.h> #include <time.h>
void main( void ) { int i;
/* Seed the random-number generator with current time so that * the numbers will be different every time we run. */ srand( (unsigned)time( NULL ) );
/* Display 10 numbers. */ for( i = 0; i < 10;i++ ) printf( " %6d\n", rand() ); }
В С аналог randomize это srand.
|
|
|
Записан
|
Да да нет нет все остальное от лукавого.
|
|
|
Alf
Гость
|
|
« Ответ #4 : 08-12-2004 09:29 » |
|
Уже который раз слышу миф о том, что где-то в недрах программ прячутся таинственные таблицы псевдослучайных чисел... Вроде бы логика подсказывает, что такого не должно быть, не могут разработчики такой ерундой забивать память. Однако и на форуме постоянно мелькают подобные заявления, и в одной из наших статей эта версия на полном серьезе выдвигалась как истина, не подлежащая сомнению... Стало любопытно, решил прояснить сей вопрос окончательно. Вот что показало маленькое расследование: /*** *rand.c - random number generator * * Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. * *Purpose: * defines rand(), srand() - random number generator * *******************************************************************************/
#include <cruntime.h> #include <mtdll.h> #include <stddef.h> #include <stdlib.h>
#ifndef _MT static long holdrand = 1L; #endif /* _MT */
/*** *void srand(seed) - seed the random number generator * *Purpose: * Seeds the random number generator with the int given. Adapted from the * BASIC random number generator. * *Entry: * unsigned seed - seed to seed rand # generator with * *Exit: * None. * *Exceptions: * *******************************************************************************/
void __cdecl srand ( unsigned int seed ) { #ifdef _MT
_getptd()->_holdrand = (unsigned long)seed;
#else /* _MT */ holdrand = (long)seed; #endif /* _MT */ }
/*** *int rand() - returns a random number * *Purpose: * returns a pseudo-random number 0 through 32767. * *Entry: * None. * *Exit: * Returns a pseudo-random number 0 through 32767. * *Exceptions: * *******************************************************************************/
int __cdecl rand ( void ) { #ifdef _MT
_ptiddata ptd = _getptd();
return( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) & 0x7fff );
#else /* _MT */ return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff); #endif /* _MT */ }
Вот и все премудрости! Следующее псевдослучайное число получается из предыдущего посредством нехитрой формулы, отсюда и повторяемость последовательности. Чтобы не стартовать последовательность каждый с одного и того же числа, как заметил New_Pi, функция с полуприличным названием srand позволяет задать начальное значение. Ну а дальше, разумеется, по накатанной колее, поскольку следующее значение полностью предопределено предыдущим. Источник информации: C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC\RAND.C (разумеется, зависит от установки Visual Studio).
|
|
« Последнее редактирование: 03-12-2007 16:27 от Алексей1153++ »
|
Записан
|
|
|
|
New_Pi
Гость
|
|
« Ответ #5 : 08-12-2004 09:36 » |
|
srand( (unsigned)time( NULL ) ); я так понимаю эта функция берёт какое-то временное значение и из него генерирует псевдослучайные числа. Вот пример 1-х чисел, которые выводит программа (у меня) после нескольких перезапусков: 8794, 8843, 8889, 8928. Вторая строка уже более расходится в значениях, но первая... Мне нужно сделать "случайный" генератор (ну или так, что бы он казался случайным ) , а получается так сказать a+b+c+... (при запуске программы). В самой программе rand() меня уже более менее убовлетворяет ) Можно ли это обойти с помощью функции srand(). Если кто знает, где я могу изучить эту функцию нормально (а то я надоем своими вопросами :twisted: ), дайте мне ссылку в то место.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #6 : 08-12-2004 10:46 » |
|
New_Pi, time( NULL ) возвращает текущее время UNIX ( число секунд после 1.1.1970 0:00:00 ). Возьми не это число, а остаток от деления на некоторое другое число, тогда период, разумеется, будет, но входные значения для srand не обязательно будут расти линейно.
А действительно случайных чисел ты не получишь. (см. Кнута, т.2)
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
npak
|
|
« Ответ #7 : 08-12-2004 11:29 » |
|
New_Pi, вот пример "качественного" генератора случайных чисел в интервале от 0 до 2^32 - 5 (0xFFFFFFFB)
Последовательность обозначим как X(n) где n номер числа в последовательности
Тогда X(n+1) = (1176*X(n) + 1476*X(n-1) + 1776*X(n-2)) % (2^32 - 5) Для инициализации генератора надо задать три числа.
период генератора около 2^96 (более одного триллиона)
Источник: Матвеев и др. "Математические и компьютерные основы криптологии",
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #8 : 08-12-2004 12:21 » |
|
Alf, в некоторых случаях, для повышения быстродействия, действительно используют таблицы со случайными числами - их заранее заполняют случайными или псевдослучайными числами, а потом выбирают последовательно или по другому закону. Конечно, вышесказанное не относится к стандартной библиотеке С.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Alf
Гость
|
|
« Ответ #9 : 08-12-2004 13:20 » |
|
RXL, в данном случае ключевая фраза - в некоторых случаях.
В особо критических случаях можно и синусы или там логарифмы брать из таблиц, экономя время на их вычислении. Но уверять, что любая программа содержит где-то в недрах таблицы случайных чисел или тригонометрических функций, я бы все же не решился. Тем более если речь идет об учебной программе, а не программировании сигнального процессора в реальном времени, где каждая микосекунда на счету.
Уж больно живучий предрассудок оказался...
|
|
|
Записан
|
|
|
|
Scorp__)
Молодой специалист
Offline
Пол:
|
|
« Ответ #10 : 08-12-2004 17:24 » |
|
New_Pi, а кстати по поводу закрытия окна по Enter я пользовался, в свое время, getch() из stdlib.h или conio.h не помню точно. И не только по Enter, а по любой клавише. Наверное в потоках С++ есть какой-нибудь аналог, но я не помню докопался я до него или нет.
|
|
|
Записан
|
- А Вы сами-то верите в привидения? - Конечно, нет, - ответил лектор и медленно растаял в воздухе.
|
|
|
nikedeforest
|
|
« Ответ #11 : 08-12-2004 19:22 » |
|
getch() относится к conio.h PSD писал: Помоему я тебя нагло обманул ... randomize это не в С . А паскаль и бейсик. Почему и в Си тоже есть: randomize initializes the random number generator with a random value void randomize (void) библиотека stdlib.h, но чтобы получить значение нада вызывать random или уже rand или srand. New_Pi, Возможно значения повторялись потому что ты не вызывал randomize() Вот пример, запусти пару раз а потом если захочешь ( если не лень будет, мне например лень даже запускать ) напиши повторялись значения. Я когда-то работал с randomize и random, проблем вроде не было, т.е. числа вроде не повторялись.
|
|
|
Записан
|
ещё один вопрос ...
|
|
|
nikedeforest
|
|
« Ответ #12 : 08-12-2004 19:31 » |
|
Блин, сам пример забыл ................................ #include <stdlib.h> #include <stdio.h> #include <time.h> int main(void) { int i; randomize(); printf("Ten random numbers from 0 to 99\n\n"); for(i=0; i<10; i++) printf("%d\n", rand() % 100); return 0; } ................................ за одно перед return 0; поставь getch(); и все будет ОК .
|
|
|
Записан
|
ещё один вопрос ...
|
|
|
New_Pi
Гость
|
|
« Ответ #13 : 02-01-2005 17:38 » |
|
Спасибо всем за подробные ответы !!! getch() и правда работает. Я даже и не знал об этой функции.
|
|
|
Записан
|
|
|
|
.
Молодой специалист
Offline
Пол:
|
|
« Ответ #14 : 12-01-2005 17:28 » |
|
.. И это только под Windows....
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #15 : 14-01-2005 06:27 » |
|
Начиная с P3(если не изменяет память), Intel процессоры поддерживают генерирование случайных чисел на основе колебаний термодатчика...
|
|
|
Записан
|
while (8==8)
|
|
|
RXL
|
|
« Ответ #16 : 14-01-2005 13:26 » |
|
sss, в процессоре такого нет, а вот в чипсет генератор случайных чисел встраивают.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
.
Молодой специалист
Offline
Пол:
|
|
« Ответ #17 : 17-01-2005 21:00 » |
|
При этом API страдает по-прежнему сильно
|
|
|
Записан
|
|
|
|
npak
|
|
« Ответ #18 : 18-01-2005 09:27 » |
|
Арсений, что значит "страдает", да ещё "по-прежнему" (оно раньше "страдало"?)? и как измерить "силу" этого "страдания"? При этом API страдает по-прежнему сильно
Есть POSIX API. В нём представлены два генератора: плохой 16-битный (rand / srand) и хороший 48-битный (drand48, erand48, lrand48 и прочие). Реализации эти интерфейсов есть во всех современных Unix-подобных системах (например, Linux, клоны BSD, Solaris). Кроме того, есть нестандартный BSD интерфейс для генератора 31-битных случайных чисел (random / srandom), причём этот генератор поддерживает инициализацию случайным числом из устройства (функция srandomdev, устройство /dev/arandom). Этот интерфейс портирован в Linux (за исключением srandomdev). Возможно, есть проблема с тем, что на Windows из перечисленных есть только rand/srand. Для генерации случайных чисел криптографического качества Windows предоставляет CryptGenRandom в Crypt API. Для целей переносимости Unix-Windows можно воспользоваться генератором случайных чисел криптографического качества из openssl См. <openssl/rand.h> : RAND_bytes, RAND_pseudo_bytes и проч. Так что интерфейсы "не страдают". Есть проблема переносимости между Unix-ами и Windows, но было бы удивительно, если бы этой проблемы не было
|
|
|
Записан
|
|
|
|
maestro(91)
Гость
|
|
« Ответ #19 : 22-05-2009 13:42 » |
|
для выбора диапозона нужно использовать такой пример например, вариация с игральным кубиком состовляет 6 чисел, так вот какое число выпадет можно описать так:(диапозон от1 до 6) ..................................... srand(time(NULL)); cout<<1+rand%6<<endl; .......................................
т.е легко понять так 1 первая граница, 6 последняя
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #20 : 22-05-2009 13:49 » |
|
maestro(91), не городи чушь, а также смотри на дату темы
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #21 : 22-05-2009 18:55 » |
|
Вообще говоря, "rand()" даёт более-менее равномерное распределние, а вот в равномерности "rand() % N" я не уверен.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #22 : 23-05-2009 06:58 » |
|
остаток от деления не даст равномерности, например: есть таблица псевдослучайных чисел от 0 до 9 0,1,2,3,4,5,6,7,8,9 //только перемешанная если числа достаются с одинаковой вероятностью, то при %6 значения результата 0,1,2,3 будут выпадать чаще а вот если весь диапазон преобразовать к диапазону 0...1 , а потом растянуть к требуемому - тогда всё идеально ps хотя... Человек упомянул про игральные кости - видимо там это выгодно )
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #23 : 23-05-2009 10:33 » |
|
А зачем преобразовывать к диапазону 0..1, если можно сразу к 0..6? Я так понимаю, нужно что-то вроде rand() / (MAX_INT / 6) - не? А то из целых в дробные, а потом обратно в целые - как-то некрасиво
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #24 : 23-05-2009 13:28 » |
|
Вад, это в математической модели преобразования надо так делать А в формуле можно упростить - без плавающей точки rand() //0...RAND_MAX rand()/RAND_MAX //0...1 (6-1)*rand()/RAND_MAX //0...5 (6-1)*rand()/RAND_MAX+1 //1...6
в итоге, никаких плавающих точек (int)((N-1)*rand()/RAND_MAX+1) // лежит в диапазоне 1...N
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #25 : 23-05-2009 15:40 » |
|
Алексей1153++, У тебя будет идти все время 1. Крутой у тебя генератор будет.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #26 : 23-05-2009 15:50 » |
|
Ну собственно проверка моей теории #include <stdlib.h> #include <stdio.h>
int main() { int N=6; for(int i=0; i<100; ++i) printf("%d", ((N-1)*rand()/RAND_MAX+1)); printf("\n"); return 0; }
Выход 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #27 : 23-05-2009 15:52 » |
|
щас проверим )) (6-1)*1234/0x7fff+1 == 1 (6-1)*7000/0x7fff+1 == 2 (6-1)*14000/0x7fff+1 == 3 (6-1)*25000/0x7fff+1 == 4 (6-1)*32000/0x7fff+1 == 5 всё нормально, единственное, что редко выпадет 6 , тут я ошибся, надо сделать так а "rand()-1" - это чтобы однажды не выпало N+1 правда при этом вероятность выпадения N чуточку уменьшилась, всего на (RAND_MAX/N - 1)/(RAND_MAX/N)*100%
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #28 : 23-05-2009 15:56 » |
|
Finch, что то странное у тебя, щас у себя проверю
-------------
проверил, у меня всё чётко )
1315332554154321121153111233441432144532545531325245554222512141152234543243354132443212353542143143
|
|
« Последнее редактирование: 23-05-2009 16:01 от Алексей1153++ »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #29 : 23-05-2009 15:59 » |
|
Хорошо, Увеличиваю цикл с твоей поправкой 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111
Если ты найдеш тут хоть намек на 2, я буду рад. Не говоря уже о других числах.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
|