Ваш инстинкт в основном прав, сортировка по возрастанию (по величине) обычно несколько улучшает ситуацию. Рассмотрим случай, когда мы добавляем числа с плавающей запятой одинарной точности (32 бита), и есть 1 миллиард значений, равных 1 / (1 миллиард), и одно значение, равное 1. Если 1 идет первой, тогда будет сумма. к 1, поскольку 1 + (1/1 миллиарда) равно 1 из-за потери точности. Каждое добавление не влияет на общую сумму.
Если сначала идут маленькие значения, они, по крайней мере, будут суммировать что-то, хотя даже тогда у меня их 2 ^ 30, тогда как после 2 ^ 25 или около того я возвращаюсь в ситуацию, когда каждое в отдельности не влияет на общую больше нет. Так что мне еще понадобятся трюки.
Это крайний случай, но в целом сложение двух значений одинаковой величины более точное, чем добавление двух значений очень разных величин, поскольку таким образом вы «отбрасываете» меньшее количество бит точности при меньшем значении. Сортируя числа, вы группируете значения одинаковой величины вместе и добавляя их в порядке возрастания, вы даете маленьким значениям «шанс» кумулятивного достижения величины больших чисел.
Тем не менее, если речь идет об отрицательных числах, этот подход легко «перехитрить». Рассмотрим три значения для суммирования {1, -1, 1 billionth}
. Арифметически правильная сумма равна 1 billionth
, но если мое первое добавление включает крошечное значение, тогда моя окончательная сумма будет равна 0. Из 6 возможных заказов только 2 являются «правильными» - {1, -1, 1 billionth}
и {-1, 1, 1 billionth}
. Все 6 порядков дают результаты, которые точны в масштабе самого большого значения на входе (0,0000001% выхода), но для 4 из них результат неточен в масштабе истинного решения (выход 100%). Конкретная проблема, которую вы решаете, скажет вам, достаточно ли первое или нет.
Фактически, вы можете сыграть гораздо больше трюков, чем просто добавить их в отсортированном порядке. Если у вас много очень маленьких значений, среднее количество средних значений и небольшое количество больших значений, тогда может быть наиболее точным сначала сложить все маленькие, а затем отдельно суммировать средние значения, сложить эти две суммы вместе, затем сложите большие. Совсем нетривиально найти наиболее точную комбинацию добавлений с плавающей запятой, но чтобы справиться с действительно плохими случаями, вы можете сохранить целый массив текущих итогов с разными величинами, добавлять каждое новое значение к итоговому результату, который лучше всего соответствует его величине, и когда текущая сумма начинает становиться слишком большой для своей величины, добавьте ее к следующей сумме и начните новую. В своем логическом пределе этот процесс эквивалентен вычислению суммы в типе произвольной точности (так что вы я сделаю это). Но, учитывая упрощенный выбор добавления в порядке возрастания или убывания, возрастание является лучшим вариантом.
Это имеет какое-то отношение к программированию в реальном мире, поскольку в некоторых случаях ваши вычисления могут сильно ошибиться, если вы случайно отрежете «тяжелый» хвост, состоящий из большого количества значений, каждое из которых слишком мало, чтобы индивидуально повлиять на него. сумма, или если вы отбрасываете слишком большую точность из множества небольших значений, которые по отдельности влияют только на последние несколько бит суммы. В тех случаях, когда хвост в любом случае незначителен, вам, вероятно, все равно. Например, если вы сначала складываете только небольшое количество значений и используете только несколько значащих цифр суммы.