Search code examples
c++structvoid-pointersgsl

How do you assign struct to a void in gsl integration


I want to use gsl package for numerical integration, which may look easy. However, my function is multi-parameters. I use a struct data type for the parameters of the function. Here is my code to integrate the function f=a*x+b as an example which contains the parameters a and b.

#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>

struct parameters { double a; double b;};

double func (double x, void * params) {
        struct parameters alpha = *(struct parameters *) params;
        double func = alpha->a*x+alpha->b;
  return func;
}
            
int main (void)
{
    gsl_integration_cquad_workspace * w
      = gsl_integration_cquad_workspace_alloc (100);

  double result, error;
  size_t neval;
  struct parameters alpha = {10.0, 3.0};
  gsl_function F;
  F.function = &func;
  F.params = &alpha;

    gsl_integration_cquad(&F, 0, 1., 0., 1e-7, w, &result, &error, &neval);

  printf ("result          = % .18f\n", result);
  printf ("estimated error = % .18f\n", error);

    gsl_integration_cquad_workspace_free (w);

    return 0;
}

This however doesn't work. I don't know how to integrate multi-parameter functions. The function which is named here (func) has the argument (void * params), which I always get an error on changing it to a variable of any type other than a void pointer, and I can't assign the struct alpha that containing the parameters a and b to this void pointer.


Solution

  • You've done the casting wrong. This:

    struct parameters alpha = *(struct parameters *) params;
    

    ...should be written as below if you want to copy params to alpha:

    struct parameters alpha = *((struct parameters *) params);
    

    ...but you later use alpha as a pointer, so it should really be this:

    struct parameters* alpha = (struct parameters *) params;
    

    You can however leave struct out when programming C++ since the struct is typedefed automatically. You should also use C++ casts:

    double func(double x, void* params) {
        auto alpha = static_cast<parameters*>(params);
    
        return alpha->a * x + alpha->b;
    }
    

    You could also make alpha a reference:

    double func(double x, void* params) {
        auto& alpha = *static_cast<parameters*>(params);
    
        return alpha.a * x + alpha.b;
    }
    

    Demo