Генерация случайных чисел в 1С:Предприятие — задача, с которой сталкиваются разработчики при создании тестовых данных, симуляции бизнес-процессов или реализации игровых механик внутри корпоративных систем. В отличие от классических языков программирования, где для этого есть стандартные библиотеки (например, Math.random() в JavaScript или модуль random в Python), в 1С подходы зависят от версии платформы, требований к качеству случайности и контекста использования.
В этой статье мы разберём 5 рабочих методов генерации случайных чисел — от встроенных функций до реализации алгоритма Мерсенна-Твистера на встроенном языке. Вы узнаете, как избежать типичных ошибок (например, предсказуемости последовательностей), какие нюансы учитывать при работе с 1С:Предприятие 8.2 и 8.3, и когда стоит использовать внешние компоненты для криптографически безопасных решений. Особое внимание уделим генерации уникальных случайных значений без повторений — актуальной задаче для создания тестовых справочников или лотерейных механизмов.
1. Встроенные функции 1С для генерации случайных чисел
Начнём с самого простого: платформа 1С:Предприятие предоставляет две базовые функции для работы со случайностью — СлучайноеЧисло() и СлучайнаяСтрока(). Они доступны во всех конфигурациях без дополнительных настроек, но имеют ограничения, о которых важно знать.
Функция СлучайноеЧисло(Максимум) возвращает псевдослучайное целое число в диапазоне от 0 до Максимум-1. Например, СлучайноеЧисло(100) может вернуть значение от 0 до 99. Главный недостаток — предсказуемость последовательности при повторных запусках программы, так как алгоритм инициализируется фиксированным seed-значением (зависит от времени запуска системы).
- ✅ Простота использования:
Результат = СлучайноеЧисло(1000); - ⚠️ Предсказуемость: последовательность повторится при перезапуске 1С.
- 🔄 Диапазон: только целые числа, верхняя граница не включается.
- 📊 Применение: тестовые данные, простые симуляции.
Для генерации случайных строк используется СлучайнаяСтрока(Длина), которая возвращает строку заданной длины из символов латинского алфавита (заглавные и строчные буквы). Пример:
Сообщить(СлучайнаяСтрока(8)); // Пример вывода: "xK9pLmQ2"
⚠️ Внимание: В 1С:Предприятие 8.2 функция СлучайнаяСтрока() может выдавать повторяющиеся символы чаще, чем в 8.3. Для критических задач проверяйте уникальность результатов.
2. Алгоритм на основе времени: повышаем непредсказуемость
Чтобы избежать повторения последовательностей при перезапуске 1С, можно использовать текущее время в качестве seed-значения. Для этого подойдёт функция ТекущаяДата() или ТекстВВремя() в комбинации с математическими операциями.
Пример кода для генерации числа от 1 до 100 с учётом миллисекунд:
ТекущееВремя = ТекущаяДата();
Миллисекунды = Число(Формат(ТекущееВремя, "SS.ffff")) * 1000;
СлучайныйSeed = Миллисекунды + ДеньНедели(ТекущееВремя);
Результат = (СлучайныйSeed % 100) + 1;
- ⏱️ Зависимость от времени: каждый запуск даёт разные результаты.
- 🔢 Диапазон: требуется ручная корректировка (например,
% 100для ограничения до 100). - ⚠️ Ограничение: при быстром последовательном вызове (например, в цикле) значения могут повторяться.
Для более равномерного распределения можно комбинировать время с другими динамическими параметрами, например, с УникальныйИдентификатор() или данными сессии:
Seed = ТекстВЧисло(Прав(Формат(ТекущаяДата(), "ДФ=yyyyMMddhhmmss.ffff"), 10)) +
ТекстВЧисло(Прав(УникальныйИдентификатор(), 8));
Ранд = Новый СлучайныеЧисла(Seed);
3. Класс "СлучайныеЧисла": объектный подход
Начиная с версии 1С:Предприятие 8.3.6, в платформе появился специализированный класс СлучайныеЧисла, который позволяет гибко настраивать генерацию. Этот класс поддерживает:
- 🎲 Инициализацию пользовательским seed-значением.
- 📏 Генерацию чисел в произвольном диапазоне (включая вещественные).
- 🔄 Перемешивание массивов.
Пример использования:
Генератор = Новый СлучайныеЧисла(ТекстВЧисло(Формат(ТекущаяДата(), "ДФ=yyyyMMddhhmmss")));
// Получаем число от 10 до 20 (включительно)
СлучайноеЗначение = Генератор.Получить(10, 20);
// Перемешиваем массив
МассивЧисел = Новый Массив;
МассивЧисел.Добавить(1);
МассивЧисел.Добавить(2);
МассивЧисел.Добавить(3);
Генератор.Перемешать(МассивЧисел);
Преимущества класса СлучайныеЧисла:
| Характеристика | Описание |
|---|---|
| Контроль seed | Можно фиксировать начальное значение для воспроизводимости (например, для тестов). |
| Типы чисел | Поддерживает целые (Получить()) и вещественные (ПолучитьВещественное()) числа. |
| Производительность | Быстрее, чем ручная реализация алгоритмов на встроенном языке. |
| Дополнительные функции | Перемешивание массивов, выбор случайного элемента из коллекции. |
⚠️ Внимание: В версиях 1С:Предприятие 8.3.5 и ниже класс СлучайныеЧисла отсутствует. Для них используйте альтернативные методы из этой статьи.
4. Реализация алгоритма Мерсенна-Твистера на встроенном языке
Если вам нужны высококачественные псевдослучайные числа с большим периодом повторения (например, для статистического моделирования), можно реализовать алгоритм Мерсенна-Твистера (MT19937) непосредственно в 1С. Этот алгоритм используется в многих стандартных библиотеках (например, в Python или C++) и обеспечивает период повторения 2^19937 - 1.
Ниже приведён упрощённый вариант реализации (полная версия занимает ~200 строк кода):
// Инициализация генератора
Процедура ИнициализироватьМТ(Seed)
MT = Новый Массив(624);
MT[0] = Seed;
Для i = 1 По 623 Цикл
MT[i] = 1812433253 * (MT[i-1] Xor (MT[i-1] >> 30)) + i;
КонецЦикла;
КонецПроцедуры
// Получение следующего случайного числа
Функция СлучайноеМТ()
Если индексMT >= 624 Тогда
// Перемешивание массива (упрощённо)
Для i = 0 По 623 Цикл
y = (MT[i] And 0x80000000) + (MT[(i+1) % 624] And 0x7FFFFFFF);
MT[i] = MT[(i+397) % 624] Xor (y >> 1);
Если (y % 2) = 1 Тогда
MT[i] = MT[i] Xor 2567483615;
КонецЕсли;
КонецЦикла;
индексMT = 0;
КонецЕсли;
y = MT[индексMT];
y = y Xor (y >> 11);
y = y Xor ((y << 7) And 2636928640);
y = y Xor ((y << 15) And 4022730752);
y = y Xor (y >> 18);
индексMT = индексMT + 1;
Возврат y;
КонецФункции
Особенности реализации:
- 🧮 Точность: требует аккуратной работы с побитовыми операциями (
Xor, сдвиги). - ⚡ Производительность: медленнее встроенных функций, но качественнее.
- 🔧 Настройка: можно сохранять/восстанавливать состояние генератора.
Полный код алгоритма Мерсенна-Твистера
Для полноценной реализации потребуется добавить обработку 32-битных чисел, корректные константы и методы для генерации чисел в заданном диапазоне. Полный код занимает ~200 строк и включает процедуры инициализации, перемешивания и выдачи чисел. Пример можно найти в открытых репозиториях 1С (например, на GitHub в проектах с математическими библиотеками).
5. Внешние компоненты для криптографически безопасных чисел
Если вам нужны криптографически стойкие случайные числа (например, для генерации паролей, токенов или ключей шифрования), встроенные механизмы 1С не подходят. В таких случаях используют:
- 🔐 CryptoAPI (через COM-объект
CAPICOMилиSystem.Security.Cryptographyв .NET). - 📦 Специализированные внешние компоненты (например, 1C:Enterprise Cryptography Extension).
- 🌐 Вызов внешних сервисов (например,
random.orgчерез HTTP-запросы).
Пример использования CAPICOM для генерации криптографически безопасного числа:
Попытка
Crypto = Новый COMОбъект("CAPICOM.Utilities.1");
СлучайныеБайты = Crypto.GetRandom(4, 0); // 4 байта = 32-битное число
Результат = ТекстВЧисло(СтрокаИзБайтов(СлучайныеБайты));
Исключение
Сообщить("Ошибка CryptoAPI: " + ОписаниеОшибки());
КонецПопытки;
⚠️ Внимание: Использование CAPICOM требует установленного компонента на клиентских машинах и может не работать в веб-клиенте или на сервере без дополнительных настроек.
Альтернатива — использование .NET-объектов (доступно в управляемых формах):
RNGCrypto = Новый NETОбъект("System.Security.Cryptography.RandomNumberGenerator");
Байты = Новый Массив(4); // 4 байта для 32-битного числа
RNGCrypto.GetBytes(Байты);
Результат = Байты[0] + (Байты[1] 256) + (Байты[2] 65536) + (Байты[3] * 16777216);
6. Генерация уникальных случайных чисел без повторений
Частая задача — сгенерировать набор уникальных случайных чисел (например, для розыгрыша призов или создания тестовых документов с уникальными номерами). Здесь важно избежать коллизий и обеспечить равномерное распределение.
Алгоритм решения:
- Создать массив всех возможных значений.
- Перемешать его с помощью
СлучайныеЧисла.Перемешать(). - Извлекать элементы последовательно.
Пример кода для генерации 10 уникальных чисел от 1 до 100:
Генератор = Новый СлучайныеЧисла();
ИсходныйМассив = Новый Массив;
Для i = 1 По 100 Цикл
ИсходныйМассив.Добавить(i);
КонецЦикла;
Генератор.Перемешать(ИсходныйМассив);
УникальныеЧисла = Новый Массив;
Для i = 1 По 10 Цикл
УникальныеЧисла.Добавить(ИсходныйМассив[i-1]);
КонецЦикла;
Для больших диапазонов (например, 1 из 1 000 000) этот метод неэффективен. В таких случаях используйте:
- 🔢 Алгоритм Фишера-Йетса для перемешивания "на лету".
- 📊 Хеш-таблицы для отслеживания использованных значений.
- 🔄 Рекурсивный перебор с проверкой уникальности (медленно, но просто).
☑️ Проверка уникальности случайных чисел
7. Типичные ошибки и как их избежать
При работе со случайными числами в 1С разработчики часто сталкиваются с следующими проблемами:
- Предсказуемость последовательностей: если не инициализировать генератор уникальным seed-значением, числа будут повторяться при перезапуске 1С.
⚠️ Внимание: В 1С:Предприятие 8.2 функция
СлучайноеЧисло()сбрасывает последовательность при каждом вызовеНовый Сеанс. Используйте глобальные переменные для хранения состояния генератора. - Неравномерное распределение: при использовании операции
%(остаток от деления) для ограничения диапазона могут возникать искажения. Например,СлучайноеЧисло(100) % 50даст числа от 0 до 49, но с разной вероятностью. - Переполнение типов: при работе с большими числами (например,
СлучайноеЧисло(2^31)) возможны ошибки из-за ограничений типаЧислов 1С. - Блокировки в многопользовательском режиме: если генератор используется в транзакциях или на сервере, требуется синхронизация, чтобы избежать коллизий.
Рекомендации по избежанию ошибок:
| Проблема | Решение |
|---|---|
| Повторяющиеся последовательности | Используйте ТекущаяДата() или УникальныйИдентификатор() для инициализации seed. |
| Неравномерное распределение | Для диапазона [A, B] используйте формулу: A + СлучайноеЧисло(B - A + 1). |
| Переполнение чисел | Разбивайте большие диапазоны на поддиапазоны или используйте строковые представления. |
| Многопользовательские конфликты | Выносите генерацию на клиент или используйте блокировки (НачатьТранзакцию()). |
Для тестирования равномерности распределения сгенерируйте 10 000 чисел в диапазоне 1–10 и постройте гистограмму в Excel. Если частоты значений отличаются более чем на 10%, проверьте алгоритм генерации.
8. Практическое применение: примеры использования
Рассмотрим реальные сценарии, где генерация случайных чисел полезна в 1С:
- 📊 Тестовые данные: заполнение справочников случайными значениями для отладки отчётов.
Для i = 1 По 100 ЦиклНовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
НовыйЭлемент.Наименование = "Товар_" + СлучайнаяСтрока(5);
НовыйЭлемент.Цена = СлучайноеЧисло(10000) / 100;
НовыйЭлемент.Записать();
КонецЦикла;
- 🎲 Лотереи и розыгрыши: случайный выбор победителей из списка участников.
Участники = Новый Массив;Участники.Добавить("Иванов");
Участники.Добавить("Петров");
Участники.Добавить("Сидорова");
Генератор = Новый СлучайныеЧисла();
Победитель = Участники[Генератор.Получить(0, Участники.ВГраница())];
- 🔒 Генерация паролей: создание временных доступов для пользователей.
Функция СгенерироватьПароль(Длина = 8)Символы = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Результат = "";
Генератор = Новый СлучайныеЧисла();
Для i = 1 По Длина Цикл
Результат = Результат + Сред(Символы, Генератор.Получить(1, СтрДлина(Символы)), 1);
КонецЦикла;
Возврат Результат;
КонецФункции
- 📈 Моделирование бизнес-процессов: имитация случайных событий (например, отказов оборудования).
Для критических задач (финансовые расчёты, шифрование) всегда используйте внешние криптографические генераторы. Встроенные функции 1С не обеспечивают достаточную энтропию для безопасности.
FAQ: Частые вопросы по генерации случайных чисел в 1С
Можно ли в 1С сгенерировать действительно случайное число, а не псевдослучайное?
Нет, в чистом виде 1С не поддерживает генерацию истинно случайных чисел (требуется аппаратный источник энтропии). Для криптографических задач используйте внешние компоненты, такие как CryptoAPI или специализированные библиотеки.
Почему при использовании СлучайноеЧисло() в цикле значения повторяются?
Это происходит из-за того, что функция инициализируется фиксированным seed-значением при старте сеанса. Решение: используйте класс СлучайныеЧисла с динамическим seed (например, на основе времени) или добавляйте задержку между вызовами.
Как сгенерировать случайную дату в заданном диапазоне?
Преобразуйте диапазон дат в количество секунд и используйте генератор чисел:
Начало = '20200101';
Конец = '20231231';
СлучайныеСекунды = СлучайноеЧисло(Конец - Начало + 1);
СлучайнаяДата = Начало + СлучайныеСекунды;
Учтите, что Конец - Начало возвращает количество дней, а не секунд. Для точности используйте ДобавитьСекунду().
Можно ли использовать генератор случайных чисел в фоновых заданиях?
Да, но учитывайте, что в фоновых заданиях 1С:Предприятие 8.3 может сбрасывать состояние глобальных переменных. Сохраняйте seed-значение генератора в базе данных или передавайте его через параметры задания.
Как проверить качество генератора случайных чисел?
Для тестирования используйте статистические тесты:
- Сгенерируйте большую выборку (например, 10 000 чисел).
- Постройте гистограмму распределения.
- Проверьте равномерность с помощью критерия хи-квадрат.
- Используйте тесты на случайность (например, тест покером или серий).
Для автоматизации можно интегрировать 1С с Python через COM-соединение и использовать библиотеку scipy.stats.