Скажем, у меня есть массив чисел с плавающей запятой, в отсортированном (пусть и восходящем) порядке, сумма которого, как известно, является целым числом N
. Я хочу "округлить" эти числа до целых чисел, оставив их без изменений. Другими словами, я ищу алгоритм, который преобразует массив чисел с плавающей запятой (назовем его fn
) в массив целых чисел (назовем его in
) таким, что:
- два массива имеют одинаковую длину
- сумма массива целых чисел
N
- разница между каждым числом с плавающей запятой
fn[i]
и его соответствующим целым числомin[i]
меньше 1 (или равна 1, если вы действительно должны) - учитывая, что поплавки находятся в отсортированном порядке (
fn[i] <= fn[i+1]
), целые числа также будут отсортированы в порядке (in[i] <= in[i+1]
)
Учитывая, что эти четыре условия выполнены, алгоритм, который минимизирует дисперсию округления (sum((in[i] - fn[i])^2)
), является предпочтительным, но это не имеет большого значения.
Примеры:
[0.02, 0.03, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14] => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] [0.1, 0.3, 0.4, 0.4, 0.8] => [0, 0, 0, 1, 1] [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] => [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] [0.4, 0.4, 0.4, 0.4, 9.2, 9.2] => [0, 0, 1, 1, 9, 9] is preferable => [0, 0, 0, 0, 10, 10] is acceptable [0.5, 0.5, 11] => [0, 1, 11] is fine => [0, 0, 12] is technically not allowed but I'd take it in a pinch
Чтобы ответить на некоторые замечательные вопросы, поднятые в комментариях:
- Повторяющиеся элементы разрешены в обоих массивах (хотя мне также было бы интересно услышать об алгоритмах, которые работают, только если массив float не включает повторы)
- Нет единого правильного ответа - для заданного входного массива поплавков обычно имеется несколько массивов int, которые удовлетворяют четырем условиям.
- Приложение, которое я имел в виду, было - и это довольно странно - раздача очков лучшим игрокам в игре MarioKart;-) Никогда не играла сама игра, но, наблюдая за кем-то, я заметил, что было 24 очков, распределенных между лучшими 4 финишерами, и я задавался вопросом, как можно распределить очки в зависимости от времени окончания (так что если кто-то закончит с большим лидерством, они получат большую долю очков). Игра отслеживает итоговые суммы как целые числа, следовательно, необходимость такого округления.
Для любопытных здесь тест script Я использовал для определения, какие алгоритмы работали.