Я пишу некоторый код на C ++ для научных вычислительных целей.Библиотека линейной алгебры, которую я выбрал, - это Armadillo.Моя проблема в том, что Armadillo использует либо простую функцию rand (), либо Mersenne Twister rng, тогда как мне нужны более качественные числа, например ranlux.GSL обеспечивает реализацию ranulx, а Armadillo позволяет использовать внешний rng, определив макрос препроцессора ARMA_RNG_ALT и записав соответствующий заголовочный файл, который мы назовем arma_rng_alt.hpp.
Теперь я не волшебник C ++, но яудалось сделать это путем более или менее копирования и вставки из существующих заголовков arma_rng_cxx98.hpp и arma_rng_cxx11.hpp.Мое решение может быть не самым красивым, но я думаю, что оно работает хорошо.Вот выдержка из моего заголовка:
#if defined(ARMA_RNG_ALT)
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#define RNG_TYPE gsl_rng_ranlxd1
class arma_rng_alt
{
public:
typedef unsigned long int seed_type;
inline void set_seed(const seed_type val);
arma_inline int randi_val();
arma_inline double randu_val();
arma_inline double randn_val();
private:
gsl_rng* engine;
};
inline
void
arma_rng_alt::set_seed(const arma_rng_alt::seed_type val)
{
engine = gsl_rng_alloc(RNG_TYPE);
gsl_rng_set(engine, val);
}
arma_inline
int
arma_rng_alt::randi_val()
{
return gsl_rng_get(engine);
}
arma_inline
double
arma_rng_alt::randu_val()
{
return gsl_rng_uniform(engine);
}
arma_inline
double
arma_rng_alt::randn_val()
{
return gsl_ran_gaussian_ziggurat(engine, 1.);
}
#endif
Теперь это было бы нормально, если бы этот внешний rng был обработан armadillo как класс без закрытой переменной (как в заголовке arma_rng_cxx98.hpp, который использует rand() и не нужно выделять двигатель).Вместо этого мне нужно выделить механизм и вызывать его каждый раз, поэтому мне нужно создать экземпляр класса, в противном случае я получаю ошибку «не могу вызвать функцию-член без объекта».Поэтому мне действительно нужно было изменить заголовок из самой библиотеки Armadillo, а именно arma_rng.hpp.Чтобы прояснить ситуацию, вот как выглядит типичный кусок исходного arma_rng.hpp для генерации случайных целых чисел:
template<typename eT>
struct arma_rng::randi
{
arma_inline
operator eT ()
{
#if defined(ARMA_RNG_ALT)
{
return eT( arma_rng_alt::randi_val() );
}
#elif defined(ARMA_USE_EXTERN_CXX11_RNG)
{
return eT( arma_rng_cxx11_instance.randi_val() );
}
#else
{
return eT( arma_rng_cxx98::randi_val() );
}
#endif
}
Как вы можете видеть, если используется cxx98 или alt, функция randi_val простовызывают, в то время как если используется cxx11, randi_val вызывается для фактического экземпляра calss arma_rng_cxx11 (локальная переменная потока, объявленная ранее в заголовке).Мне нужно что-то похожее на cxx11, поэтому я изменил заголовок библиотеки arma_rng.hpp для этого конкретного примера:
template<typename eT>
struct arma_rng::randi
{
arma_inline
operator eT ()
{
#if defined(ARMA_RNG_ALT)
{
return eT( arma_rng_alt_instance.randi_val() );
}
#elif defined(ARMA_USE_EXTERN_CXX11_RNG)
{
return eT( arma_rng_cxx11_instance.randi_val() );
}
#else
{
return eT( arma_rng_cxx98::randi_val() );
}
#endif
}
после объявления собственного локального экземпляра потока класса arma_rng_alt, который я создал.
Работает как шарм, подвох в том, что теперь мне нужно запустить свой код в кластере HPC и, хотя я могу создать свой собственный arma_rng_alt.hpp, я не могу изменить заголовок библиотеки arma_rng.hppсам.Поэтому мне нужен способ заставить оригинальный заголовок работать (без создания экземпляра класса).У вас есть идеи, как это сделать?Мои знания C ++ откровенно растянуты до предела.
Спасибо