Заказы на доработку 1С (сервис удаленной работы)

Хранилище

База знаний
Бесплатные отчеты, обработки, конфигурации, внешние компоненты для 1С Статьи, описание работы, методики по работе с 1С

Здравствуйте, гость ( Вход | Зарегистрироваться )



> Генератор случайных чисел в 1С , Подборка алгоритмов для генерации случайных чисел и перемешивания.          
Vofka Подменю пользователя
сообщение 09.02.11, 20:39
Сообщение #1

У нас здесь своя атмосфера...
***********
Группа: Основатель
Сообщений: 13948
Из: Киев
Спасибо сказали: 4514 раз
Рейтинг: 3635.6

Ключевые слова: генератор, случайный, чисел, число, алгоритм, random, randomize, распределение, равномерное, лотерея


insider:

Вот не думал, что в 1С пригодится, а вот на Вам.. клиенты решили акцию провести, типа "собери крышечки", только собирать нужно слова, кто правильное слово из своего набора букв соберет - тот и выиграл. Задача вообщем казалось бы простая: имеется алфавит, имеется некое слово, которое нужно собрать, например "коньяк", в нем 6 букв, как видите.

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

Дополнительное условие: все эти варианты (правильные и нет) нужно пронумеровать, чтобы при получении "призовой" карточки можно было бы сверить номер (а был ли такой).

Казалось бы, причем здесь 1С? Так вот учет этих карточек и призов желают добавить в учетную прогу, ну и заодно попросили нагенерить случайных комбинаций (ну не вручную же их сочинять).
Для каждой акции комбинации генерятся один раз, потом по ним изготавливают карточки, т.е. в следующий раз слово будет другое и т.д.

В общем задача сводится к следующему:
1. Генерить случайные числа, желательно с большим разбросом.
2. По числу вычислять комбинацию букв (т.е. найти какое-то соответствие между возможныи комбинациями и их номерами).
3. Пункт обратный предыдущему - по слову проверять номер комбинации.

Учитывая, что на форуме периодически задаются вопросы по генераторам случайных чисел и т.п. - решил поделиться. К моему стыду, эта занимательная арифметика занимала меня последние три часа.

Решение:
1. т.к. генератор от avb и NS давал маленький разброс случайных чисел, пришлось поюзать немного другой алгоритм:

function Random()
    if emptyvalue(randSeed) = 1 then
        randSeed = _getperformancecounter();
    endif;                      
    
    randSeed=(a*randSeed+c)%m;
    return randSeed;
endfunction


Здесь:
a=1664525; c=1013904223; m=4294967296;
последняя переменная - 2 в 32-й степени, две другие - рекомендуемые для таких целей коэффициенты

Ограничение по максимальному значению 2^32 выбрано исходя из максимального кол-ва комбинаций (для обрезанного алфавита в 28 букв и слов по 7, т.к. в реальной задаче их именно 7, общее число комбинаций составит 28^7, таким образом выбранное ограничение лежит примерно посередине интервала, что вполне достаточно для выборки 20-30 тыс. вариантов)

Нам также понадобится еще одна вспомогательная функция - возведение в целочисленную положительную степень:

Функция Степень(Знач а,Знач б, Рез=1)
    Если б>0 Тогда
        Рез=Рез*а;    
        б=б-1;
        Степень(а,б,Рез);
        Возврат Рез;
    Иначе
        Возврат Рез;
    КонецЕсли;
КонецФункции


Здесь: а - основание степени, б - показатель степени, Рез - результат


2. Выявить зависимость между последовательно расположенными комбинациями, оказалось на удивление простым:

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

Для нашей системы счисления, основанием будут являться степени шестерки, т.е. для получения первого слева разряда, необходимо разделить номер нашей комбинации на 6 в 5-й степени, затем остаток от деления - на 6 в 4-й и т.д.

Таким образом, получаем набор из шести чисел, которые по сути являются порядковыми номерами букв в нашем алфавите.

Получившийся код:

Функция ПолучитьСимволы(Поз,ТекСимв=1,СимСтр="")
    Если ТекСимв<к Тогда
        Делитель=Степень(СтрДлина(Буквы),к-ТекСимв);
        ТекОст=Поз%Делитель;
        СимСтр=Строка(СимСтр)+Сред(Буквы,Цел(Поз/Делитель+?(ТекОст>0,1,0)),1);    
        ПолучитьСимволы(ТекОст,ТекСимв+1,СимСтр);
        Возврат СимСтр;
    Иначе          
        СимСтр=СимСтр+Сред(Буквы,(?(Поз=0,СтрДлина(Буквы),Поз)),1);
        Возврат СимСтр;
    КонецЕсли;
КонецФункции


Здесь:
Поз - номер комбинации (псевдослучайное число)
ТекСимв - текущий обрабатываемый символ
СимСтр - резльтирующая строка символов
Буквы = строка, содержащая буквы алфавита в стандартном порядке ("абв...юя")
к - число символов в искомом слове (в данном случае = 6)

3. Обратное преобразование также тривиально:

Функция ПолучитьКомбинацию(Слово,ТекСимв=0,Поз=0)
    НомСимв=Найти(Буквы,Сред(Слово,к-ТекСимв,1));
    Если ТекСимв>0 Тогда
        Если ТекСимв<к Тогда
            Поз=Поз+(НомСимв-1)*Степень(СтрДлина(Буквы),ТекСимв);
            ПолучитьКомбинацию(Слово,ТекСимв+1,Поз);
        Иначе
            Возврат Поз;
        КонецЕсли;
    Иначе
        Поз=?(НомСимв=СтрДлина(Буквы),0,НомСимв);
        ПолучитьКомбинацию(Слово,ТекСимв+1,Поз);
        Возврат Поз;
    КонецЕсли;
