При доработке печатных форм, отчетов или документов в платформе 1С:Предприятие 7.7 разработчики периодически сталкиваются с парадоксальным поведением программы: вычисленное значение переменной визуально равно нулю, отладчик показывает тип Число со значением 0, но логическое условие вида Если ОстКолво <= 0 возвращает Ложь, а Если ОстКолво > 0 вычисляется как Истина.
Рассмотрим подробно причины возникновения такой проблемы, проанализируем внутренние механизмы работы с числами в платформах 1С 7.7 и разберем проверенные способы исправления этой ошибки в коде.
Выясним, почему возникает данная коллизия. В платформе 1С 7.7 нетипизированные переменные, промежуточные результаты арифметических вычислений (особенно вычитания, деления и умножения) и колонки таблиц значений без явно заданной точности хранятся в оперативной памяти как числа с плавающей запятой двойной точности (формат double стандарта IEEE 754).
Когда в процессе работы программы выполняется цепочка вычислений (например, вычитание списанного количества из исходного: 20 - 20), в памяти процессора из-за особенной бинарного представления вещественных чисел может остаться бесконечно малое значение порядка 0.0000000000000001 или -0.0000000000000001.
При этом возникают следующие эффекты:
0.>, <, <=, >= сравнивают точное содержимое ячейки памяти. Поскольку значение 0.0000000000000001 строго больше абсолютного нуля, условие Если ОстКолво > 0 срабатывает.Самым надежным и общепринятым способом решения данной проблемы является принудительное округление вычисленного значения до необходимой точности учета перед выполнением логических проверок. Для этого используется встроенная функция Окр().
Разберем пример кода, в котором количество округляется до 3 знаков после запятой (стандартная точность для товарных остатков):
ОстКолво = Окр(ВсегоКол - СписаноКол, 3);
Если ОстКолво <= 0 Тогда
// Строка не требует дальнейшего списания или обработки
ИначеЕсли (ОстКолво > 0) И (ОстКолво < ВсегоКол) Тогда
// Частичное списание
КонецЕсли;
Если в коде необходимо проверить факт равенства переменной нулю без изменения самого значения переменной, проанализируем подход с использованием допустимой погрешности (эпсилона) или встроенной функции Абс() (модуль числа).
Посмотрим на примеры реализаций:
// Вариант А: Сравнение с минимальной пороговой величиной
Если ОстКолво <= 0.00001 Тогда
// Считаем, что остаток нулевой или отрицательный
КонецЕсли;
// Вариант Б: Проверка на равенство нулю через модуль числа
Если Абс(ОстКолво) < 0.0001 Тогда
// Число практически равно нулю
КонецЕсли;
Часто накопление погрешности происходит при помещении промежуточных расчетов в таблицы значений. Если колонка добавлена методом НоваяКолонка() без указания типа и точности, данные в ней сохраняются в формате с плавающей точкой со всеми накапливающимися погрешностями.
Чтобы избежать этого, создадим колонку с явным указанием типа Число, его длины и точности. В этом случае платформа 1С 7.7 автоматически округляет помещаемые значения:
ТаблицаГТД = СоздатьОбъект("ТаблицаЗначений");
// Указываем тип "Число", длину 15 знаков и точность 3 знака после запятой
ТаблицаГТД.НоваяКолонка("Количество", "Число", 15, 3);
// Теперь при сравнении значений из таблицы погрешности не возникнет:
Если ТаблицаГТД.Количество <= 0 Тогда
// Логика обработки нулевого количества
КонецЕсли;
Резюме: При написании алгоритмов пересчета количества и сумм в 1С 7.7 не следует полагаться на прямое сравнение вычисленных переменных с нулем. Всегда применяйте округление с помощью Окр(), задавайте точность колонок таблиц значений или используйте проверку модуля числа через Абс().