Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> генератор случайных чисел, помогите написать 
V
    Опции темы
GoldFinch
Дата 20.6.2009, 19:20 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 15
Всего: 26



Цитата(Irdis @  20.6.2009,  18:42 Найти цитируемый пост)
не так не интересно... можно например таким образом
берём системное время, делаем из него число, возводим в квадрат, берём 4 цифры от получившегося (из середины ,например), делаем из них число, возводим в куб берём 4 цифры и т. д.
достаточное количество подобных операций позволит сделать генератор случайных чисел

полнейший бред, показывающий незнание теории.

взяли системное время - там допустим 20.5 случайных бит, провели с ним любое количество операций, получили либо те же 20.5 бит, либо например 18.1 бит, т.к. что потеряли.

Это сообщение отредактировал(а) GoldFinch - 20.6.2009, 19:21
PM MAIL ICQ   Вверх
Леопольд
Дата 20.6.2009, 20:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(natusik86 @ 20.6.2009,  16:36)
А для диапазона от 3 до 7 получаются числа от 5 до 9.

Вы уверенны? Сколько итераций провели для выяснения? smile

rX - число полученное от генератора.

3 + r0 % 7 = 3
3 + r6 % 7 = 9
отрезок [3,9] а не [5,9]


Пока считал, нашёл ошибку у себя, надо единичку добавить, а то не получается нужный отрезок.
Следовательно, правильный алгоритм такой:
Код

int rand_range(int from, int to)
{
    return from + rand() % (abs(to - from) + 1);
}

abs возвращает абсолютную величину числа, если припомнить алгебру то |-7| = |7| = 7.

3 +  r0 % (|7 - 3| + 1) = 3 + 0 = 3
3 +  r4 % (|7 - 3| + 1) = 3 + 4 = 7
3 +  r6 % (|7 - 3| + 1) = 3 + 1 = 4
все числа в заданном отрезке.

На всякий случай следует попробовать с отрицательным числом [-3,7]:
-3 +  r0 % (|7 - (-3)| + 1) = -3 + 0 = -3
-3 +  r10 % (|7 - (-3)| + 1) = -3 + 10 = 7
-3 +  r11 % (|7 - (-3)| + 1) = -3 + 1 = -2

Пробуем для отрезка [3,-7]
3 +  r0 % (|-7 - 3)| + 1) = 3 + 0 = 3
3 +  r10 % (|-7 - 3)| + 1) = 3 + 10 = 13
Увы и ах, не фурычит. Но можно сделать так, что-бы зафурычило, уверяю Вас, но оставлю и Вам маленько, извилины поразмять...

Это сообщение отредактировал(а) Леопольд - 20.6.2009, 20:37


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 21.6.2009, 10:08 (ссылка)   | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Ладно, не буду томить.
Совсем правильный алгоритм, не зависящий от порядка такой:

Код

#include <cstdlib>
#include <algorithm>

int rand_range(int from, int to)
{
    if(from > to)
        std::swap(from,to); // меняем местами
    return from + std::rand() % (std::abs(to - from) + 1);
}



Вот теперь, надо тестировать, хотя тесты лучше писать до кода smile
Код

#include <iostream>
#include <exception>
class test_case:public std::exception{
    std::string w;
public:
    test_case(std::string text):w(text){}
    virtual const char* what() const throw(){
        return w.c_str();
    }
    virtual ~test_case() throw(){}
};

void test() {
    try{
        int i, res;
        //test case [3,-7]
        {
            for(i=0; i< 1000000; ++i){
                res = rand_range(3,-7);
                if(res > 3 || res < -7)
                    throw test_case("test case [3,-7] fails");
            }
        }
        //test case [-7,3]
        {
            for(i=0; i< 1000000; ++i){
                res = rand_range(-7,3);
                if(res > 3 || res < -7)
                    throw test_case("test case [-7,3] fails");
            }
        }
        //test case [-7,-3]
        {
            for(i=0; i< 1000000; ++i){
                res = rand_range(-7,-3);
                if(res > -3 || res < -7)
                    throw test_case("test case [-7,-3] fails");
            }
        }
        //test case [-3,-7]
        {
            for(i=0; i< 1000000; ++i){
                res = rand_range(-3,-7);
                if(res > -3 || res < -7)
                    throw test_case("test case [-3,-7] fails");
            }
        }
        //test case [3,7]
        {
            for(i=0; i< 1000000; ++i){
                res = rand_range(3,7);
                if(res > 7 || res < 3)
                    throw test_case("test case [3,7] fails");
            }
        }
        //test case [7,3]
        {
            for(i=0; i< 1000000; ++i){
                res = rand_range(7,3);
                if(res > 7 || res < 3)
                    throw test_case("test case [7,3] fails");
            }
        }
        throw std::exception();
    }
    catch(test_case& ex){
        std::cout<<ex.what()<<std::endl;
    }
    catch(std::exception&){
        std::cout<<"All cases are passed successfuly"<<std::endl;
    }
}