КонецФункции


Здесь:
Слово - комбинация символов, номер которой ищем
ТекСимв - текущий обрабатываемый символ (по сути разряд шестиричного "числа")
Поз - искомый номер комбинации

//********************************************************************************
************************

Премешать N чисел:

Для а=1 по N цикл 
массив[а]=а;
Конеццикла;
Для а=1 по N-1 цикл
Сл=Случ(а,N);// Целое случайное число в интервале [а..N]
К=массив[а];
массив[а]=массив[Сл];
массив[Сл]=К;
КонецЦикла;


//********************************************************************************
************************

Sc    =    CreateObject("MSScriptControl.ScriptControl"); 
Sc.language    =    "VBscript";
sc.executeStatement("randomize");  
оноВотТутаБудет=Sc.eval("rnd");


Как сделать чтобы числа выбирались произвольно от 1 до 100?

Ранд=_GetPerformanceCounter()%(100+1);


похоже это лучшеее

//********************************************************************************
************************

В 8.0 для получения случайных чисел можно использовать встроенный генератор GUID.
Вот пример простенькой функции:

//только для целых чисел
Функция ПолучитьСлучайноеЧисло(Мин,Макс)
    
    //вместо Randomize
    Для н = 1 По 100 Цикл
        Уник = Новый УникальныйИдентификатор;
    КонецЦикла;
    
        //генерируем GUID
    Уник = СокрЛП(Новый УникальныйИдентификатор);

        //оставляем только цифры
    Уник = СтрЗаменить(Уник,"-","");
    Уник = СтрЗаменить(Уник,"a","");
    Уник = СтрЗаменить(Уник,"b","");
    Уник = СтрЗаменить(Уник,"c","");
    Уник = СтрЗаменить(Уник,"d","");
    Уник = СтрЗаменить(Уник,"e","");
    Уник = СтрЗаменить(Уник,"f","");

    //знаменатель должен иметь такое же количество нулей + 1
    Знаменатель = 10;
    Для н = 2 По (СтрДлина(СтрЗаменить(Уник,Символы.НПП,""))) Цикл
        Знаменатель = Знаменатель * 10;
    КонецЦикла;
    
    Случ = Число(Уник) / Знаменатель; //здесь получается дробное случайное число от 0 до 1
    
    //преобразуем его в случайное число из заданного интервала, округляем до целого
    ЧислоИзИнтервала = Мин(Макс(Окр(Мин + (Макс-Мин)*Случ),Мин),Макс);
    
    Возврат ЧислоИзИнтервала;

КонецФункции


Взято [необходимо зарегистрироваться для просмотра ссылки]

//********************************************************************************
************************

ЗЫ. я набрёл на эту статью в поисках генератора случайных чисел. Так вот для себя я выбрал вариант
Ранд=_GetPerformanceCounter()%(100+1);

Спасибо сказали: mister-x, telemost,

mister-x Подменю пользователя
сообщение 10.02.11, 12:37
Сообщение #2

...
Иконка группы
Модератору Про1С (за заслуги в 2011 году)
Группа: Местный
Сообщений: 3477
Из: Тернопіль
Спасибо сказали: 1417 раз
Рейтинг: 0

Ще б знати, що було по цьому посиланню [необходимо зарегистрироваться для просмотра ссылки].

Vofka Подменю пользователя
сообщение 10.02.11, 12:58
Сообщение #3

У нас здесь своя атмосфера...
***********
Группа: Основатель
Сообщений: 13948
Из: Киев
Спасибо сказали: 4514 раз
Рейтинг: 3635.6

mister-x, где логика? Узнать не знаю что, но узнать что было там?

mister-x Подменю пользователя
сообщение 10.02.11, 14:56
Сообщение #4

...
Иконка группы
Модератору Про1С (за заслуги в 2011 году)
Группа: Местный
Сообщений: 3477
Из: Тернопіль
Спасибо сказали: 1417 раз
Рейтинг: 0

Цитата
mister-x, где логика? Узнать не знаю что, но узнать что было там?

Ось, шо я мав на увазі:
Цитата
Взято [необходимо зарегистрироваться для просмотра ссылки]
по цьому посиланню є таке:
Цитата
Библиотека мат. функций, где есть генератор сл. чисел:
[необходимо зарегистрироваться для просмотра ссылки]

[необходимо зарегистрироваться для просмотра ссылки]

от мене цікавило, що було за другим посиланням - оскілько воно вже не актуальне.

вибачте, можливо я не до кінця висловився - тепер поправив wink.gif

Библиотека мат. функций, где есть генератор сл. чисел.

Не нашли ответа на свой вопрос?
Зарегистрируйтесь и задайте новый вопрос.


Ответить Новая тема
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

RSS Текстовая версия Сейчас: 28.03.24, 20:32
1С Предприятие 8.3, 1С Предприятие 8.2, 1С Предприятие 8.1, 1С Предприятие 8.0, 1С Предприятие 7.7, Литература 1С, Общие вопросы по администрированию 1С, Методическая поддержка 1С - всё в одном месте: на Украинском 1С форуме!