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

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

22.09.2014, 22:00. Показов 5154. Ответов 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
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
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
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
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
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
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
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru