Как вычислить абсолютное значение числа в 1С

· 9 мин

Содержание

Чтобы взять число по модулю в 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(-7)` во встроенном языке 1С?
Как взять модуль числа в языке запросов 1С?
Чему равно `-Abs(-5)`?

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

Есть ли у функции модуля русское название?
Нет. Пишется только Abs (регистр не важен). Русского синонима, как у Цел или Окр, у неё нет.
Работает ли Abs с датами?
С самой датой — нет, модуль берут от числа. Но разность двух дат во встроенном языке — это число секунд, поэтому Abs(Дата1 - Дата2) вернёт длительность между ними без учёта порядка.
Чем Abs отличается от условия с `?()`?
Для числа — ничем, результат одинаковый. Abs короче и читается яснее. Условный оператор нужен там, где Abs недоступна (запрос) или где по знаку надо выполнить разные действия, а не только убрать минус.
Почему Abs выдаёт ошибку преобразования типа?
В функцию передали не число, а строку, NULL или значение другого типа. Приведите аргумент к числу через Число(...) и проверьте, что в нём нет нечисловых символов.
Как сравнить две суммы «по модулю разницы»?
Через Abs(Сумма1 - Сумма2) < Погрешность, например < 0.01. Прямое равенство для денег после округлений почти всегда даёт ложь.
Меняет ли Abs точность или тип числа?
Нет. Функция возвращает число того же типа и с той же точностью — убирает только знак. Дробная часть и разрядность остаются прежними, округления Abs не делает.