代码之家  ›  专栏  ›  技术社区  ›  IonOne

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

  •  3
  • IonOne  · 技术社区  · 11 年前

    我想提高我的表现 动态链接库 (DLL)。

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

    由于我想要最大的性能,我想从 0到2PI 包含由此产生的cos和sin计算。

    为了在精度方面取得好成绩,我认为 每个函数1 mb的表格 是尺寸和精度之间的一个很好的交易。

    我想知道如何在不使用外部文件(因为它是一个DLL)的情况下创建和使用这些表: 我想把所有的东西都放在一个文件里。

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

    但是 用C怎么做++ ?

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

    我做了一个小的基准测试,发现如果你需要好的精度和速度,你可以做250000个单位的矢量和它们之间的线性插值,你会有7.89E-11的最大误差(!),这是我尝试过的所有近似中最快的(它比sin()快12倍多(准确地说是13296倍)

    3 回复  |  直到 8 年前
        1
  •  3
  •   user283145 user283145    11 年前

    最简单的解决方案是编写一个单独的程序,创建 .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();
    }
    

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

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

        2
  •  2
  •   6502    11 年前

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

    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]; }
    
        3
  •  0
  •   James Kanze    11 年前

    对于这类问题,通常的答案是写一个 生成C++源文件的程序,该文件中的值 一个表,并将其编译到您的DLL中。如果你正在考虑 具有128000个条目的表(128000个双是1MB), 编译器中可能会遇到一些内部限制。 在这种情况下,您可能会考虑将值写入 作为内存转储的文件,以及 mmap 加载时正在处理此文件 DLL。(在窗户下面,我想你甚至可以把这一秒放进去 文件转换为DLL文件的第二个流,这样您就不会 以分发第二个文件。)