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

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

Как округлить число в меньшую сторону в 1С

Как округлить число в меньшую сторону в 1С: функции Цел(), Окр(), ВЫРАЗИТЬ в запросе, округление до копеек и целых упаковок. Примеры кода и типичные ошибки.

Во встроенном языке 1С нет отдельной функции «округлить вниз» вроде Floor из других языков, поэтому задача решается комбинацией штатных средств: Цел(), Окр() с указанием режима округления, приведением типа в запросе или настройкой форматирования при выводе. Выбор способа зависит от того, где выполняется округление — в коде модуля, в запросе, в формуле печатной формы или в пользовательских настройках отчёта.

Важно понимать разницу между тремя операциями, которые часто путают: округление до ближайшего целого (математическое), отсечение дробной части (усечение) и округление в меньшую сторону (floor). Для положительных чисел усечение и округление вниз совпадают, а для отрицательных — нет: усечение −2,7 даст −2, а округление в меньшую сторону должно дать −3. В учётных задачах 1С (количество упаковок, целые штуки при списании, расчёт скидок) чаще всего нужен именно floor, и смешение этих понятий приводит к копеечным расхождениям в проводках.

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

Функция Цел() — базовый способ отсечь дробную часть

Функция Цел(Число) возвращает целую часть числа, просто отбрасывая всё после запятой. Для положительных значений это и есть округление в меньшую сторону: Цел(17.95) вернёт 17, Цел(0.999) вернёт 0.

Типичный пример из торгового учёта — расчёт целого количества упаковок, которое можно отгрузить со склада:

ОстатокШтук = 100;

ШтукВУпаковке = 12;

ЦелыхУпаковок = Цел(ОстатокШтук / ШтукВУпаковке); // 8, а не 8.33

Подводный камень — отрицательные числа. Цел(-2.7) вернёт −2, потому что функция отсекает дробную часть по направлению к нулю, а не в меньшую сторону. Если в вашем алгоритме возможны отрицательные значения (сторно, корректировки, возвраты), это различие нужно учитывать обязательно.

Универсальный floor для положительных и отрицательных чисел

Если нужен строгий математический floor (всегда в меньшую сторону, независимо от знака), используйте небольшую формулу:

Функция ОкруглитьВниз(Число)

ЦелаяЧасть = Цел(Число);

Если Число < 0 И Число <> ЦелаяЧасть Тогда

Возврат ЦелаяЧасть - 1;

Иначе

Возврат ЦелаяЧасть;

КонецЕсли;

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

Проверка: ОкруглитьВниз(2.7) → 2, ОкруглитьВниз(-2.7) → −3, ОкруглитьВниз(-2) → −2. Условие Число <> ЦелаяЧасть защищает от лишнего вычитания единицы, когда число уже целое.

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

Округление вниз до нужного знака: копейки, десятые, десятки

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

// Вниз до копеек (двух знаков)

Результат = Цел(Сумма * 100) / 100;

// Вниз до десятых

Результат = Цел(Число * 10) / 10;

// Вниз до целых десятков

Результат = Цел(Число / 10) * 10;

Пример из практики: расчёт скидки, которую нельзя округлять в пользу покупателя. Цел(СуммаСкидки * 100) / 100 гарантирует, что копейка не «уедет» вверх, и сумма документа не превысит расчётную.

Учтите ограничение точности: при умножении больших чисел на 100 промежуточный результат может выйти за разумную разрядность типа Число, если она задана слишком малой в метаданных. Для денежных сумм обычно достаточно Число(15,2), но промежуточные вычисления в коде выполняются с полной точностью платформы, поэтому проблема возникает редко — в основном при записи результата в реквизит с жёсткой разрядностью.

bsl
// Округление вниз до произвольной точности
Функция ОкруглитьВнизДоТочности(Число, Точность)
    Множитель = Pow(10, Точность);
    Возврат Цел(Число * Множитель) / Множитель;
КонецФункции
// ОкруглитьВнизДоТочности(123.456, 2) -> 123.45

Функция Окр() и режимы округления

Штатная функция Окр(Число, Разрядность, РежимОкругления) по умолчанию округляет до ближайшего значения, причём 0,5 уходит вверх (в типовых конфигурациях применяется режим «0.5 как 1»). Это не округление вниз, и использовать Окр() без понимания режима — распространённая причина расхождений.

Третий параметр принимает значения системного перечисления РежимОкругления: Округление15как10 и Округление15как20. Первый округляет 0,5 вниз, второй — вверх. Однако ни один из них не даёт настоящий floor: Окр(2.7, 0) вернёт 3 в любом режиме, потому что 0,7 ближе к единице.

Поэтому правило простое: если требование — «всегда в меньшую сторону», Окр() не подходит, используйте Цел() или формулу с множителем. Окр() уместен, когда бизнес-правило звучит как «округлить до ближайшего», а «в меньшую сторону» касается только пограничного случая 0,5.

Сравнение способов

Цел(Число)

Отсечение дробной части к нулю. Подходит для положительных чисел, для отрицательных даёт не floor.

Цел() с поправкой на знак

Настоящий floor для любых чисел. Требует небольшой функции-обёртки.

Цел(Число * 10^N) / 10^N

Округление вниз до N знаков. Универсально для копеек и десятых.

Окр(Число, Разрядность, Режим)

Округление до ближайшего с управлением половинкой. Не является округлением вниз.

Округление вниз в запросах

