Предварительно вычислите один раз cos () и sin () в таблицах

Я хотел бы улучшить производительность моего Динамически связанная библиотека (DLL).

Для этого я хочу использовать таблицы поиска сов () а также грех () как я использую их много.

Поскольку я хочу максимальной производительности, я хочу создать таблицу из От 0 до 2PI который содержит результирующие вычисления cos и sin.

Думаю, для хорошего результата в плане точности таблицы по 1 мб для каждой функции это хорошая сделка между размером и точностью.

Я хотел бы знать, как создавать и использовать эти таблицы без использования внешнего файла (так как это DLL): Я хочу сохранить все в одном файле.

Также я не хочу вычислять функции sin и cos при запуске плагина: они должны быть вычислены один раз и помещены в стандарт вектор.

Но как мне это сделать в C ++?

EDIT1: код из jons34yp очень хорош для создания векторных файлов.

Я сделал небольшой тест и обнаружил, что если вам нужна хорошая точность и хорошая скорость, вы можете сделать вектор 250000 единиц и линейную интерполяцию между ними, у вас будет максимальная ошибка 7,89E-11 (!), И она является самой быстрой из всех приближений Я пытался (и это более чем в 12 раз быстрее, чем грех () (13,296 х точно)

3

Решение

Самое простое решение — написать отдельную программу, которая создает .cc файл с определением вашего вектора.

Например:

#include <iostream>
#include <cmath>

int main()
{
std::ofstream out("values.cc");

out << "#include \"static_values.h\"\n";
out << "#include <vector>\n";

out << "std::vector<float> pi_values = {\n";
out << std::precision(10);

// We only need to compute the range from 0 to PI/2, and use trigonometric
// transformations for values outside this range.
double range = 3.141529 / 2;
unsigned num_results = 250000;

for (unsigned i = 0; i < num_results; i++) {
double value = (range / num_results) * i;
double res = std::sin(value);

out << "    " << res << ",\n";
}
out << "};\n"out.close();
}

Обратите внимание, что это вряд ли улучшит производительность, так как таблица такого размера, вероятно, не поместится в ваш кэш второго уровня. Это означает, что большой процент тригонометрических вычислений потребуется для доступа к ОЗУ; Каждый такой доступ стоит примерно несколько сотен циклов ЦП.

Кстати, вы смотрели примерные тригонометрические библиотеки SSE SIMD? Это похоже на хороший вариант использования для них.

3

Другие решения

Вы можете использовать предварительные вычисления вместо того, чтобы сохранять их уже предварительно вычисленные в исполняемом файле:

double precomputed_sin[65536];

struct table_filler {
table_filler() {
for (int i=0; i<65536; i++) {
precomputed_sin[i] = sin(i*2*3.141592654/65536);
}
}
} table_filler_instance;

Таким образом, таблица вычисляется только один раз при запуске программы, и она все еще имеет фиксированный адрес памяти. После этого tsin а также tcos может быть реализован в виде

inline double tsin(int x) { return precomputed_sin[x & 65535]; }
inline double tcos(int x) { return precomputed_sin[(x + 16384) & 65535]; }
2

Обычный ответ на этот вопрос — написать небольшой
программа, которая генерирует исходный файл C ++ со значениями в
таблицу и скомпилируйте ее в свою DLL. Если вы думаете о
таблицы с 128000 записей (128000 двойные 1 МБ), однако,
вы можете столкнуться с некоторыми внутренними ограничениями в вашем компиляторе.
В этом случае вы можете записать значения в
файл как дамп памяти, и mmapиспользуя этот файл при загрузке
DLL. (Под окнами, я думаю, вы могли бы даже поставить этот второй
файл во второй поток вашего файла DLL, так что у вас не будет
раздать второй файл.)

0
По вопросам рекламы [email protected]