К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как вычислить факториал в 1С

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

Факториал числа — это произведение всех натуральных чисел от 1 до заданного числа. Во встроенном языке 1С нет готовой функции для его вычисления, поэтому разработчику приходится реализовывать алгоритм самостоятельно: через цикл или рекурсию. Задача типична для учебных заданий, расчётов комбинаторики и проверки навыков программирования на собеседованиях.

Главная особенность факториала — чрезвычайно быстрый рост значений. Уже 20! равен 2 432 902 008 176 640 000, а 25! превышает 15 секстиллионов. Из-за ограничений на точность и разрядность чисел в 1С корректно вычислить факториал можно только для сравнительно небольших аргументов, и это нужно учитывать при проектировании функции.

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

Что такое факториал и где он нужен в 1С

Факториал неотрицательного целого числа N (обозначается N!) — произведение всех натуральных чисел от 1 до N включительно. По определению 0! = 1 и 1! = 1. Например, 5! = 1 × 2 × 3 × 4 × 5 = 120.

В прикладных решениях факториал встречается в комбинаторных расчётах: число перестановок, сочетаний и размещений. Это может понадобиться при оценке количества вариантов комплектации, в расчётах вероятностей, в механизмах генерации сочетаний номенклатуры или в интеграциях с математическими сервисами.

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

Базовый алгоритм: вычисление факториала циклом

Самый надёжный и предсказуемый способ — итеративный цикл. Переменная-аккумулятор инициализируется единицей, затем последовательно умножается на числа от 2 до N. Такой код легко читается, не зависит от глубины стека и просто отлаживается.

Функция Факториал(Число) Экспорт

Если Число < 0 Тогда

ВызватьИсключение "Факториал определён только для неотрицательных чисел";

КонецЕсли;

Результат = 1;

Для Сч = 2 По Число Цикл

Результат = Результат * Сч;

КонецЦикла;

Возврат Результат;

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

Обратите внимание на проверку отрицательного аргумента: факториал для отрицательных чисел не определён, и молчаливый возврат единицы в этом случае — скрытая ошибка. Лучше явно сообщить о недопустимом входном значении через исключение.

Цикл начинается с 2, а не с 1 — умножение на единицу не меняет результат, и лишняя итерация не нужна. Для входных значений 0 и 1 цикл не выполнится ни разу, и функция корректно вернёт 1.

Как добавить функцию в конфигурацию
  1. 1
    Создайте общий модуль (например, МатематикаСервер) или откройте существующий модуль прикладной логики
  2. 2
    Вставьте функцию Факториал с проверкой отрицательного аргумента и циклом умножения
  3. 3
    Если модуль серверный, убедитесь, что вызов происходит в серверном контексте
  4. 4
    Вызовите функцию из нужного места: Результат = МатематикаСервер.Факториал(5)
  5. 5
    Проверьте результат на контрольных значениях: 0! = 1, 5! = 120, 10! = 3628800

Рекурсивный вариант вычисления

Рекурсия — классический способ записи факториала: N! = N × (N−1)!, а базовый случай — 0! = 1. Код получается компактным и наглядно отражает математическое определение.

Функция ФакториалРекурсивно(Число)

Если Число < 0 Тогда

ВызватьИсключение "Факториал определён только для неотрицательных чисел";

КонецЕсли;

Если Число <= 1 Тогда

Возврат 1;

КонецЕсли;

Возврат Число * ФакториалРекурсивно(Число - 1);

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

У рекурсии есть принципиальное ограничение: каждый вызов занимает место в стеке вызовов. При большой глубине рекурсии платформа аварийно завершит выполнение с ошибкой переполнения стека. Для факториала это маловероятно из-за ограничений точности чисел (реальный предел аргумента наступает раньше), но как приём рекурсия в 1С применяется осторожно.

На практике для прикладного кода предпочтителен цикл: он не зависит от стека, быстрее выполняется и проще отлаживается. Рекурсивный вариант уместен в учебных целях или когда важна демонстрация самого определения.

