Ваш інстинкт в основному правильний, сортування за зростанням (за величиною) зазвичай дещо покращує речі. Розглянемо випадок, коли ми додаємо одноточні (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%). Конкретна проблема, яку ви вирішуєте, підкаже, чи є перший досить хорошим чи ні.
Насправді ви можете грати набагато більше трюків, ніж просто додавати їх у відсортованому порядку. Якщо у вас багато дуже малих значень, середня кількість середніх значень і невелика кількість великих значень, то, можливо, найточніше спочатку скласти всі малі, а потім окремо скласти середні, додати ці два сумарні разом потім додайте великі. Зовсім не банально знайти найбільш точну комбінацію доповнень з плаваючою комою, але, щоб впоратися з дійсно поганими випадками, ви можете зберегти цілий масив запущених підсумків різної величини, додавати кожне нове значення до загальної суми, що найкраще відповідає його величині, і коли поточний сумар починає надто великим для його величини, додайте його до наступного загального підсумку і почніть новий. Вважаючи свою логічну крайність, цей процес еквівалентний виконанню суми в довільній точності типу (тож ви буду робити це). Але з огляду на спрощений вибір додавання у порядку зростання чи за спаданням величини, краща ставка на зростання.
Це має певне відношення до програмування в реальному світі, оскільки є деякі випадки, коли ваш розрахунок може піти дуже неправильно, якщо ви випадково відрубаєте «важкий» хвіст, що складається з великої кількості значень, кожне з яких занадто мало, щоб індивідуально впливати суму, або якщо ви викидаєте занадто велику точність від безлічі малих значень, які окремо впливають лише на останні кілька біт суми. У тих випадках, коли хвіст все одно незначний, напевно, вам все одно. Наприклад, якщо ви в першу чергу додаєте лише невелику кількість значень і використовуєте лише кілька значущих цифр суми.