【问题标题】:GSL Error Handler status with Wrapper function in C++C++ 中带有 Wrapper 函数的 GSL 错误处理程序状态
【发布时间】:2014-06-10 17:01:14
【问题描述】:

我在 c++ 中将这个 wrapper 函数用于我在其他解决方案中看到的 gsl

gsl_function_pp Fp( std::bind(&Class::member_function, &(*this),  std::placeholders::_1) );
gsl_function *F = static_cast<gsl_function*>(&Fp);

在 GSL 的文档中, https://www.gnu.org/software/gsl/manual/html_node/Error-Reporting-Examples.html#Error-Reporting-Examples

它说 int status = gsl_function..。 将给出错误代码。但是我不知道如何使用上面的包装函数获取状态。

******************************更新1

所以我用这个函数来解决 fzero 问题

double gsl_root(gsl_function *F, double x_lo, double x_hi) {
    const gsl_root_fsolver_type *T;
    gsl_root_fsolver *s;

    T = gsl_root_fsolver_brent;
    s = gsl_root_fsolver_alloc (T);

    gsl_root_fsolver_set (s, F, x_lo, x_hi);

    int status;
    do {
        status = gsl_root_fsolver_iterate(s);

        x_lo = gsl_root_fsolver_x_lower (s);
        x_hi = gsl_root_fsolver_x_upper (s);

        status = gsl_root_test_interval (x_lo, x_hi, 0, 1e-12);

    } while(status == GSL_CONTINUE);

    gsl_root_fsolver_free(s);

    return 0.5*(x_lo + x_hi);   
}

如何获得上述函数的状态输出,我尝试了迭代和区间函数但没有奏效,我已经不知道为什么和如何。

例如,当 GSl 没有解决方案时,我会收到如下错误:

gsl: brent.c:74: ERROR: endpoints do not straddle y=0
Default GSL error handler invoked.

所以这就是我真正想要的。我只想处理这种情况。很抱歉造成混淆,希望现在问题更清楚。

