Вы вычисляете value1 - value2
довольно много раз в своей функции.Просто сделайте это один раз.
Это приведение к uint8_t
также может быть проблематичным.Что касается производительности, то наилучшим целочисленным типом для использования при преобразовании из двойного в целое является 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) * 1036 * генерирует значительно более медленный код (на 25% медленнее с этой проблемой!), Чем clang -O3
, который, в свою очередь, генерирует код, который немного медленнее, чем сгенерированный clang -O4
.
Я также играл с подходом рационального приближения функций (аналогично ответу Марка Рэнсома), но вышеизложенное, очевидно, не использует такой подход.