В языке запросов 1С функции «округлить вниз» тоже нет, но есть приведение типа: ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 0)). При приведении к числу с нулевой разрядностью дробная часть отсекается — для положительных значений это округление вниз.

ВЫБРАТЬ

ВЫРАЗИТЬ(Товары.Количество / 12 КАК ЧИСЛО(15, 0)) КАК ЦелыхУпаковок

ИЗ

Документ.РеализацияТоваровУслуг.Товары КАК Товары

Тот же приём работает и для копеек: ВЫРАЗИТЬ(Сумма * 100 КАК ЧИСЛО(15, 0)) / 100. Имейте в виду, что поведение приведения типов в запросах может незначительно отличаться в зависимости от СУБД (файловая база, MS SQL, PostgreSQL), поэтому критичные к точности расчёты стоит проверить на реальных данных вашей базы.

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

Порядок действий при выборе способа
  1. 1
    Определите, где выполняется округление: код модуля, запрос или вывод на форму.
  2. 2
    Проверьте, возможны ли отрицательные значения — если да, используйте floor с поправкой на знак.
  3. 3
    Определите требуемую разрядность: целые, копейки, десятки.
  4. 4
    Реализуйте округление через Цел() с множителем или ВЫРАЗИТЬ в запросе.
  5. 5
    Протестируйте на граничных значениях: 0.999, -2.7, ровно целое число.

Округление при выводе: форматная строка и Формат()

Если задача — только показать число без дробной части (в печатной форме, на форме, в отчёте), а хранить нужно точное значение, используйте функцию Формат() с конструкцией ЧДЦ:

СтрокаДляПечати = Формат(Сумма, "ЧДЦ=0"); // отображение без копеек

Важный нюанс: форматирование при выводе округляет до ближайшего, а не в меньшую сторону. Формат(2.7, "ЧДЦ=0") покажет «3». Поэтому если требуется именно отсечение, сначала примените Цел() к значению, а потом форматируйте.

То же относится к свойству «Формат» у полей формы и колонок табличных документов: оно управляет только отображением и не меняет данные в базе. Расчёты, проводки и итоги продолжат использовать исходное точное значение.

Типичные ошибки и как их проверить

Самая частая ошибка — использовать Окр(Число, 0) там, где нужен floor. На значениях вроде 2,3 результат совпадёт случайно, а на 2,7 расчёт «поплывёт» на единицу. Вторая ошибка — забыть про отрицательные числа в корректировках и возвратах: Цел(-2.7) даёт −2 вместо −3.

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

Типичные ошибки
01
Использовать Окр(Число, 0) вместо Цел() — на дробях больше 0.5 результат уйдёт вверх.
02
Применять Цел() к отрицательным числам без поправки — получится усечение к нулю, а не в меньшую сторону.
03
Округлять только при выводе через Формат() — итоги и проводки продолжат считаться с полной точностью и разойдутся с печатной формой.
04
Использовать разные правила округления в разных местах одного расчёта — накапливаются копеечные расхождения.
Контрольные точки

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

Цел(17.95)
Норма

Результат 17

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

Результат 18 — использовано округление до ближайшего вместо отсечения

Floor отрицательного: -2.7
Норма

Результат -3

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

Результат -2 — применено усечение к нулю без поправки на знак

Округление копеек: 100.999 до 2 знаков
Норма

100.99

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

101.00 — сработало обычное округление

Сумма строк = итог документа
Норма

Совпадает до копейки

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

Расхождение на копейки — в расчёте смешаны разные правила округления

FAQ: частые вопросы об округлении в меньшую сторону в 1С

Чем Цел() отличается от Окр(Число, 0)?

Цел() просто отбрасывает дробную часть в сторону нуля, а Окр() округляет до ближайшего целого. Для 2.3 обе функции дадут 2, но для 2.7 Цел() вернёт 2, а Окр() — 3. Если бизнес-правило требует «всегда вниз», применяйте Цел().

Как округлить в меньшую сторону отрицательное число?

Цел() для отрицательных чисел отсекает дробь к нулю, поэтому Цел(-2.7) даст −2. Для настоящего округления вниз добавьте поправку: если число отрицательное и не целое, вычтите единицу из целой части. Формула приведена в разделе про универсальный floor.

Как округлить сумму до копеек в меньшую сторону?

Умножьте сумму на 100, возьмите Цел() и разделите обратно на 100: Цел(Сумма * 100) / 100. Так 100.999 превратится в 100.99, а не в 101.00. Для отрицательных сумм добавьте поправку на знак по той же схеме.

Можно ли округлить вниз прямо в запросе 1С?

Да, через приведение типа: ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 0)) отсекает дробную часть. Для копеек — ВЫРАЗИТЬ(Сумма * 100 КАК ЧИСЛО(15, 0)) / 100. Проверьте поведение на своей СУБД, если расчёт критичен к точности.

Почему печатная форма показывает одно, а итоги — другое?

Форматная строка (ЧДЦ=0 и подобные) меняет только отображение и округляет до ближайшего, а данные в документе остаются с полной точностью. Чтобы форма и итоги совпадали, округляйте само значение через Цел() до записи или вывода, а не только форматирование.

Есть ли готовая функция округления вниз в типовых конфигурациях?

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

Итог

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

Округление в меньшую сторону в 1С делается через Цел() для положительных чисел, через Цел() с поправкой на знак — для любых, через Цел(Число * 10^N) / 10^N — для нужной разрядности, а в запросах — через ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 0)). Функция Окр() округляет до ближайшего и для floor не подходит. Единое правило округления во всех расчётах защищает от копеечных расхождений.