Вы вычисление value1 - value2
достаточно несколько раз в вашей функции. Просто сделайте это один раз.
Это отличное от uint8_t
также может быть проблематичным. Что касается производительности, лучшим интегральным типом, используемым в качестве преобразования из double в integer, является int
, так как наилучшим интегральным типом для использования индекса массива является int
.
max_value = value1;
diff = value1 - value2;
if (diff < 0.0) {
max_value = value2;
diff = -diff;
}
if (diff >= 5.0) {
return max_value;
}
else {
return max_value + LUT[(int)(diff * 10.0)];
}
Обратите внимание, что приведенное выше гарантирует, что индекс LUT будет находиться между 0 (включительно) и 50 (исключительно). Здесь нет необходимости в uint8_t
.
Редактировать
После некоторых игр с некоторыми вариациями, это довольно быстро LUT на основе приближения к log(exp(value1)+exp(value2))
:
#include <stdint.h>
// intptr_t *happens* to be fastest on my machine. YMMV.
typedef intptr_t IndexType;
double log_sum_exp (double value1, double value2, double *LUT) {
double diff = value1 - value2;
if (diff < 0.0) {
value1 = value2;
diff = -diff;
}
IndexType idx = diff * 10.0;
if (idx < 50) {
value1 += LUT[idx];
}
return value1;
}
Интегральный тип IndexType
является одним из ключей к форсированию вещи вверх. Я тестировал с clang и g ++, и оба указали, что литье на intptr_t
(long
на моем компьютере) и использование intptr_t
в качестве индекса в LUT быстрее других интегральных типов. Это значительно быстрее, чем некоторые типы. Например, unsigned long long
и uint8_t
невероятно плохие выборы на моем компьютере.
Тип - это не просто подсказка, по крайней мере, с использованием компиляторов, которые я использовал. Эти компиляторы сделали именно то, что ему сказал код в отношении преобразования из типа с плавающей точкой в интегральный тип, независимо от уровня оптимизации.
Еще одна ошибка скорости получается из сравнения интегрального типа с 50 в отличие от сравнения типа с плавающей точкой с 5.0.
Последняя удача скорости: не все компиляторы созданы равными. На моем компьютере (YMMV), g++ -O3
генерирует значительно более медленный код (на 25% медленнее с этой проблемой!), Чем clang -O3
, который, в свою очередь, генерирует код, который немного медленнее, чем сгенерированный clang -O4
.
Я также играл с приближением рациональной функции (аналогично ответу Марка Рэнсома), но вышеприведенное, очевидно, не использует такой подход.
Зачем вычислять 'max()', когда вы уже знаете результат? – sharptooth
Вау ... спасибо, это было действительно глупо ... исправил! – vls
Если это * реальное * узкое место, то графические процессоры очень хороши в этом (таблицы добавления насыщения и поиска). – MSalters