【问题讨论】:

  • 你好。首先:我已经写了一些我使用这个包装器的答案,但我不是它的原始创建者。这是一个相对众所周知的解决方案。因此,来自“Vinicius Miranda”的包装是不公平的(也无助于引用)。您能否说“我在这些解决方案上看到的包装器”并实际指定您在哪里看到它以及如何在代码中使用它..
  • 第二:gsl 中有返回错误状态的函数,例如:“int gsl_integration_qag(...)”。 gsl_function 不是其中之一。实际上 gsl_function 只是一个包含函数和 void 指针的 c-struct。请参阅源代码行 123-130 中的 gsl_math.h
  • :( 不,我没有理解或以错误的方式问。现在让我再说一遍;在我上面的例子中,我正在调用一个带有包装器的成员函数。哪个变量将基本上保持状态? 没关系 gsl_func 是一个结构,但在我的情况下我如何使用那个 gsl_inteegration_qag()?
  • 更新了问题!更新 1 是最近的
  • 更新 2...我真的希望这个问题现在已经结束了!

标签: c++ exception wrapper handle gsl


【解决方案1】:

我认为我的评论解决了问题,但我会在这里总结一下以结束问题。 GSL 函数只是以下 c-struct 的 typedef

struct gsl_function_struct 
{
  double (* function) (double x, void * params);
  void * params;
};

typedef struct gsl_function_struct gsl_function ;

那么,很明显 gsl_function 不是一个例程,例如“int gsl_fft_complex_radix2_forward(...)”,它执行一些操作并返回一个带有错误状态的整数。

更新 1:我仍然不明白错误状态和包装器之间的关系是什么。所以让我展示一个几乎完整的例子(gsl集成)

 // use smart pointers in c++
 template< typename T > class deleter;

 template<> class deleter< gsl_integration_workspace > {
    public:
    void operator()( gsl_integration_workspace* ptr ) { 
        gsl_integration_workspace_free(ptr);
        return; 
    }
  };

  typedef std::unique_ptr< gsl_integration_workspace, 
   deleter< gsl_integration_workspace > > cpp_gsl_integration_workspace;


 // main program
 // TURN OFF GSL ERROR ERROR HANDLER (GSL JUST PRINT ERROR MESSAGE AND KILL THE PROGRAM IF FLAG IN ON)
 gsl_set_error_handler_off();

 auto ptr = [](double x)->double{ return x; };
 std::function<double(const double)> F1( std::cref(ptr) );
 gsl_function_pp F2(F1);
 gsl_function *F = static_cast<gsl_function*>(&F2); 

 double result;
 double error;
 double lower_limit = 0;
 double upper_limit = 1;
 double abs_eps = 0;
 double rel_eps= 1e3;
 int size = 1000;

 cpp_gsl_integration_workspace w( gsl_integration_workspace_alloc( size ) );

 int status = gsl_integration_qag ( F, lower_limit, upper_limit, abs_eps, rel_eps, 
    2000, GSL_INTEG_GAUSS15, w.get(), result, error );

 // check status and get error message if integration failed.
 // Nothing to do with the use of the C++ wrapper
 if ( status )
 {
   // gsl_strerror prints a message explaining the error 
   std::cout << "GSL FAIL: " << std::string( gsl_strerror (status) ) << std::endl;
   exit(1);
 }

 std::cout << result << "   " << error << std::endl

使用 fft 函数,您应该做一些非常相似的事情 int status = ....; if(status) {cout &lt;&lt; std::string( gsl_strerror (status) ) &lt;&lt; std::endl; exit(1); // or throw an exception}

更新 2:我希望现在清楚错误句柄与 C++ 包装器无关

首先:当您设置gsl_set_error_handler_off() 时,您有责任检查 gsl 调用的错误。然后你必须将你当前的代码替换为这样的东西

int status;

// this will be the crucial line for my the answer to your problem, but it is important
// to stress all places where you must check the status of the gsl function calls.
status = gsl_root_fsolver_set (s, F, x_lo, x_hi);
if(status) std::cout << std::string( gsl_strerror (status) ) << std::endl;

do {
    status = gsl_root_fsolver_iterate(s);

    if(status) std::cout << std::string( gsl_strerror (status) ) << std::endl;

    x_lo = gsl_root_fsolver_x_lower (s);
    x_hi = gsl_root_fsolver_x_upper (s);

    status = gsl_root_test_interval (x_lo, x_hi, 0, 1e-12);

    if(status) std::cout << std::string( gsl_strerror (status) ) << std::endl;

} while(status == GSL_CONTINUE);

if(status != GSL_SUCCESS ) std::cout << std::string( gsl_strerror (status) ) << std::endl;

第二:如果您检查 GSL 源代码,您将看到该消息

gsl: brent.c:74: 错误:端点不跨越 y=0

写在函数上

 static int brent_init (void * vstate, gsl_function * f, double * root, double x_lower, double x_upper)

此外,函数 set 在您的特定情况下只是指向 brent_init 的指针

typedef struct
{
  const char *name;
  size_t size;
  int (*set) (void *state, gsl_function * f, double * root, double x_lower, double x_upper);
  int (*iterate) (void *state, gsl_function * f, double * root, double * x_lower, double * x_upper);
}
gsl_root_fsolver_type;

static const gsl_root_fsolver_type brent_type =
{"brent",                               /* name */
 sizeof (brent_state_t),
 &brent_init,
 &brent_iterate};

然后,您无法检测到错误,因为您错过了以下调用的状态

 status = gsl_root_fsolver_set (s, F, x_lo, x_hi);
 if(status) std::cout << std::string( gsl_strerror (status) ) << std::endl; 

最后,当发生这种情况时,检查 GSL 源代码很重要。错误消息显示发生错误的文件名和行号。所以享受 GSL 是一个开源代码并检查那里发生了什么!此外,GSL 源代码组织良好、干净且易于理解。

【讨论】:

  • 感谢您的努力 vinicius 但是我如何在我的情况下使用 gsl_fft_complex_radix2_forward(...) 并在调用成员函数时使用包装器..??
  • 酷,所以现在我的问题肯定更清楚了(对我来说,对此感到抱歉..)所以,现在我使用类似::::---> int status;做{状态= gsl_root_fsolver_iterate(s); x_lo = gsl_root_fsolver_x_lower (s); x_hi = gsl_root_fsolver_x_upper (s);状态 = gsl_root_test_interval (x_lo, x_hi, 0, 1e-12); } 而(状态 == GSL_CONTINUE);
  • 所以在这里我尝试使用 gsl_strerror 输出状态,但它没有出来。那么你建议如何正确获取 gsl 错误?
  • aha 得到 GSL FAIL 的输出:迭代尚未收敛。这是在 gsl_root_test_interval 之后,但这不是我想要的。因为当“”gsl:brent.c:74:错误:端点不跨越y = 0调用默认GSL错误处理程序时,我需要输出。 ""
  • 完美的维尼修斯!好吧,status = ..._set 真的很重要,如果没有你,我不会弄明白。你说得对,这不是关于包装器,但我真的很困惑,我正在尝试继续由另一位工程师编写的项目,这些天我没有睡觉:/抱歉有太多时间。+无论如何,我现在在所有这些方面都学到了很多东西。希望我可以帮助其他人。
猜你喜欢
  • 2019-02-21
  • 1970-01-01
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 1970-01-01
  • 2016-03-06
相关资源
最近更新 更多