Скажем, у меня есть массив чисел с плавающей запятой, в отсортированном (пусть и восходящем) порядке, сумма которого, как известно, является целым числом 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 Я использовал для определения, какие алгоритмы работали.