Абсолютно оптимальный способ - использовать приоритетную очередь следующим образом:
PriorityQueue<Float> q = new PriorityQueue<Float>();
for(float x : list) q.add(x);
while(q.size() > 1) q.add(q.pop() + q.pop());
return q.pop();
(этот код предполагает, что числа положительные; обычно очередь должна быть упорядочена по абсолютному значению)
Объяснение: учитывая список чисел, чтобы сложить их как можно точнее, вы должны стремиться к тому, чтобы числа сближались, т.е. устранить разницу между маленькими и большими. Вот почему вы хотите сложить два наименьших числа, таким образом увеличивая минимальное значение списка, уменьшая разницу между минимальным и максимальным значениями в списке и уменьшая размер проблемы на 1.
К сожалению, я понятия не имею, как это можно векторизовать, учитывая, что вы используете OpenCL. Но я почти уверен, что это может быть. Вы можете взглянуть на книгу о векторных алгоритмах, удивительно, насколько мощными они на самом деле являются: Векторные модели для параллельных вычислений