Как правильно распределить сумму пропорционально количеству в 1С и решить проблему «копеек»?

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

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

Метод закрытия остатка на последнюю строку

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

Разберем реализацию этого метода по шагам:

  1. Инициализируем переменную НакопленнаяСумма со значением 0.
  2. В цикле проходим по всем строкам таблицы.
  3. Если это не последняя строка, вычисляем сумму как Окр(Количество / ОбщееКоличество * ОбщаяСумма, 2).
  4. Если это последняя строка, присваиваем значение ОбщаяСумма - НакопленнаяСумма.
  5. На каждом шаге добавляем вычисленное значение в НакопленнаяСумма.

НакопленнаяСумма = 0;
Для Индекс = 0 По Таблица.Количество() - 1 Цикл
    Стр = Таблица[Индекс];
    Если Индекс = Таблица.Количество() - 1 Тогда
        Стр.Сумма = ОбщаяСумма - НакопленнаяСумма;
    Иначе
        Стр.Сумма = Окр(Стр.Количество / ОбщееКоличество * ОбщаяСумма, 2);
    КонецЕсли;
    НакопленнаяСумма = НакопленнаяСумма + Стр.Сумма;
КонецЦикла;

Метод итерационного распределения (аналог БСП)

Более надежный подход, который минимизирует накопление погрешности, заключается в постепенном уменьшении остатка распределяемой суммы и остатка суммы коэффициентов. Этот метод часто встречается в типовых конфигурациях 1С, так как он более устойчив к «некрасивым» результатам в последней строке.

При использовании этого алгоритма на каждой итерации мы считаем долю от оставшейся суммы:


Функция РаспределитьПропорционально(ИсхСумма, МассивКоэф, Точность = 2)
    СуммаКоэф = 0;
    Для Каждого Коэф Из МассивКоэф Цикл
        СуммаКоэф = СуммаКоэф + Коэф;
    КонецЦикла;

    МассивСумм = Новый Массив();
    Для Каждого Коэф Из МассивКоэф Цикл
        ТекущаяДоля = Окр(ИсхСумма * Коэф / СуммаКоэф, Точность, 1);
        МассивСумм.Добавить(ТекущаяДоля);
        ИсхСумма = ИсхСумма - ТекущаяДоля;
        СуммаКоэф = СуммаКоэф - Коэф;
    КонецЦикла;
    Возврат МассивСумм;
КонецФункции

Важные замечания и советы

При работе с подобными алгоритмами обязательно учитывайте следующие моменты:

Применяя эти методы, вы сможете корректно распределить любые суммы, сохранив математическую точность данных и избежав классической проблемы «копеек», когда Сумма(Строк) не равна ОбщейСумме из-за ошибок округления.

← На главную