Я пытаюсь разделить набор чисел на соотношения (32%/68%), но хотел бы иметь алгоритм, чтобы округленные дроби складывались в исходное разделение чисел. Прямой подход этого не делает (22/48 против 23/47).
Qty 32% 68% Rounded Rounded Adjusted Adjusted
10 3.2 6.8 3 7 3 7
10 3.2 6.8 3 7 3 7
5 1.6 3.4 2 3 2 3
5 1.6 3.4 2 3 1 4
10 3.2 6.8 3 7 3 7
10 3.2 6.8 3 7 3 7
5 1.6 3.4 2 3 2 3
15 4.8 10.2 5 10 4 11
-------------------------------------------------------------
70 22.4 47.6 23 47 70 21 49
22 48
Гибкость заключается в том, что дробление должно быть как можно ближе к целевому соотношению, если не точное. Итак, если в сумме после округления получается на 1 больше, то ее надо отнять, но от какого числа? Исходное число — 70, что разделяет 22,4/47,6. Так какое соотношение ближе к 32/68 – 22/48 или 23/47? Если 22/48 лучше, то лишнее можно убрать из первого номер одного из отдельных расколов. Но этот мини-сплит должен быть как можно ближе к 32/68. Кажется, что если необходимо внести корректировку, то следует выбрать наибольшее число, чтобы корректировка имела минимальное влияние. Таким образом, 5/10 может быть 4/10, а не 2/3 как 1/4.
Более важным ограничением при суммировании мини-разделений является то, что разделение исходного числа должно быть как можно ближе к 32/68, а исходное число должно быть получено путем сложения мини-разделений.
Возможно ли вообще, что округленные мини-разделения при суммировании будут меньше исходного числа, поэтому вместо того, чтобы что-то убирать, нужно что-то добавить?
Я реализовал предложение Гейба Сечана (большое спасибо!), и сумма скорректированных столбцов дала исходное число. Исходное разделение составляет 21/49, что не ближе к 32/68, чем к 22/48. Но я думаю, что без дальнейшей оптимизации изменения порядка обработки чисел это решение работает.
Я думаю, что если вы хотите минимизировать абсолютную разницу, вы можете просто математически округлить значения в процентах, потому что невозможно получить ровно 0,5 с целыми числами и соотношением 32/68.
@Дэйв, я отредактировал проблему, чтобы обеспечить гибкость.
Отслеживайте ошибку — величину отклонения от округления. Например, если число равно 3,2 и округляется до 3, ошибка равна -.2. Когда ошибка равна 1,6 и округляется до 2, ошибка равна 0,4. При каждом округлении накапливайте ошибку. Когда ошибка станет достаточно большой, откорректируйте округление. Простой способ сделать это — добавить ошибку к фактическому числу, а затем округлить результат. Таким образом, 3,2 с ошибкой 0,6 равно 3,8, которое округляется до 4. Тогда ваша новая ошибка будет -.2 (вы начали с .6, затем добавили -.8, оставив -.2). Однако вы также можете выбрать другие пороговые значения для настройки округления в зависимости от того, насколько вы предпочитаете минимизировать количество корректируемых элементов.
Если у вас нет гибкости в отношении небольших дроблений, точно соответствующих целевому соотношению, то (в общем) решения нет, как показывает ваш контрпример. Если у вас есть гибкость, пожалуйста, опишите ее. Например, вы бы предпочли минимизировать количество мини-сплитов, измененных с 32/68, или вы бы предпочли минимизировать максимальную абсолютную разницу между любым мини-сплитом и его целевым показателем 32/68, или что-то еще?