Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: Интересные сособенности языка С++  (Прочитано 37390 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
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
Главный специалист

ru
Offline 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
Главный специалист

ru
Offline 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
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 08-12-2004 10:46 » 

New_Pi, time( NULL ) возвращает текущее время UNIX ( число секунд после 1.1.1970 0:00:00 ). Возьми не это число, а остаток от деления на некоторое другое число, тогда период, разумеется, будет, но входные значения для srand не обязательно будут расти линейно.

А действительно случайных чисел ты не получишь. (см. Кнута, т.2)
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #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 (более одного триллиона)

Источник: Матвеев и др. "Математические и компьютерные основы криптологии",
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 08-12-2004 12:21 » 

Alf, в некоторых случаях, для повышения быстродействия, действительно используют таблицы со случайными числами - их заранее заполняют случайными или псевдослучайными числами, а потом выбирают последовательно или по другому закону. Конечно, вышесказанное не относится к стандартной библиотеке С.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Alf
Гость
« Ответ #9 : 08-12-2004 13:20 » 

RXL, в данном случае ключевая фраза - в некоторых случаях.

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

Уж больно живучий предрассудок оказался...
Записан
Scorp__)
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 08-12-2004 17:24 » 

New_Pi, а кстати по поводу закрытия окна по Enter я пользовался, в свое время, getch() из stdlib.h или conio.h не помню точно. И не только по Enter, а по любой клавише. Наверное в потоках С++ есть какой-нибудь аналог, но я не помню докопался я до него или нет.
Записан

- А Вы сами-то верите в привидения?
- Конечно, нет, - ответил лектор и медленно растаял в воздухе.
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #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
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #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 » new

Спасибо всем за подробные ответы !!!
getch() и правда работает. Я даже и не знал об этой функции.
Записан
.
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 12-01-2005 17:28 » 

.. И это только под Windows....
Записан
sss
Специалист

ru
Offline Offline

« Ответ #15 : 14-01-2005 06:27 » 

Начиная с P3(если не изменяет память), Intel процессоры поддерживают генерирование случайных чисел на основе колебаний термодатчика...
Записан

while (8==8)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #16 : 14-01-2005 13:26 » 

sss, в процессоре такого нет, а вот в чипсет генератор случайных чисел встраивают.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
.
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 17-01-2005 21:00 » 

При этом API страдает по-прежнему сильно
Записан
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #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, но было бы удивительно, если бы этой проблемы не было Улыбаюсь
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
maestro(91)
Гость
« Ответ #19 : 22-05-2009 13:42 » 

для выбора диапозона нужно использовать такой пример например, вариация с игральным кубиком состовляет 6 чисел, так вот какое число выпадет можно описать так:(диапозон от1 до 6)
.....................................
srand(time(NULL));
cout<<1+rand%6<<endl;
.......................................

т.е легко понять так 1 первая граница, 6 последняя
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #20 : 22-05-2009 13:49 » 

maestro(91), не городи чушь, а также  смотри на дату темы
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #21 : 22-05-2009 18:55 » 

Вообще говоря, "rand()" даёт более-менее равномерное распределние, а вот в равномерности "rand() % N" я не уверен.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline 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 хотя... Человек упомянул про игральные кости - видимо там это выгодно Улыбаюсь)
Записан

Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 23-05-2009 10:33 » 

А зачем преобразовывать к диапазону 0..1, если можно сразу к 0..6? Я так понимаю, нужно что-то вроде rand() / (MAX_INT / 6) - не? А то из целых в дробные, а потом обратно в целые - как-то некрасиво Улыбаюсь
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline 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
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #25 : 23-05-2009 15:40 » 

Алексей1153++, У тебя будет идти все время 1. Крутой у тебя генератор будет.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Finch
Спокойный
Администратор

il
Offline 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
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline 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 , тут я ошибся, надо сделать так

Код:
N*(rand()-1)/RAND_MAX+1

а "rand()-1" - это чтобы однажды не выпало N+1
правда при этом вероятность выпадения N чуточку уменьшилась, всего на

(RAND_MAX/N - 1)/(RAND_MAX/N)*100%

 Отлично
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #28 : 23-05-2009 15:56 » 

Finch, что то странное у тебя, щас у себя проверю


-------------


проверил, у меня всё чётко )

1315332554154321121153111233441432144532545531325245554222512141152234543243354132443212353542143143
« Последнее редактирование: 23-05-2009 16:01 от Алексей1153++ » Записан

Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #29 : 23-05-2009 15:59 » 

Хорошо, Увеличиваю цикл Улыбаюсь с твоей поправкой
Цитата
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111
Если ты найдеш тут хоть намек на 2, я буду рад. Не говоря уже о других числах.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines