Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.67/21: Рейтинг темы: голосов - 21, средняя оценка - 4.67
63 / 64 / 11
Регистрация: 27.02.2013
Сообщений: 1,116

Продвинутый рандом (возможность задать рандомное число в нескольких диапазонах)

22.09.2014, 22:00. Показов 5060. Ответов 44
Метки нет (Все метки)

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

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
#include <iostream>
#include <vector>
#include <time.h>
#include <conio.h>
 
using namespace std;
 
struct Range
{
    int min;
    int max;
};
 
int random(Range range, ...)
{
    static bool flag = false;
    if (!flag)
    {
        srand(time(0));
        flag = true;
    }
    Range* value = &range;
    vector<int> values;
    while (value->min || value->max)
    {
        values.push_back(value->min + rand() % (value->max - value->min));
        value++;
    }
    return values[rand() % values.size()];
}
 
int main(int argc, char *argv[])
{
    for (int i = 0; i < 10; i++)
    {
        int x = random(Range({ 0, 10 }), Range({ 50, 60 }));
        cout << "x[" << i << "] = " << x << endl;
    }
    return getch();
}
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
22.09.2014, 22:00
Ответы с готовыми решениями:

Задать рандомное число
Собственно когда каждый раз жму ctrl-f5, то выводит одно и тоже числоа. Как сделать так, чтобы каждый раз было разные? #include...

Как задать рандомное число от 200 до 800?
Как это правильно оформить? Может кто-нибудь сказать, какой-нибудь простой для понимания алгоритм, по которому задаются диапазоны? Я только...

Как задать Рандомное число в заданном диапазоне
Не всё так просто как написано в шапке ;D Допустим есть число типа double d = 0.100200000000000; Как задать случайное число в...

