2017-07-06 69 views
1

我對C++比較陌生,但我有一些(稀缺)編碼和數值經驗。如何將std :: valarray <double>與gsl整合?

我知道這個問題會不時發佈,你如何整合一個數組。在MATLAB中,你可以強制你的數組成爲一個函數(我忘記了它是如何的,但我知道我之前做過),並將它發送給內置的集成器,所以我的問題是你如何在C++中做到這一點。

我有這個積分:

I = integral(A(z)*sin(qz)*dz) 

q是隻需雙擊常量,z是積分變量,而A(z)是一個數組(我會actualfunction從現在開始稱呼它)有相同的我的代碼中z軸的點數。積分邊界是z [0]和z [nz-1]。

我使用梯形法則計算了這個積分,對於z軸的5000點,這需要0.06秒。我的問題是這個計算大概發生了300 * 30 * 20次(我有3個循環),這個0.06秒非常快速地增長到3個小時的模擬。我的代碼的整個瓶頸就是這種集成(我明顯可以通過減少z來加速,但這不是重點。)

我知道庫函數通常比用戶編寫的函數好得多。我也知道我不能像辛普森的規則那樣使用更簡單的東西,因爲被積函數是高度振盪的,我想避免自己實現一些複雜的數值alghoritm。

GSL需要形式的函數:

F = F(雙X,無效* PARAMS)

,我大概可以使用QAWO自適應的積分從GSL,但我怎麼做我的函數形式將我的數組變成函數?

我想到的東西爲:

F(double z, void *params) 
{ 
    std::valarray<double> actualfunction = *(std::valarray<double> *) params; 
    double dz = *(double *) params; // Pretty sure this is wrong 
    unsigned int actual_index = z/dz; // crazy assumption (my z[0] was 0) 
    return actualfunction[actual_index]; 
} 

是這樣的可能嗎?我懷疑數值算法會使用與實際功能相同的空間差異,那麼我是否應該以某種方式對實際功能進行插值?

有什麼更好的然後gsl?

回答

0
template<class F> 
struct func_ptr_helper { 
    F f; 
    void* pvoid(){ return std::addressof(f); } 
    template<class R, class...Args> 
    using before_ptr=R(*)(void*,Args...); 
    template<class R, class...Args> 
    using after_ptr=R(*)(Args...,void*); 
    template<class R, class...Args> 
    static before_ptr<R,Args...> before_func() { 
    return [](void* p, Args...args)->R{ 
     return (*static_cast<F*>(p))(std::forward<Args>(args)...); 
    }; 
    } 
    template<class R, class...Args> 
    static after_ptr<R,Args...> after_func() { 
    return [](Args...args, void* p)->R{ 
     return (*static_cast<F*>(p))(std::forward<Args>(args)...); 
    }; 
    } 
}; 
template<class F> 
func_ptr_helper<F> lambda_to_pfunc(F f){ return {std::move(f)}; } 

使用:

auto f = lambda_to_pfunc([&actualfunction, &dz](double z){ 
    unsigned int actual_index = z/dz; // crazy assumption (my z[0] was 0) 
    return actualfunction[actual_index]; 
}); 

然後

void* pvoid - f.pvoid(); 
void(*pfun)(double, void*) = f.after_func(); 

,你可以通過pfunpvoid通過。

任何錯別字的道歉。

這個想法是我們寫一個lambda,做我們想要的wgat。然後lambda_to_pfunc包裝它,所以我們可以將它作爲void*和函數指針傳遞給C風格的API。