I am not a frequent user of GSL, but I think I made it work by wrapping the hypergeometric function 2F1
provided by GSL in such a way, that it would return NaN
for $x=1$. Then, the numerical integration will use this information for its purposes and the domain error
will not be thrown.
So, (following the example provided in GSL docs) in function double f
I compared the passed argument $x$ with a domain bound sing_value
(don't judge the naming) in the floating-point sense. If they are sufficiently close, I return NaN
, otherwise, I call the provided by GSL 2F1
function.
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_sf_hyperg.h>
#include <limits>
double f (double x, void * params) {
double alpha = *(double *) params;
double sing_value = 1.0;
double diff = std::abs(x-sing_value);
bool singular_point = (diff <= std::numeric_limits<double>::epsilon()*std::abs(x+sing_value)*2);
// as per Kirill's comment, the comparison
// (diff < std::numeric_limits<double>::min())
// is unnecessary for any practical sense.
if (singular_point)
return std::numeric_limits<double>::quiet_NaN();
else
return gsl_sf_hyperg_2F1(1,2,3,alpha*x);
}
int
main (void)
{
gsl_integration_cquad_workspace * wcquad = gsl_integration_cquad_workspace_alloc (10000);
double result, error;
size_t nevals;
double expected = log(16);
double alpha = 1.0;
gsl_function F;
F.function = &f;
F.params = α
gsl_integration_cquad (&F, -1.0, 1.0, 0, 1e-14, wcquad, &result, &error,&nevals);
printf ("result = % .18f\n", result);
printf ("exact result = % .18f\n", expected);
printf ("estimated error = % .18f\n", error);
printf ("actual error = % .18f\n", result - expected);
printf ("# evaluations = %zu\n", nevals);
gsl_integration_cquad_workspace_free (wcquad);
return 0;
}
According to Wolfram Alpha,
$$
\int_{-1}^1 {}_2F_1(1,2,3,x)dx = \ln 16
$$
which seems to be confirmed by the code
result = 2.772588722239701653
exact result = 2.772588722239781145
estimated error = 0.000000000000023683
actual error = -0.000000000000079492
# evaluations = 2553
The code is not optimized in terms of tolerances, subdivisions and, especially, it being an awful mixture of C/C++ for no reason.
Tested on gcc 6.4 and GSL 2.4.2