44
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,822
23.09.2014, 19:44
Цитата Сообщение от КОП Посмотреть сообщение
Честно говоря, никогда не разбирал код с таким количеством шаблонов + переменное число аргументов. Есть над чем подумать. Спасибо
Шаблоны тут, скажем так, совсем нехитрые. Нужны только для обеспечения корректности (чтобы передавать в качестве аргумента можно было только Range и количество этих Range было > 0.
Выглядит конечно не очень понятно, но можно слегка причесать. Вынести метафункцияю проверки аргументов отдельно:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// функция-помощник для логического "И" от произвольного числа аргументов.
template <typename ...Args>
struct variadic_and
    : std::true_type
{};
template <typename First, typename ...Other>
struct variadic_and<First, Other...>
    : std::integral_constant<bool, First::value && variadic_and<Other...>::value>
{};
 
// проверка, что все аргументы Args эквивалентны T и количество аргументов больше 0 (используется SFINAE)
template <typename T, typename ...Args>
struct variadic_check
    : std::enable_if<
        (variadic_and<std::is_same<Args, T>...>::value && sizeof...(Args) > 0u)
      >
{};
Соответственно сама функция становится гораздо проще:
C++
1
2
template <typename ...RangeT, typename = typename variadic_check<Range, RangeT...>::type>
int random(std::mt19937 & mt, RangeT const & ...args);
0
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
23.09.2014, 19:53
DrOffset, поторопился, не все проверил: возникают ошибки при диапазоне типа (3,3) а так же если больше диапазонов использовать: Range{ 0, 0 }, Range{ 3, 4 }, Range{ 50, 100 } Не генерируются 50 и 3.

Код я ваш пока так и не осилил ввиду ужасного интернета, но потыркался оффлайн в переменных и циклах. единственное что понял:
при диапазоне типа (3,3) к sum ничего не прибавляется. Вот добавил пару костылей, вроде работает:
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
int random(std::mt19937 & mt, RangeT const & ...args)
{
    int sum = -1; //одна из тех единиц уже учтена и её надо нивелировать
    struct MRange
    {
        const int min, max;
        const int distance;
 
        MRange(int min, int max, int & sum)
            : min(min), max(max), distance(std::abs(min - max))
        {
            sum += distance + 1; //добавляем недостающую 1 каждый раз
        }
    } const ranges[] =
    {
        MRange(args.min, args.max, sum)...
    };
    int index = std::uniform_int_distribution<int>(0, sum)(mt);
    auto check_ = [&index](int ret, MRange const & x)
    {
        bool const f = ret > std::max(x.max, x.min);
        if (f)
        {
            index -= x.distance + 1; //метод тыка доказад, что тут тоже надо
        }
        return f;
    };
    size_t i = 0;
    int pos;
    do
    {
        pos = std::min(ranges[i].min, ranges[i].max) + index;
    } while (check_(pos, ranges[i++]));
 
    return pos;
}
1
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,822
23.09.2014, 21:32
Цитата Сообщение от КОП Посмотреть сообщение
DrOffset, поторопился, не все проверил: возникают ошибки при диапазоне типа (3,3)
Есть такое дело, спасибо.
Индекс терялся при переходе к следующему диапазону.
Вот пофиксил.
Кликните здесь для просмотра всего текста
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
54
55
56
57
58
59
60
61
62
63
64
65
66
struct Range
{
    int min;
    int max;
};
 
template <typename ...Args>
struct variadic_and
    : std::true_type
{};
 
template <typename First, typename ...Other>
struct variadic_and<First, Other...>
    : std::integral_constant<bool, First::value && variadic_and<Other...>::value>
{};
 
 
template <typename T, typename ...Args>
struct variadic_check
    : std::enable_if<
        (variadic_and<std::is_same<Args, T>...>::value && sizeof...(Args) > 0u)
      >
{};
 
template < typename ...RangeT
         , typename = typename variadic_check<Range, RangeT...>::type
>
int random(std::mt19937 & mt, RangeT const & ...args)
{
    size_t sum = sizeof...(args) - 1; // корректировка на смещение индекса на каждом переходе
                                      // к следующему диапазону, закладываем запас на количество смещений 
    struct MRange
    {
        int const min, max;
        int const distance;
 
        MRange(Range const & x, size_t & sum)
            : min(std::min(x.min, x.max))
            , max(std::max(x.max, x.min))
            , distance(std::abs(min - max))
        {
            sum += distance;
        }
    } const ranges[] = { MRange(args, sum)... };
 
    int index = std::uniform_int_distribution<int>(0u, sum)(mt);
    int pos;
 
    auto check_ = [&index, &pos](MRange const & r)
    {
        bool const f = pos > r.max;
        if(f)
        {
            index -= (r.distance + 1); // смещаем индекс (чтобы было с нуля)
        }
        return f;
    };
    int i = 0;
    do
    {
        pos = ranges[i].min + index;
    }
    while(check_(ranges[i++]));
 
    return pos;
}
0
63 / 64 / 11
Регистрация: 27.02.2013
Сообщений: 1,116
23.09.2014, 21:39  [ТС]
фига вы тут разошлись... все ниасилю, но для начала что такое "...args" ?
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,822
24.09.2014, 14:54
КОП, проблема была из-за того, что при переходе к след. диапазону не учитывалось, что индекс начинается с нуля. После того как мы это учили (в лямбде) наша последовательность съехала, т.к. получилось, что крайний индекс стал меньше на количество переходов. Поэтому нужно было добавить в начале это количество, что компенсировать верхний предел последнего диапазона. В случае, когда диапазон один, никакого дополнения не нужно, т.к. и переходов у нас нет (для этого там <кол-во аргументов> - 1).

Добавлено через 3 минуты
Цитата Сообщение от GetHelp Посмотреть сообщение
но для начала что такое "...args" ?
Это так называемый parameter pack. Это аргументы шаблона с переменным количеством аргументов. Они там сидят
Читай тут, ну и тут.

Добавлено через 17 часов 8 минут
Кстати, если диапазоны известны на этапе компиляции, то можно серьезно сократить
результирующий код и увеличить быстродействие, фактически отказавшись от хранения
данных о диапазонах и убрав циклы (засчет переноса некоторой части вычислений в compile-time).
Результирующий код может выглядеть примерно так:
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
//...............
 
template <int Min, int Max>
struct ct_range
{
    static constexpr int min() { return Min < Max ? Min : Max; }
    static constexpr int max() { return Max > Min ? Max : Min; }
    static constexpr int distance() { return ct_abs(min() - max()); }
};
 
//...................
 
template <typename ...RangesT
        , typename = typename is_template_of_check<ct_range, RangesT...>::type>
int random1(std::mt19937 & mt)
{
    return ct_select_range_value<RangesT...>(
                    std::uniform_int_distribution<int>(
                        0u
                      , sizeof...(RangesT) - 1 + ct_range_sum<RangesT...>()
                    )(mt)
                );
}
 
int main()
{
    std::mt19937 mt(static_cast<unsigned>(std::time(nullptr)));
 
    std::map<int, int> m;
 
    for(int i = 0; i < 10000; ++i)
    {
        ++m[random1<ct_range<0, 0>, ct_range<3, 4>, ct_range<50, 100>>(mt)];
    }
    for(auto && v : m)
    {
        printf("%d generated %d times\n", v.first, v.second);
    }
}
В моем случае(GCC 4.8.1) ушли все циклы, память под диапазоны не выделяется.
Код стал фактически эквивалентен такому (для случая [0;0], [3;4], [50;100]):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int rand2(std::mt19937 & mt)
{
     int const index = std::uniform_int_distribution<int>(0, 53/*51 + (3 - 1)*/)(mt);
 
/*0*/if(0/*min*/ + (index - 0/*distance*/) > 0 /*max*/)
     {
/*1*/    if(3/*max*/ + (index - (1/*distance*/)) > 4 /*max*/)
         {
/*2*/        if(50/*min*/ + (index - (50/*distance*/ + 1/*prev distance*/ + 1/*corr*/)) > 100 /*max*/)
             {
                 ; // сюда мы никогда не попадем по условию
             }
             return 50/*min*/ + (index - (1/*distance*/ + 2/*corr*/)); /*2*/
         }
         return 3/*min*/ + (index - (0/*distance*/ + 1/*corr*/));      /*1*/
     }
     return 0/*min*/ + index;                                          /*0*/
}
Расписано для понятности, все вычисления явных констант естественно не будут производиться в runtime.

Весь код
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
constexpr int ct_abs(int a) { return a < 0 ? -a : a; }
 
template <int Min, int Max>
struct ct_range
{
    static constexpr int min() { return Min < Max ? Min : Max; }
    static constexpr int max() { return Max > Min ? Max : Min; }
    static constexpr int distance() { return ct_abs(min() - max()); }
};
 
template <typename RangeT>
constexpr size_t ct_range_sum()
{
    return RangeT::distance();
}
 
template <typename RangeT
        , typename ...RangesT
        , typename = typename std::enable_if<(sizeof...(RangesT) > 0)>::type>
constexpr size_t ct_range_sum()
{
    return RangeT::distance() + ct_range_sum<RangesT...>();
}
 
template <typename RangeT>
constexpr int ct_select_range_value(int index)
{
    return RangeT::min() + index;
}
template <typename RangeT
        , typename ...RangesT
        , typename = typename std::enable_if<(sizeof...(RangesT) > 0)>::type>
constexpr int ct_select_range_value(int index)
{
    return RangeT::min() + index > RangeT::max()
           ? ct_select_range_value<RangesT...>(index - (RangeT::distance() + 1))
           : RangeT::min() + index;
}
 
// helper
template <typename ...Args>
struct variadic_and
    : std::true_type
{};
 
template <typename First, typename ...Other>
struct variadic_and<First, Other...>
    : std::integral_constant<bool, First::value && variadic_and<Other...>::value>
{};
 
// is template has instance of I
template <template <int, int> class T, typename I>
struct is_template_of
    : std::false_type
{ };
template <template <int, int> class T, int A, int B>
struct is_template_of<T, T<A, B>>
    : std::true_type
{ };
 
// is template has instance of I (variadic)
template <template <int, int> class T, typename ...Args>
struct is_template_of_check
    : std::enable_if<
       (variadic_and<is_template_of<T, Args>...>::value && sizeof...(Args) > 0u)
      >
{};
 
template <typename ...RangesT
        , typename = typename is_template_of_check<ct_range, RangesT...>::type>
constexpr int random1(std::mt19937 & mt)
{
    return ct_select_range_value<RangesT...>(
                    std::uniform_int_distribution<int>(
                        0u
                      , sizeof...(RangesT) - 1 + ct_range_sum<RangesT...>()
                    )(mt)
                );
}
 
int main()
{
    std::mt19937 mt(static_cast<unsigned>(std::time(nullptr)));
 
    std::map<int, int> m;
 
    for(int i = 0; i < 10000; ++i)
    {
        ++m[random1<ct_range<0,0>,ct_range<3,4>,ct_range<50,100>>(mt)];
    }
    for(auto && v : m)
    {
        printf("%d generated %d times\n", v.first, v.second);
    }
}


Кстати, у этой реализации осталась одна багофича. Если задать два одинаковых диапазона или частично
пересекающиеся, то числа из них будут генерироваться во столько раз чаще, сколько пересечений указано.
Можно починить, трансформировав диапазоны из аргументов в другие, с исключением пересечений.
А можно и не чинить, вдруг из этого можно будет получить како-либо полезный case
4
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
24.09.2014, 14:54

Рандомное проставление и суммирование целых чисел в ячейках в выборных диапазонах в Excel
Доброго времени суток! За ранее извиняюсь если не правильно обозвал тему и за орфографические ошибки =( Я не шарю в программировании...

Дать программе возможность самостоятельно выбрать число из нескольких введенных пользователем
Есть поля для ввода текста и есть кнопка рядом. Я допустим пишу в поле ввода текст допустим ну то есть повторяю, например, 1 потом 5 потом...

Подсчёт количества текстового значения ячейки в нескольких диапазонах
Помогите пожалуйста с формулой подсчёта... При подсчёте в одном диапазоне я использовал формулу =СЧЁТЕСЛИМН($B$3:$J$19;B22). В ячейке В22...

Как сделать, чтобы random работал в нескольких диапазонах?
Нужно отобразить в одном массиве цифры и буквы в случайном порядке и потом использывать группировку элементов массива. Уже на первом...

Задать рандомное направление шара
Необходимо задать рандомное направление шара, подскажите как это делать


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

Или воспользуйтесь поиском по форуму:
45
Ответ Создать тему
Новые блоги и статьи
Программа для com-порта
Uhbif79 05.06.2026
Всем привет, давно хотел изучить Qt, начинал, бросал, потом снова начинал. И сейчас вот смог написать свою первую программу. До этого имел опыт программирования микроконтроллеров, писал прошивки на. . .
Транскрипция 55-минутного видео через Whisper: WhisperDesktop облажался, спас Google Colab[
anaschu 01.06.2026
Понадобилось получить текст из свежезагруженного видео на YouTube. Казалось бы, задача на пять минут. Заняла полтора часа. Делюсь опытом — может кому пригодится последовательность решений. . . .
21 мат мед. Планы на развитие модели здравоСохранения
anaschu 01.06.2026
AnyLogic: план развития симуляционной модели рабочего коллектива — динамический абсентеизм, реальные данные, три сценария сравнения Продолжаю серию постов о дискретно-событийной модели рабочего. . .
20. Мат мед. Абсентеизм как отдельный тип простоя
anaschu 29.05.2026
Апдейт модели: исправленные баги, абсентеизм и новые механизмы Продолжаю развивать ранее описанную модель рабочего коллектива на AnyLogic. За последние несколько дней был проведён серьёзный. . .
19. здоровье, усталость и психотип работника влияют на производительность предприятия, и наоборот, производительность на здоровье, усталось и психотип
anaschu 28.05.2026
Дискретно-событийная модель рабочего коллектива на AnyLogic: здоровье, выгорание, психотипы и микростимуляция Привет, коллеги. Хочу поделиться итогами нескольких недель работы над симуляционной. . .
"Прокси" для последовательного порта
Eddy_Em 28.05.2026
Эту штуку написал я достаточно давно. Но сейчас вот понадобилось настроить датчик грозы, но при этом не отключать его от "метеодемона". Соответственно, надо запустить этот "прокси": метеодемон будет. . .
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru