我正在编写代码以使用n点执行Gaussian integration,其中n是编译时间常数。

对于给定的n,我知道如何计算横坐标和权重。必须为每个不同的n从头开始进行计算。

现在,我按照以下思路进行操作:

// Several structs like this one (laguerre, chebyshev, etc).
template <size_t n>
struct legendre
{
    static const size_t size = n;
    static const double x[n];
    static const double w[n];
};

template <typename Rule, typename F>
double gauss_quadrature (F&& f)
{
    double acc = 0;
    for (size_t j = 0; j < Rule::size; j++)
        acc += Rule::w[j] * f (Rule::x[j]);

    return acc;
}

像这样使用:
double i = gauss_quadrature<legendre<12>> (f);

现在,我可以通过翻译来专门研究legendre<12>的系数
template <>
const legendre<12>::x[12] = { ... };

template <>
const legendre<12>::w[12] = { ... };

只要我只使用12点高斯-勒格德勒(Gauss-Legendre),一切都很好。

现在,我正在尝试使用不同数量的点,并且知道如何生成权重和节点。例如,我可以提供一个例程
void compute_legendre_coeffs (size_t n, double* w, double* x);

和:
  • 当我调用gauss_quadrature<legendre<n>>时,模板legendre<n>会自动实例化(这种情况)。
  • 当为某些编译时legendre<n>实例化n时,我希望在main之前的某个时刻调用上述compute_legendre_coeffs,以便它填充xw成员数组。 我该如何实现?

  • 我知道必须先定义数组:
    template <size_t n>
    const double legendre<n>::x[n] = {};
    
    template <size_t n>
    const double legendre<n>::w[n] = {};
    

    但我无法提出一种初始化它们的方法。有人有技巧吗?

    最佳答案

    template <size_t n>
    class legendre
    {
    public:
        static const size_t size = n;
        static const double (&getX())[n] {
           init();
           return x;
        }
        static const double (&getW())[n] {
           init();
           return x;
        }
    private:
        static double x[n];
        static double w[n];
        static void init() {
           static bool _ = do_init(x,y);
        }
        static bool do_init( double *x, double *y ) {
           // do the computation here, use local vars x, y
           return true;
        }
    };
    template <size_t n>
    double legendre<n>::x[n];
    template <size_t n>
    double legendre<n>::w[n];
    

    通过提供访问器,您可以控制类的入口点。访问器分派(dispatch)给init函数,该函数使用局部静态变量的初始化在程序生命周期中仅调用一次do_initdo_init进行成员的实际初始化。

    笔记:

    取决于编译器,这可能不是线程安全的(即,并非所有的C++ 03编译器都提供静态变量的线程安全的初始化,这反过来意味着do_init可能被并行调用多次,具体取决于所使用的算法还是不成问题-例如,如果do_init将这些值放在一边,只写它们,则潜在的竞争条件就无关紧要了,因为最终结果将是相同的)。一些编译器提供了保证一次性执行的机制(我相信boost具有这种机制)。或者,根据您的域,您也许可以在启动线程之前准备系数。

    在这种情况下,实际数组不能为const,因为在创建它们之后需要进行初始化。除了可能的微优化以外,这应该不是问题(即编译器不知道系数的值,因此它不能在编译时执行子表达式评估)。

    09-13 04:06