int main(int argc, char* argv[]){
    test();
    return 0;
}



--------------------
вопросов больше чем ответов
PM MAIL   Вверх
zim22
Дата 21.6.2009, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(Леопольд @  21.6.2009,  10:08 Найти цитируемый пост)
Вот теперь, надо тестировать, хотя тесты лучше писать до кода

у вас тесты не полные. проверяются только границы диапазона. посмотрите, что получится в этом случае: 
smile
Код

int rand_range(int from, int to)
{
    return from;
}

***
и неплохо бы ГПСЧ запустить
Код

srand(time(NULL));


Это сообщение отредактировал(а) zim22 - 21.6.2009, 10:25


--------------------
PM MAIL   Вверх
Irdis
Дата 21.6.2009, 12:00 (ссылка)   | (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 21.5.2008

Репутация: нет
Всего: 1



Цитата

полнейший бред, показывающий незнание теории.

скажем так, для нужд народного хозяйства моего метода хватит
Цитата

взяли системное время - там допустим 20.5 случайных бит, провели с ним любое количество операций, получили либо те же 20.5 бит, либо например 18.1 бит, т.к. что потеряли.

полнейший бред

Это сообщение отредактировал(а) Irdis - 21.6.2009, 12:01
PM MAIL   Вверх
GoldFinch
Дата 21.6.2009, 12:59 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 15
Всего: 26



Цитата(Irdis @  21.6.2009,  13:00 Найти цитируемый пост)
полнейший бред

ок, обосную.

Допустим мы получаем время с точностью до 1/1024 сек,
интенсивность использования ГСЧ 1 Гц,
тогда в идеальном случае мы имеем 10 случайных бит, распределение будем считать равномерным.

Т.е. в среднем каждую секунду запрашивая время мы получаем число у которого младшие 10 двоичных разрядов заранее неизвестны (случайны), а старшие известны и постоянно увеличиваются.

Тогда отбросив старшие разряды мы получаем случайное число которое может принять одно из 1024 значений, от 0 до 1023

Проведя с ним какуюто последовательность операций, мы для каждого конкретного числа x1 получаем какоето другое число y1=f(x1). 
Если для каждого xy не повторяются, то информация не теряется, и мы для 1024 разных x получаем 1024 разных y.
Если какието y повторяются, например 220 одинаковых, то мы для 1024 разных x получим 804 разных y, 9.651бит,  - информация потеряется.
И на в каком случае, мы не получим большее количество y чем x.

литература: http://ru.wikipedia.org/wiki/%D0%98%D0%BD%...%BF%D0%B8%D1%8F

Это сообщение отредактировал(а) GoldFinch - 21.6.2009, 13:01
PM MAIL ICQ   Вверх
Irdis
Дата 21.6.2009, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 21.5.2008

Репутация: нет
Всего: 1



убедительно, но всё таки:
Если мы можем получить хотя бы один байт случайной информации то из них не трудно склепать 1Гб случайной информации.
ко времени можно также прибавить другие изменяющиеся данные (зависит от фантазии) также добавить в формулу рекуррентные соотношения(тогда даже если время начнёт повторяться  smile  мы будем получать новые числа, т.е. y1=f(x1); y2=f(x1) => y1!=y2 http://ru.wikipedia.org/wiki/Рекуррентная_формула мощнейший аппарат).
В любом случае это не полный бред.

Это сообщение отредактировал(а) Irdis - 21.6.2009, 18:37
PM MAIL   Вверх
Леопольд
Дата 21.6.2009, 20:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(zim22 @ 21.6.2009,  10:22)
Цитата(Леопольд @  21.6.2009,  10:08 Найти цитируемый пост)
Вот теперь, надо тестировать, хотя тесты лучше писать до кода

у вас тесты не полные. проверяются только границы диапазона. посмотрите, что получится в этом случае: 
smile
Код

int rand_range(int from, int to)
{
    return from;
}

На самом деле, такая функция даже не сгенерит ни бита бинарного кода, потому что она бессмысленна. Думаю, даже gcc оптимизатор не пропустит smile

Вопрос был у человека, получать числа в заданном диапазоне. Т.е. значение, возвращаемое функцией rand_range не должно выходить за него. Будет совсем не то что надо... smile 

Генератор, думаю, надо инициализировать до вызова этой функции.

Это сообщение отредактировал(а) Леопольд - 21.6.2009, 20:09


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
zim22
Дата 21.6.2009, 20:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(Леопольд @  21.6.2009,  20:04 Найти цитируемый пост)
Вопрос был у человека, получать числа в заданном диапазоне

вы тесты зачем привели? чтобы проверить, что числа находятся в нужном диапазоне, правильно?
я вам привёл пример, на котором ваши тесты бесполезны. смысл тогда от них? smile
Цитата(Леопольд @  21.6.2009,  20:04 Найти цитируемый пост)
На самом деле, такая функция даже не сгенерит ни бита бинарного кода, потому что она бессмысленна

так осмысленней?
Код

int rand_range(int from, int to)
{
    return rand() % 2 ? from: to;
}


Это сообщение отредактировал(а) zim22 - 21.6.2009, 20:35


--------------------
PM MAIL   Вверх
natusik86
Дата 21.6.2009, 21:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 25.5.2009

Репутация: нет
Всего: нет



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

Код

int rand_range(int from, int to)
{
    int ch, i, j, k;
    int Mas[10];

    if(from >= 0)
    {
      for(i=0; i<10; i++)
      {
        k=-1;
        while(k<from)
        {
          k = random(to+1);
        }
        Mas[i] = k;
      }
    }
    else
    {
      if(to>0)
      {
        for(i=0; i<10; i++)
        {
         j = random(2);
         switch(j)
         {
           case 0: Mas[i] = random(abs(from)+1);
                   Mas[i] = (-1)*Mas[i];
                   break;
           case 1: Mas[i] = random(to+1);
                   break;
         }
        }
       }
       else
       {
         for(i=0; i<10; i++)
         {
            k=-1;
            while(k<abs(to))
            {
              k = random(abs(from)+1);
            }
            Mas[i] = (-1) * k;
         }
       }

    }
    j=random(10);
    ch = Mas[j];
    
    return ch;
}


PM MAIL   Вверх
codelord
Дата 21.6.2009, 22:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 777
Регистрация: 7.5.2005
Где: ты моя темноглаза я где?!

Репутация: 1
Всего: 39



Цитата(natusik86 @ 21.6.2009,  17:02)
по моему это слишком круто для такой функции
Код

int rand_range(int from, int to)
{
    int ch, i, j, k;
    int Mas[10];

    if(from >= 0)
    {
      for(i=0; i<10; i++)
      {
        k=-1;
        while(k<from)
        {
          k = random(to+1);
        }
        Mas[i] = k;
      }
    }
    else
    {
      if(to>0)
      {
        for(i=0; i<10; i++)
        {
         j = random(2);
         switch(j)
         {
           case 0: Mas[i] = random(abs(from)+1);
                   Mas[i] = (-1)*Mas[i];
                   break;
           case 1: Mas[i] = random(to+1);
                   break;
         }
        }
       }
       else
       {
         for(i=0; i<10; i++)
         {
            k=-1;
            while(k<abs(to))
            {
              k = random(abs(from)+1);
            }
            Mas[i] = (-1) * k;
         }
       }

    }
    j=random(10);
    ch = Mas[j];
    
    return ch;
}


А если так smile
Код

int random_range( int from, int to )
{
 int interval = to - from + 1;
 int rand_value = rand() % interval;
 return from + rand_value;
}



--------------------
Доступен поиск по исходным кодам в GOOGLE.
http://www.google.com/codesearch
PM MAIL   Вверх
Леопольд
Дата 22.6.2009, 07:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(zim22 @ 21.6.2009,  20:34)
Цитата(Леопольд @  21.6.2009,  20:04 Найти цитируемый пост)
Вопрос был у человека, получать числа в заданном диапазоне

вы тесты зачем привели? чтобы проверить, что числа находятся в нужном диапазоне, правильно?
я вам привёл пример, на котором ваши тесты бесполезны. смысл тогда от них? smile

Смысл очень прост - requirements verification.

Стоит задача, написать функцию возвращающую рандомное значение в заданном диапазоне, а не протестировать распределение функции std::rand. Не надо усложнять.

Тесты я привёл для того что-бы показать natusik86 что функциональность надо тестировать.

Но я обратил более пристальное внимание на тесты и понял что хватит трёх вместо всех тех.
Код

void test() {
        int i, res;
        //test case [0,1]
        {
            for(i=0; i< 1000; ++i){
                res = rand_range(0,1);
                if(res > 1 || res < 0){
                    std::cout<<"test case [0,1] fails. returned value is "<<res<<std::endl;
                    break;
                }
            }
        }
        //test case [0,-1]
        {
            for(i=0; i< 1000; ++i){
                res = rand_range(0,-1);
                if(res > 0 || res < -1){
                    std::cout<<"test case [0,-1] fails. returned value is "<<res<<std::endl;
                    break;
                }
            }
        }
        //test case [0,0]
        {
            for(i=0; i< 1000; ++i){
                res = rand_range(0,0);
                if(res != 0){
                    std::cout<<"test case [0,0] fails. returned value is "<<res<<std::endl;
                    break;
                }
            }
        }
}


Это сообщение отредактировал(а) Леопольд - 22.6.2009, 09:01


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 22.6.2009, 08:14 (ссылка)    | (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(natusik86)

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

Чем проще функция тем лучше. Кому как, а я бы воспользовался этим smile
Код

#include <cstdlib>
#include <algorithm>
int rand_range(int from, int to)
{
    if(from > to)                                // если from больше to то
        std::swap(from,to);                      // меняем местами to и from
    return from + std::rand() % (to - from + 1); // f(x) = from + x % (to - from + 1)
}



Цитата(codelord)

А если так smile
Код

int random_range( int from, int to )
{
 int interval = to - from + 1;
 int rand_value = rand() % interval;
 return from + rand_value;



А если так, то что получится для [1,0]?
Попробуйте прогнать через это:
Код

#include <iostream>
void test() {
        int i, res;
        //test case [0,1]
        {
            for(i=0; i< 1000; ++i){
                res = rand_range(0,1);
                if(res > 1 || res < 0){
                    std::cout<<"test case [0,1] fails. returned value is "<<res<<std::endl;
                    break;
                }
            }
        }
        //test case [0,-1]
        {
            for(i=0; i< 1000; ++i){
                res = rand_range(0,-1);
                if(res > 0 || res < -1){
                    std::cout<<"test case [0,-1] fails. returned value is "<<res<<std::endl;
                    break;
                }
            }
        }
        //test case [0,0]
        {
            for(i=0; i< 1000; ++i){
                res = rand_range(0,0);
                if(res != 0){
                    std::cout<<"test case [0,0] fails. returned value is "<<res<<std::endl;
                    break;
                }
            }
        }
}


Это сообщение отредактировал(а) Леопольд - 22.6.2009, 09:00


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
codelord
Дата 22.6.2009, 11:04 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 777
Регистрация: 7.5.2005
Где: ты моя темноглаза я где?!

Репутация: 1
Всего: 39



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

Цитата(Леопольд @  22.6.2009,  04:14 Найти цитируемый пост)
Чем проще функция тем лучше. Кому как, а я бы воспользовался этим 

вот этот вариант я имею ввиду. 

И не надо предлагать мне использовать твои кривые тесты, писать научись.


--------------------
Доступен поиск по исходным кодам в GOOGLE.
http://www.google.com/codesearch
PM MAIL   Вверх
Леопольд
Дата 22.6.2009, 12:17 (ссылка)  | (голосов:5) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(codelord @ 22.6.2009,  11:04)
Леопольд
не надо через задницу задвавать диапазон, и если ты взял логику из моей функции дописал туда swap и удалил переменную и гордится этим

"Надо Федя, надо."  А если оторвёшь взгляд от себя любимого, то, возможно, заметишь что эту функцию я написал раньше. Но не я изобрел алгебру и потому никак не могу обвинить тебя в плагиате...

Цитата(codelord @ 22.6.2009,  11:04)

ты облажался со своим abs он здесь не нужен.

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

Ты же облажался со swap'ом. Я бы с интересом посмотрел как ты мою фукнцию "уронишь", как я твою. Может она в распределённых системах будет вызывать ошибку? smile 
Я (как автор функции) может и не задам кривой диапазон, некоторое время. А вот через год, или два, я, теоретически, сам стану юзером своей функции, и могу забыть что я не предусмотрел того что отрезок/диапазон можно задать и справа-налево, т.е. от большему к меньшему. Или надо программировать асболютно бездумно и не учитывать что на вход могут прийти не все reqirements в силу того что их автор мог просто упустить некоторые детали? А используя свои "кривые" тесты, я значительно ускорю любое изменение. Причём, можно эти тесты подцепить к assert или к #define DEBUG. Этакий unitary testing.

Цитата(codelord @ 22.6.2009,  11:04)

И не надо предлагать мне использовать твои кривые тесты, писать научись.

Почему "кривые"? Хотелось бы услышать какое-то обоснование а не голословный тявк. Если можешь написать, то напиши "ровные", а если не можешь то просто промолчи, это лучше чем тявкать на "кривые". И съёшь что-то от "озверина", например "мышьяк" smile

Как заключение, я не хотел бы работать с таким самодовольным типом как ты в одной команде.

Это сообщение отредактировал(а) Леопольд - 22.6.2009, 12:59


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Страницы: (3) Все 1 [2] 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0930 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.