При разработке прикладных решений на платформе 1С 8.3 часто возникает необходимость не просто округлить число по стандартным математическим правилам, но и реализовать специфические режимы округления. Например, округлить число всегда в большую сторону (вверх) или отсечь лишние знаки после запятой без изменения самого числа (вниз). Начинающие разработчики часто решают эту задачу через преобразование числа в строку, поиск запятой и манипуляции с подстроками. Проанализируем, почему этот метод неэффективен, и разберем по шагам, как построить красивый, быстрый и точный математический алгоритм.
Рассмотрим типичный подход начинающего разработчика. Число преобразуется в строку с помощью функции Строка(), затем через Найти() определяется позиция разделителя (запятой или точки), после чего строковыми функциями Лев() и Сред() выделяются нужные фрагменты для последующего анализа и сборки нового числа.
Этот метод рабочий, но имеет несколько критических недостатков:
Проанализируем ситуацию и выясним, как решить задачу исключительно математическими методами встроенного языка 1С.
Для реализации корректного округления без строк нам понадобятся базовые арифметические операции и несколько встроенных функций 1С:
Цел() — возвращает целую часть числа, полностью отсекая дробную.Дробь() — возвращает только дробную часть числа.Pow() — функция возведения числа в степень (понадобится для быстрого получения множителя разрядности).Давайте разберем принцип работы математического сдвига разрядов. Чтобы оставить у числа 250.35941 ровно 2 знака после запятой, выполним следующие шаги:
250.35941 * 100 = 25035.941. Теперь целевые разряды округления оказались в целой части числа.25035 / 100 = 250.35.Рассмотрим, как этот алгоритм выглядит на практике для разных режимов округления.
Нам необходимо реализовать функцию, принимающую три параметра: округляемое число, количество знаков после запятой (разрядность) и режим («Вверх», «Вниз» или «Нет» — стандартное математическое округление).
Посмотрим на пример законченной и оптимизированной функции:
Функция ОкруглитьЧислоМатематически(Знач ИсходноеЧисло, Знач Разрядность, Знач РежимОкругления) Экспорт
// Если разрядность некорректная, возвращаем исходное число
Если Разрядность < 0 Тогда
Возврат ИсходноеЧисло;
КонецЕсли;
// Вычисляем коэффициент сдвига запятой (10, 100, 1000 и т.д.)
Коэффициент = Pow(10, Разрядность);
// Сдвигаем запятую вправо
СдвинутоеЧисло = ИсходноеЧисло * Коэффициент;
Если РежимОкругления = "Вниз" Тогда
// Режим "Вниз" (простое усечение/отсечение дробной части)
Возврат Цел(СдвинутоеЧисло) / Коэффициент;
ИначеЕсли РежимОкругления = "Вверх" Тогда
// Режим "Вверх" (округление всегда в большую сторону, если есть остаток)
Если Дробь(СдвинутоеЧисло) > 0 Тогда
Возврат (Цел(СдвинутоеЧисло) + 1) / Коэффициент;
Иначе
Возврат СдвинутоеЧисло / Коэффициент;
КонецЕсли;
Иначе // Режим "Нет" (по правилам математики)
// Используем быструю встроенную функцию платформы
Возврат Окр(ИсходноеЧисло, Разрядность);
КонецЕсли;
КонецФункции
Рассмотрим подробнее каждый режим работы функции:
250.35941 на 100, получая 25035.941. Функция Цел() отбрасывает дробную часть 0.941, оставляя ровно 25035. При делении на 100 мы получаем итоговое значение 250.35. Метод работает мгновенно и без строковых преобразований.Дробь(). Если у числа 25035.941 дробная часть (0.941) больше нуля, это значит, что число не было целым и его нужно округлить в большую сторону. Мы берем целую часть 25035, прибавляем к ней 1 (получаем 25036) и делим на 100. Результат — 250.36.Окр() отлично справляется с этой задачей, работая на уровне скомпилированного кода платформы с максимальной скоростью.Разработчикам полезно знать возможности стандартной функции Окр(), которые могут избавить от написания собственного кода:
Окр(1256, -2) вернет 1300 (округление до сотен).РежимОкругления.Окр15как20 (или значение 1) округлит 1.5 до 2. Режим РежимОкругления.Окр15как10 (или значение 0) округлит 1.5 до 1 (банковское/бухгалтерское округление для снижения погрешности суммирования).Начиная с версии платформы 8.3.20, разработчикам больше не нужно использовать сложные конструкции вроде ВЫРАЗИТЬ() или выгружать данные в код для округления. В язык запросов и СКД были добавлены полноценные математические функции:
ОКР(ПолеТаблицы, Разрядность) — выполняет округление значений прямо на уровне СУБД.ЦЕЛ(ПолеТаблицы) — возвращает целую часть числа в запросе.Использование этих функций в запросах позволяет значительно повысить производительность отчетов и обработок, перекладывая математические вычисления на СУБД.