Я хотел бы улучшить производительность моего Динамически связанная библиотека (DLL).
Для этого я хочу использовать таблицы поиска сов () а также грех () как я использую их много.
Поскольку я хочу максимальной производительности, я хочу создать таблицу из От 0 до 2PI который содержит результирующие вычисления cos и sin.
Думаю, для хорошего результата в плане точности таблицы по 1 мб для каждой функции это хорошая сделка между размером и точностью.
Я хотел бы знать, как создавать и использовать эти таблицы без использования внешнего файла (так как это DLL): Я хочу сохранить все в одном файле.
Также я не хочу вычислять функции sin и cos при запуске плагина: они должны быть вычислены один раз и помещены в стандарт вектор.
Но как мне это сделать в C ++?
EDIT1: код из jons34yp очень хорош для создания векторных файлов.
Я сделал небольшой тест и обнаружил, что если вам нужна хорошая точность и хорошая скорость, вы можете сделать вектор 250000 единиц и линейную интерполяцию между ними, у вас будет максимальная ошибка 7,89E-11 (!), И она является самой быстрой из всех приближений Я пытался (и это более чем в 12 раз быстрее, чем грех () (13,296 х точно)
Самое простое решение — написать отдельную программу, которая создает .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? Это похоже на хороший вариант использования для них.
Вы можете использовать предварительные вычисления вместо того, чтобы сохранять их уже предварительно вычисленные в исполняемом файле:
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]; }
Обычный ответ на этот вопрос — написать небольшой
программа, которая генерирует исходный файл C ++ со значениями в
таблицу и скомпилируйте ее в свою DLL. Если вы думаете о
таблицы с 128000 записей (128000 двойные 1 МБ), однако,
вы можете столкнуться с некоторыми внутренними ограничениями в вашем компиляторе.
В этом случае вы можете записать значения в
файл как дамп памяти, и mmap
используя этот файл при загрузке
DLL. (Под окнами, я думаю, вы могли бы даже поставить этот второй
файл во второй поток вашего файла DLL, так что у вас не будет
раздать второй файл.)