Как обрезать число без округления до нужного количества знаков после запятой в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление нашей фирмой IT и автоматизация бизнеса
← На главную

Часто в практике программирования на платформе 1С:Предприятие возникает потребность отсечь лишние десятичные знаки у дробного числа без его математического округления. Рассмотрим классическую ситуацию: имеется число 12,566666667, и нам необходимо получить ровно два знака после запятой, то есть 12,56. Выясним причину, почему стандартные функции в этом случае не подходят, и подробно разберем несколько способов решения этой задачи.

Почему не подходят функции Окр() и Формат()

Проанализируем работу встроенных механизмов 1С. Если мы попытаемся использовать функцию Окр() или зададим параметры форматирования строки через Формат(), система применит стандартные математические правила округления. В платформе 1С вообще нет встроенного режима округления "в меньшую сторону" (floor). Режимы Окр15как10 и Окр15как20 влияют исключительно на пограничную цифру "5". Поскольку в нашем примере отсекаемая цифра "6" (больше пяти), система неизбежно округлит значение в большую сторону, и результатом станет 12,57. Посмотрим на альтернативные методы, которые позволяют строго "обрезать" хвост числа.

Способ 1. Математический сдвиг с помощью функции Цел()

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

Если нам нужно оставить ровно два знака после запятой, умножим исходное число на 100, применим выделение целой части и разделим обратно на 100:


Обрезка = Цел(ВашеЧисло * 100) / 100;

Проанализируем ситуацию, если количество знаков после запятой должно задаваться динамически. В этом случае воспользуемся функцией возведения в степень Pow():


КоличествоЗнаков = 2; // Задаем нужное число знаков
Множитель = Pow(10, КоличествоЗнаков);
Обрезка = Цел(ВашеЧисло * Множитель) / Множитель;

Нюанс с отрицательными числами: Этот математический вариант является наиболее правильным, так как функция Цел() в 1С отбрасывает дробную часть по направлению к нулю. Рассмотрим пример с отрицательным числом -12.566. При умножении на 100 и взятии целой части Цел(-12.566 * 100) мы получим -1256. Разделив это на 100, мы получим корректный результат: -12.56.

Способ 2. Строковый метод обрезки

Посмотрим на строковый метод. Иногда разработчики прибегают к преобразованию числа в строку, обрезке лишних символов и обратному преобразованию в число. Разберем по шагам, как это можно реализовать.

Можно использовать сложный алгоритм вычисления длины целой и дробной части:


КоличествоРазрядов = Макс(СтрДлина(Строка(Цена)) - СтрДлина(Цел(Цена)) - 1, 0);
ВсегоСимволов = СтрДлина(Строка(Цена));
РезультатЦена = Число(Лев(Строка(Цена), ВсегоСимволов - КоличествоРазрядов + 2));

Однако, рассмотрим более изящный и простой строковый вариант. Он основан на поиске десятичного разделителя (запятой) в строковом представлении числа:


СтроковоеЧисло = Строка(ВашеЧисло);
ПозицияЗапятой = СтрНайти(СтроковоеЧисло, ",");
Если ПозицияЗапятой > 0 Тогда
    Результат = Число(Лев(СтроковоеЧисло, ПозицияЗапятой + 2)); // 2 - количество знаков
Иначе
    Результат = ВашеЧисло; // Дробной части нет
КонецЕсли;

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

Способ 3. Решение на уровне языка запросов 1С для быстрого анализа данных

Проанализируем ситуацию, когда обрезку нужно выполнить непосредственно в SQL-подобном запросе 1С. В языке запросов функции Цел() не существует. В этом случае мы воспользуемся математическим трюком в сочетании с функцией ВЫРАЗИТЬ().

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


ВЫБРАТЬ
    ВЫРАЗИТЬ(МояТаблица.Сумма - 0.005 КАК ЧИСЛО(15, 2)) КАК СуммаБезОкругления
ИЗ
    РегистрНакопления.Продажи КАК МояТаблица

Рассмотрим подробнее работу с отрицательными числами в запросе. Для них этот трюк требует прибавления 0.005, чтобы обрезка происходила ближе к нулю. Реализуем универсальное решение через конструкцию ВЫБОР:


ВЫБРАТЬ
    ВЫБОР 
        КОГДА МояТаблица.Сумма > 0 ТОГДА ВЫРАЗИТЬ(МояТаблица.Сумма - 0.005 КАК ЧИСЛО(15, 2))
        КОГДА МояТаблица.Сумма < 0 ТОГДА ВЫРАЗИТЬ(МояТаблица.Сумма + 0.005 КАК ЧИСЛО(15, 2))
        ИНАЧЕ 0
    КОНЕЦ КАК ОбрезаннаяСумма
ИЗ
    РегистрНакопления.Продажи КАК МояТаблица

Способ 4. Обрезка чисел в отчетах (СКД) и печатных формах

Разберем ситуацию с макетами печатных форм (например, ценников в конфигурации "Управление нашей фирмой") и отчетами на базе Системы Компоновки Данных (СКД). Как мы уже выяснили, свойства формата ячейки (например, установка параметра ЧДЦ=2) никогда не обрезают число, они всегда используют стандартное округление при выводе.

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

  1. Создайте собственную экспортную функцию в общем модуле или модуле объекта, которая будет выполнять математическую обрезку (через умножение и деление).
  2. Если вы работаете в СКД, перейдите на вкладку "Вычисляемые поля".
  3. Добавьте новое вычисляемое поле.
  4. В колонке "Выражение" пропишите вызов нашей математической формулы или функции: Цел(Сумма * 100) / 100.
  5. Именно это вычисляемое поле выводите в выбранные поля отчета вместо исходного реквизита базы данных.

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

← На главную