Цикл или рекурсия

Итеративный цикл

Подходит для прикладного кода: не зависит от глубины стека, быстрее, проще отлаживается. Ограничение — только точность чисел

Рекурсия

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

Ограничения: почему большие факториалы считаются неверно

Числа в 1С имеют ограниченную точность: для типа «Число» максимальная разрядность ограничена (по умолчанию при определении реквизитов — до 38 знаков с учётом дробной части, в вычислениях встроенный язык оперирует числами с фиксированной точностью). Как только промежуточное произведение превышает допустимое число значащих цифр, старшие разряды сохраняются, а младшие теряются — результат становится приближённым или вовсе неверным.

Практический ориентир: точные значения факториала гарантированно получаются примерно до 20!–27! в зависимости от контекста вычислений и настроек точности. 20! содержит 19 цифр, 25! — уже 26 цифр. Дальше результат будет округлён, и доверять ему в расчётах нельзя.

Если задача требует точных больших факториалов (например, для криптографии или научных расчётов), встроенных средств 1С недостаточно. Варианты обхода: реализовать «длинную арифметику» через массивы цифр или строки, либо выполнять вычисление во внешнем компоненте, COM-объекте или через вызов внешнего сервиса.

Проверка результата и тестовые значения

После внедрения функции её нужно проверить на эталонных значениях. Достаточно нескольких контрольных точек, чтобы убедиться в корректности логики цикла и обработки граничных случаев.

Аргумент NОжидаемый результат N!Что проверяет
01Граничный случай, цикл не выполняется
11Граничный случай
5120Базовая логика умножения
103 628 800Корректность накопления произведения
202 432 902 008 176 640 000Работа на границе точности

Удобный способ быстрой проверки — вывести результат через Сообщить() в отладочной процедуре или выполнить вызов функции в консоли кода (внешней обработке для выполнения произвольного кода). Для автоматизированной проверки сравните возвращаемое значение с эталоном и зафиксируйте расхождение.

Заодно проверьте поведение на некорректных входных данных: отрицательное число должно приводить к понятному исключению, а не к молчаливому неверному ответу. Дробный аргумент стоит либо отклонять, либо явно приводить к целому через Цел() с документированием такого поведения.

Контрольные точки

Как проверить результат

Факториал(0) и Факториал(1)
Норма

Оба вызова возвращают 1

Тревожный признак

Возвращается 0 или ошибка — неверна инициализация аккумулятора

Факториал(5)
Норма

Результат равен 120

Тревожный признак

Другое значение — ошибка в границах цикла

Факториал(20)
Норма

2 432 902 008 176 640 000 без округления

Тревожный признак

Число округлено или в экспоненциальном виде — превышена точность

Факториал(-3)
Норма

Понятное исключение о недопустимом аргументе

Тревожный признак

Молча возвращается 1 — скрытая ошибка логики

Типичные ошибки при реализации

Первая частая ошибка — инициализация результата нулём вместо единицы. Умножение на ноль обнуляет весь результат, и функция всегда возвращает 0. Симптом заметен сразу на любом тестовом значении.

Вторая ошибка — неверные границы цикла: цикл «Для Сч = 1 По Число - 1» даёт факториал числа на единицу меньше, а обращение к функции с такой ошибкой в комбинаторных формулах даёт смещённые результаты, которые сложно отловить без эталонных значений.

Третья группа проблем — отсутствие контроля входных данных и диапазона. Отрицательные числа, дробные значения и аргументы выше предела точности должны обрабатываться явно. Также в рекурсивном варианте иногда забывают базовый случай (Число <= 1), и функция уходит в бесконечную рекурсию до переполнения стека и аварийного завершения.

Типичные ошибки
01
Инициализация результата нулём — функция всегда возвращает 0
02
Цикл до Число - 1 вместо Число — результат смещён на один факториал
03
Нет проверки отрицательного аргумента — молчаливый неверный ответ вместо исключения
04
Нет базового случая в рекурсии — переполнение стека и аварийное завершение сеанса
05
Игнорирование предела точности — приближённые значения попадают в прикладные расчёты

