Как вычислить абсолютное значение числа в 1С
Содержание
Чтобы взять число по модулю в 1С, вызовите функцию Abs: выражение Abs(-5) вернёт 5, Abs(5) — тоже 5, Abs(0) — 0. Отдельной функции с именем «Модуль» в языке нет, и писать своё условие с проверкой знака для обычного числа не нужно.
Абсолютное значение числа в 1С 8.3 считается так же, как в 8.2 и даже в 7.7 — функция не менялась. Разница только в том, где вы берёте модуль. Во встроенном языке работает Abs. В языке запросов такой функции нет — там нужна конструкция ВЫБОР. В системе компоновки данных (СКД) модуль задают в вычисляемом поле. Все три случая — с кодом ниже.
Коротко, где какой способ применяется:
| Где считаете | Чем берёте модуль | Пример |
|---|---|---|
| Встроенный язык (модули, обработки) | Abs(X) | Abs(-5) → 5 |
| Язык запросов | ВЫБОР КОГДА X < 0 ТОГДА -X ИНАЧЕ X КОНЕЦ | столбец выборки |
| Вычисляемое поле СКД | Abs(Поле) | в выражении поля |
| Макет печатной формы | Abs(Параметр) | в выражении ячейки |
Функция Abs во встроенном языке
Синтаксис простой: Abs(<Число>). На вход — число, на выходе — его модуль, то есть то же число без знака минус. Результат всегда неотрицательный.
Язык 1С не различает регистр, поэтому Abs(), abs() и ABS() — одно и то же. Русского синонима у функции нет, в отличие от Цел (целая часть) или Окр (округление). Пишется только латиницей.
Результат = Abs(-1250); // 1250
Нормаль = Abs(3.14); // 3.14
Ноль = Abs(0); // 0
Отклонение = Abs(Факт - План); // модуль разницы, знак не важен
В последней строке скобки обязательны: сначала вычисляется разность внутри, потом берётся её модуль. Если план 100 000, а факт 95 000, то Abs(95000 - 100000) даст Abs(-5000) = 5000.
На вход Abs принимает только число. Если в переменной лежит строка "-500", сначала приведите её: Abs(Число("-500")). Иначе платформа выдаст ошибку преобразования типа.
Когда источник значения неизвестен заранее (реквизит, поле таблицы, результат обмена), перед Abs стоит проверить тип. Это убирает добрую часть «падений» на боевой базе:
Если ТипЗнч(Значение) = Тип("Число") Тогда
Модуль = Abs(Значение);
Иначе
Модуль = 0; // или своя обработка нечислового значения
КонецЕсли;
Модуль пригодится не только для целых и дробных чисел. Разность двух дат во встроенном языке — это число секунд, поэтому Abs(Дата1 - Дата2) вернёт длительность между датами независимо от того, какая из них больше.
Если после модуля нужно ещё и округлить результат, порядок обычный: сначала модуль, потом округление. Окр(Abs(-12.347), 2) сперва даст 12.347, затем округлит до 12.35. Менять местами эти функции не нужно — на знак округление не влияет.
Ручной расчёт через тернарный оператор
Там, где Abs недоступна (об этом ниже — язык запросов), или когда рядом с модулем нужна дополнительная логика, модуль собирают вручную через условный оператор ?():
Модуль = ?(Значение < 0, -Значение, Значение);
Читается так: если Значение меньше нуля — вернуть -Значение (минус на минус даёт плюс), иначе — само значение. Для обычного числа результат ровно такой же, как у Abs.
Для чисел всегда предпочитайте Abs: короче и понятнее. Ручной вариант нужен в двух ситуациях — в языке запросов, где функции модуля нет, и когда по знаку исходного числа надо не просто убрать минус, а выполнить разные действия.
Пример второго случая — текст по знаку сальдо и его величина одной строкой:
Подпись = ?(Сальдо < 0, "Долг", "Переплата") + ": " + Формат(Abs(Сальдо), "ЧЦ=15; ЧДЦ=2");
Здесь ?() выбирает слово по знаку, а Abs даёт величину без минуса, которую Формат выводит аккуратными цифрами. Для сальдо -3500 получится строка Долг: 3 500,00.
Модуль в языке запросов через ВЫБОР
В языке запросов 1С функции Abs нет. Модуль собирают конструкцией ВЫБОР … КОГДА … ТОГДА … ИНАЧЕ … КОНЕЦ — тем же условием по знаку:
ВЫБОР
КОГДА Расчеты.СуммаВзаиморасчетов < 0
ТОГДА -Расчеты.СуммаВзаиморасчетов
ИНАЧЕ Расчеты.СуммаВзаиморасчетов
КОНЕЦ КАК МодульСуммы
Такой вычисляемый столбец удобен, когда нужно отсортировать или отобрать записи по величине суммы, не глядя на её знак — скажем, показать все расхождения в сверке больше 1000 рублей, и переплаты, и долги вместе.
Если поле может быть пустым (NULL), сравнение с нулём даст неопределённый результат. Оберните поле в ЕСТЬNULL(Расчеты.СуммаВзаиморасчетов, 0) до того, как подставлять его в ВЫБОР, иначе строки с NULL выпадут из выборки.
Тот же приём работает и для разницы двух полей: поставьте в условие (Поле1 - Поле2) < 0, а в ветки — (Поле2 - Поле1) и (Поле1 - Поле2) соответственно.
Модуль в СКД и в отчётах
В отчёте на СКД модуль берут одним из двух способов.
Способ 1 — в запросе набора данных. Добавьте в запрос тот же вычисляемый столбец с ВЫБОР, что и выше. Дальше отчёт работает с готовым положительным значением как с обычным полем: группирует, суммирует, отбирает.
Способ 2 — в вычисляемом поле СКД. На вкладке «Вычисляемые поля» схемы компоновки добавьте поле и в выражении укажите Abs(Сумма). В выражениях вычисляемых полей встроенные математические функции доступны, поэтому Abs здесь сработает напрямую — без конструкции ВЫБОР.
Какой способ выбрать: если модуль нужен для отбора или сортировки в самом запросе — считайте в запросе. Если только для вывода в готовой таблице — проще вычисляемое поле.
Чтобы не потерять знак при выводе, направление удобно показать условным оформлением. На вкладке «Настройки» компоновщика добавьте оформление: для исходного (не модульного) поля задайте красный цвет текста при условии «меньше 0» и зелёный — при «больше 0». Тогда в колонке стоит положительная величина из Abs, а цвет сообщает сторону отклонения. Данные не меняются — меняется только представление.
Модуль «съедает» знак, а вместе с ним — смысл «переплата или долг». Если направление важно, не затирайте его: выводите знак отдельной колонкой или подсветкой оформления, а модуль используйте только для величины.
Где модуль нужен на практике
Пара типовых задач, в которых без модуля не обойтись:
- 📊 Отклонение факта от плана.
Abs(Факт - План)показывает величину расхождения, а перерасход это или экономия — отдельным признаком. - 🤝 Расхождения в сверке. Долги и переплаты идут с разными знаками. Модуль сводит их к одной шкале «насколько разошлись суммы».
- 💱 Курсовые и суммовые разницы. Для отчёта о величине разницы знак часто не нужен — важен размер.
- ⚖️ Сравнение чисел с допуском. Два денежных значения после округлений почти никогда не равны «до копейки». Вместо
Сумма1 = Сумма2сравнивайте с погрешностью:
Если Abs(Сумма1 - Сумма2) < 0.01 Тогда
// считаем суммы совпавшими
КонецЕсли;
Здесь Abs(1200.50 - 1200.49) = Abs(0.01) = 0.01, и условие < 0.01 их разведёт, а при разнице в полкопейки — сведёт. Это самый частый повод вспомнить про модуль в прикладном коде.
Модуль удобен и для процента отклонения. Формула Abs(Факт - План) / План * 100 даёт величину отклонения в процентах без привязки к знаку: при факте 95 000 и плане 100 000 получится 5000 / 100000 * 100 = 5 процентов. Перерасход это или экономия — решайте по знаку исходной разницы, а не по модулю.
Готовая функция: величина и направление сразу
Часто модуль нужен не сам по себе, а вместе с ответом «в какую сторону отклонение». Чтобы не считать разницу дважды, соберите величину и направление в одной функции общего модуля:
Функция РазницаСЗнаком(Сумма1, Сумма2) Экспорт
Разница = Сумма1 - Сумма2;
Результат = Новый Структура("Модуль, Направление");
Результат.Модуль = Abs(Разница);
Если Разница > 0 Тогда
Результат.Направление = "Больше";
ИначеЕсли Разница < 0 Тогда
Результат.Направление = "Меньше";
Иначе
Результат.Направление = "Равны";
КонецЕсли;
Возврат Результат;
КонецФункции
Вызов РазницаСЗнаком(95000, 100000) вернёт структуру с Модуль = 5000 и Направление = "Меньше". Величину показываете в отчёте, направление — иконкой или цветом. Так модуль решает свою задачу (размер отклонения), а знак не теряется.
Частые ошибки при работе с модулем
Ловушки, на которых спотыкаются чаще всего:
- Строка вместо числа.
Abs("—500")илиAbs(ЗначениеИзРеквизита), где реквизит строковый, даёт ошибку «Преобразование значения к типу Число не может быть выполнено». Приводите аргумент черезЧисло(...). - Ждут
Absв запросе. В языке запросов её нет. Код не компилируется — используйтеВЫБОР. - Проверка на точное равенство денег.
Abs(a - b) = 0для сумм после умножений и округлений почти всегда ложно из-за дробных «хвостов». Сравнивайте< 0.01, а не с нулём. - Потеря знака там, где он нужен. Применили модуль к сальдо — и перестали отличать актив от пассива. Модуль — только для величины.
- Лишние скобки или их нехватка.
-Abs(5)даёт-5, аAbs(-5)даёт5. Это разные выражения: минус передAbsприменяется к уже готовому модулю. NULLв запросе. Пустое поле (например, после левого соединения) ломает сравнение по знаку, и строка молча выпадает из результата. Оборачивайте поле вЕСТЬNULL(Поле, 0)до конструкцииВЫБОР.
Когда модуль брать не нужно
Модуль — не универсальная замена всему. Пропустите его, если:
- Нужен знак. Когда важно, переплата это или долг, приход или расход, — модуль уничтожит нужную информацию.
- Нужно просто показать число без минуса на экране. Для вывода это задача оформления (формат, цвет), а не изменения данных. Исходное значение лучше не трогать.
- Сравниваете «что больше». Чтобы выбрать большее из двух чисел, в запросе есть агрегатные
МАКСИМУМиМИНИМУМ— модуль тут ни при чём.
Иногда модуль пробуют считать «хитро» — через Sqrt(X * X) (корень из квадрата) или Pow(X * X, 0.5). Математически это и правда модуль: Sqrt(-4 * -4) = Sqrt(16) = 4. Но такой приём медленнее, хуже читается и накапливает погрешность на дробных числах. Во встроенном языке для модуля всегда берите Abs, а в запросе — ВЫБОР. Корень из квадрата стоит знать лишь как любопытный факт, а не как рабочий способ.
Частые вопросы
Есть ли у функции модуля русское название?
Abs (регистр не важен). Русского синонима, как у Цел или Окр, у неё нет.Работает ли Abs с датами?
Abs(Дата1 - Дата2) вернёт длительность между ними без учёта порядка.Чем Abs отличается от условия с `?()`?
Abs короче и читается яснее. Условный оператор нужен там, где Abs недоступна (запрос) или где по знаку надо выполнить разные действия, а не только убрать минус.Почему Abs выдаёт ошибку преобразования типа?
NULL или значение другого типа. Приведите аргумент к числу через Число(...) и проверьте, что в нём нет нечисловых символов.Как сравнить две суммы «по модулю разницы»?
Abs(Сумма1 - Сумма2) < Погрешность, например < 0.01. Прямое равенство для денег после округлений почти всегда даёт ложь.Меняет ли Abs точность или тип числа?
Abs не делает.