1с8 Распределение суммы по базе
Posted On 2020-12-10
В данном алгоритме ошибка прибавляется к сумме, у которой максимальный коэффициент. При достаточном большом количестве сторк можкт накопиться погрешность, которая прибавится к этой строке.
Функция РаспределитьПропорционально(Знач ИсхСумма, МассивКоэф, Знач Точность = 2) Экспорт Если МассивКоэф.Количество() = 0 Или ИсхСумма = 0 Или ИсхСумма = Null Тогда Возврат Неопределено; КонецЕсли; ИндексМакс = 0; МаксЗнач = 0; РаспрСумма = 0; СуммаКоэф = 0; Для К = 0 По МассивКоэф.Количество() - 1 Цикл МодульЧисла = ?(МассивКоэф[К] > 0, МассивКоэф[К], - МассивКоэф[К]); Если МаксЗнач < МодульЧисла Тогда МаксЗнач = МодульЧисла; ИндексМакс = К; КонецЕсли; СуммаКоэф = СуммаКоэф + МассивКоэф[К]; КонецЦикла; Если СуммаКоэф = 0 Тогда Возврат Неопределено; КонецЕсли; МассивСумм = Новый Массив(МассивКоэф.Количество()); Для К = 0 По МассивКоэф.Количество() - 1 Цикл МассивСумм[К] = Окр(ИсхСумма * МассивКоэф[К] / СуммаКоэф, Точность, 1); РаспрСумма = РаспрСумма + МассивСумм[К]; КонецЦикла; // Погрешности округления отнесем на коэффиецент с максимальным весом Если Не РаспрСумма = ИсхСумма Тогда МассивСумм[ИндексМакс] = МассивСумм[ИндексМакс] + ИсхСумма - РаспрСумма; КонецЕсли; Возврат МассивСумм; КонецФункции
Из Розницы 2.2
// Выполняет пропорциональное распределение суммы в соответствии // с заданными коэффициентами распределения. // // Параметры: // РаспределяемаяСумма - Число - сумма, которую надо распределить, если сумма равна 0 - то возвращается Неопределено; // Если передана отрицательная - расчет по модулю и после инверсия знаков результата. // Коэффициенты - Массив - коэффициенты распределения, должны быть положительны или отрицательными одновременно // Точность - Число - точность округления при распределении. Необязателен. // // Возвращаемое значение: // Массив - массив размерностью равный массиву коэффициентов, содержит // суммы в соответствии с весом коэффициента (из массива коэффициентов). // В случае, если распределить невозможно (кол-во коэффициентов = 0, // есть коэффициенты с отрицательным значением или суммарный вес коэффициентов = 0), // тогда будет возвращено Неопределено. // // Пример: // // Коэффициенты = Новый Массив; // Коэффициенты.Добавить(1); // Коэффициенты.Добавить(2); // Результат = ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам(1, Коэффициенты); // // Результат = [0.33, 0.67] // Функция РаспределитьСуммуПропорциональноКоэффициентам(Знач РаспределяемаяСумма, Знач Коэффициенты, Знач Точность = 2) Экспорт КоэффициентыАбсолютные = Новый Массив(Новый ФиксированныйМассив(Коэффициенты)); // cpy // Старое поведение при неуказанной сумме - для обратной совместимости. Если Не ЗначениеЗаполнено(РаспределяемаяСумма) Тогда Возврат Неопределено; КонецЕсли; Если КоэффициентыАбсолютные.Количество() = 0 Тогда // Недопустимо значение параметра Коэффициенты // Ожидалось: хотя бы один коэффициент будет задан. Возврат Неопределено; КонецЕсли; ИндексМаксимальногоКоэффициента = 0; МаксимальныйКоэффициент = 0; СуммаКоэффициентов = 0; КоэффициентыОтрицательны = (КоэффициентыАбсолютные[0] < 0); Для Индекс = 0 По КоэффициентыАбсолютные.Количество() - 1 Цикл Коэффициент = КоэффициентыАбсолютные[Индекс]; Если КоэффициентыОтрицательны И Коэффициент > 0 Тогда // Недопустимо значение параметра Коэффициенты // Ожидалось: все коэффициенты положительны или все отрицательны одновременно. Возврат Неопределено; КонецЕсли; Если Коэффициент < 0 Тогда Коэффициент = -Коэффициент; // Abs(Коэффициент) КоэффициентыАбсолютные[Индекс] = Коэффициент; // move КонецЕсли; Если МаксимальныйКоэффициент < Коэффициент Тогда МаксимальныйКоэффициент = Коэффициент; ИндексМаксимальногоКоэффициента = Индекс; КонецЕсли; СуммаКоэффициентов = СуммаКоэффициентов + Коэффициент; КонецЦикла; Если СуммаКоэффициентов = 0 Тогда // Недопустимо значение параметра Коэффициенты // Ожидалось: хотя бы один коэффициент будет отличен от нуля. Возврат Неопределено; КонецЕсли; Результат = Новый Массив(КоэффициентыАбсолютные.Количество()); ВыполнятьИнверсию = (РаспределяемаяСумма < 0); Если ВыполнятьИнверсию Тогда РаспределяемаяСумма = -РаспределяемаяСумма; // Abs(РаспределяемаяСумма). КонецЕсли; РаспределеннаяСумма = 0; Для Индекс = 0 По КоэффициентыАбсолютные.Количество() - 1 Цикл Результат[Индекс] = Окр(РаспределяемаяСумма * КоэффициентыАбсолютные[Индекс] / СуммаКоэффициентов, Точность, 1); РаспределеннаяСумма = РаспределеннаяСумма + Результат[Индекс]; КонецЦикла; СуммарнаяПогрешность = РаспределяемаяСумма - РаспределеннаяСумма; Если СуммарнаяПогрешность > 0 Тогда // Погрешности округления отнесем на коэффициент с максимальным весом. Если Не РаспределеннаяСумма = РаспределяемаяСумма Тогда Результат[ИндексМаксимальногоКоэффициента] = Результат[ИндексМаксимальногоКоэффициента] + СуммарнаяПогрешность; КонецЕсли; ИначеЕсли СуммарнаяПогрешность < 0 Тогда // Если распределили больше чем положено, размазываем погрешность по ближайшим максимальным весам. ЗначениеПогрешности = 1 / Pow(10, Точность); КоличествоЭлементовПогрешности = -СуммарнаяПогрешность / ЗначениеПогрешности; Для Сч = 1 По КоличествоЭлементовПогрешности Цикл МаксимальныйКоэффициент = МаксимальноеЗначениеВМассиве(КоэффициентыАбсолютные); Индекс = КоэффициентыАбсолютные.Найти(МаксимальныйКоэффициент); Результат[Индекс] = Результат[Индекс] - ЗначениеПогрешности; КоэффициентыАбсолютные[Индекс] = 0; КонецЦикла; Иначе // Если СуммарнаяПогрешность = 0, то все идеально. КонецЕсли; Если ВыполнятьИнверсию Тогда Для Индекс = 0 По КоэффициентыАбсолютные.Количество() - 1 Цикл Результат[Индекс] = -Результат[Индекс]; КонецЦикла; КонецЕсли; Возврат Результат; КонецФункции