В процессе разработки на платформе 1С мы часто сталкиваемся с необходимостью распределить общую сумму по строкам табличной части пропорционально какому-либо весовому коэффициенту (например, количеству товаров). На первый взгляд задача кажется простой: достаточно умножить долю строки на общую сумму. Однако при использовании функции Окр() возникают погрешности округления, из-за чего сумма распределенных значений может отличаться от исходной. Рассмотрим, как решить эту задачу профессионально.
Это самый популярный и простой способ, который позволяет гарантированно выйти на итоговую сумму. Суть метода заключается в том, что мы последовательно распределяем сумму по строкам, округляя результат, а в последней итерации записываем не рассчитанное значение, а разницу между общей суммой и уже распределенными величинами.
Разберем реализацию этого метода по шагам:
НакопленнаяСумма со значением 0.Окр(Количество / ОбщееКоличество * ОбщаяСумма, 2).ОбщаяСумма - НакопленнаяСумма.НакопленнаяСумма.
НакопленнаяСумма = 0;
Для Индекс = 0 По Таблица.Количество() - 1 Цикл
Стр = Таблица[Индекс];
Если Индекс = Таблица.Количество() - 1 Тогда
Стр.Сумма = ОбщаяСумма - НакопленнаяСумма;
Иначе
Стр.Сумма = Окр(Стр.Количество / ОбщееКоличество * ОбщаяСумма, 2);
КонецЕсли;
НакопленнаяСумма = НакопленнаяСумма + Стр.Сумма;
КонецЦикла;
Более надежный подход, который минимизирует накопление погрешности, заключается в постепенном уменьшении остатка распределяемой суммы и остатка суммы коэффициентов. Этот метод часто встречается в типовых конфигурациях 1С, так как он более устойчив к «некрасивым» результатам в последней строке.
При использовании этого алгоритма на каждой итерации мы считаем долю от оставшейся суммы:
Функция РаспределитьПропорционально(ИсхСумма, МассивКоэф, Точность = 2)
СуммаКоэф = 0;
Для Каждого Коэф Из МассивКоэф Цикл
СуммаКоэф = СуммаКоэф + Коэф;
КонецЦикла;
МассивСумм = Новый Массив();
Для Каждого Коэф Из МассивКоэф Цикл
ТекущаяДоля = Окр(ИсхСумма * Коэф / СуммаКоэф, Точность, 1);
МассивСумм.Добавить(ТекущаяДоля);
ИсхСумма = ИсхСумма - ТекущаяДоля;
СуммаКоэф = СуммаКоэф - Коэф;
КонецЦикла;
Возврат МассивСумм;
КонецФункции
При работе с подобными алгоритмами обязательно учитывайте следующие моменты:
ОбщееКоличество равно нулю, алгоритм должен либо прерываться, либо распределять сумму поровну (в зависимости от вашей бизнес-логики).Применяя эти методы, вы сможете корректно распределить любые суммы, сохранив математическую точность данных и избежав классической проблемы «копеек», когда Сумма(Строк) не равна ОбщейСумме из-за ошибок округления.