在表中预先计算一次cos()和sin()

时间:2013-08-30 11:15:25

标签: c++ windows dll lookup sin

我想提高动态链接库(DLL)的性能。

为此,我想使用 cos() sin()的查找表,因为我使用了很多。

由于我想要获得最大性能,我想创建一个从 0到2PI 的表,其中包含生成的cos和sin计算。

为了在精确度方面取得好成绩,我认为每个函数1 mb的表是大小和精度之间的良好交易。

我想知道如何在不使用外部文件的情况下创建和使用这些表(因为它是一个DLL):我想将所有内容保存在一个文件中。

此外,我不想在插件启动时计算sin和cos函数:它们必须计算一次并放入标准向量

但是我如何在C ++中做到这一点

EDIT1:来自jons34yp的代码非常适合创建矢量文件。

我做了一个小基准测试,发现如果你需要良好的精度和良好的速度,你可以做一个250000单位矢量和它们之间的线性插值,你将有7.89E-11最大误差(!),它是最快的我试过的所有近似值(它比sin()快12倍(完全快13,296 x)

3 个答案:

答案 0 :(得分: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();
}

请注意,这不太可能提高性能,因为此大小的表可能不适合您的L2缓存。这意味着大部分三角计算需要访问RAM;每次这样的访问大约需要几百个CPU周期。

顺便问一下,你看过近似的SSE SIMD三角函数库吗?这看起来像是一个很好的用例。

答案 1 :(得分:2)

您可以使用预计算而不是将它们预先存储在可执行文件中:

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;

这样,表在程序启动时只计算一次,它仍然在固定的内存地址。之后tsintcos可以内联实现

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

答案 2 :(得分:0)

这类问题的通常答案是写一个小问题 生成带有值的C ++源文件的程序 一个表,并将其编译到您的DLL中。如果你在想 表有128000个条目(128000双打是1MB),但是, 您可能会遇到编译器中的某些内部限制。 在这种情况下,您可以考虑将值写入 一个文件作为内存转储,并在加载时mmap此文件 DLL。 (在Windows下,我想你甚至可以把它放在第二位 将文件放入DLL文件的第二个流中,这样就不会有了 分发第二个文件。)