Применение: комбинаторные формулы и оптимизация

На практике факториал редко нужен сам по себе — чаще он входит в формулы сочетаний C(n, k) = n! / (k! × (n−k)!) и размещений. Здесь есть важная оптимизация: вычислять три больших факториала и делить их неэффективно и опасно с точки зрения точности. Число сочетаний выгоднее считать сокращённым произведением.

Функция ЧислоСочетаний(N, K)

Если K < 0 Или K > N Тогда

Возврат 0;

КонецЕсли;

Если K > N - K Тогда

K = N - K; // используем симметрию C(n,k) = C(n,n-k)

КонецЕсли;

Результат = 1;

Для Сч = 1 По K Цикл

Результат = Результат * (N - K + Сч) / Сч;

КонецЦикла;

Возврат Результат;

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

Такой подход держит промежуточные значения значительно меньше, чем прямое вычисление факториалов, и расширяет диапазон точных результатов. Дополнительный приём — использование симметрии сочетаний, которая сокращает число итераций.

Если функция факториала вызывается многократно в цикле с повторяющимися аргументами, имеет смысл кэшировать уже вычисленные значения в соответствии: это убирает повторные умножения и ускоряет пакетные расчёты.

В прикладных конфигурациях факториал почти всегда является частью формулы сочетаний или перестановок. Перед тем как писать отдельную функцию факториала, проверьте итоговую формулу: часто её можно переписать так, чтобы большие факториалы сократились, и тогда ограничение точности перестанет быть проблемой.
ПЗ
Практическое замечание
Итог

Что важно запомнить

В 1С факториал вычисляется собственной функцией: надёжнее всего — циклом с накоплением произведения. Обязательны проверки отрицательного аргумента и верхней границы из-за ограниченной точности чисел: точный результат гарантирован лишь для небольших N. Для комбинаторных формул используйте сокращённые произведения вместо прямого деления факториалов.

Частые вопросы

Есть ли встроенная функция факториала в 1С?

Нет, во встроенном языке платформы такой функции нет. Факториал реализуют самостоятельно — обычно циклом с накоплением произведения или рекурсией. Готовую функцию удобно разместить в общем модуле, чтобы использовать её из любого места конфигурации.

До какого числа можно точно вычислить факториал в 1С?

Точные значения гарантированно получаются примерно до 20!–27! в зависимости от контекста вычислений и разрядности чисел. Дальше младшие разряды теряются без предупреждения. Рекомендуется добавить в функцию проверку верхней границы аргумента и отказ от вычисления при её превышении.

Что вернёт факториал нуля и почему?

По математическому определению 0! = 1. Если функция написана с инициализацией результата единицей и циклом от 2 до N, то для нуля цикл просто не выполнится, и функция корректно вернёт 1 без дополнительных веток кода.

Что делать, если нужен факториал очень большого числа?

Встроенные числа 1С для этого не подходят. Варианты: реализовать длинную арифметику (хранение числа как массива или строки цифр с поразрядным умножением), использовать внешнюю компоненту или COM-объект, либо выполнять вычисление во внешнем сервисе и получать готовый результат.

Почему рекурсивная функция факториала падает с ошибкой?

Наиболее вероятная причина — отсутствие или неверное условие выхода из рекурсии (базовый случай Число <= 1). Без него вызовы продолжаются бесконечно, пока не исчерпается стек, и платформа аварийно завершает выполнение. Проверьте, что базовый случай стоит до рекурсивного вызова и корректно срабатывает.

Как посчитать число сочетаний без переполнения точности?

Не вычисляйте три факториала и не делите их напрямую. Используйте сокращённое произведение: C(n, k) считается циклом из k итераций с умножением на (n − k + i) и делением на i на каждом шаге. Промежуточные значения остаются намного меньше, и точный результат достижим для значительно больших n.