// Linear Shooting Method

#include <stdio.h>
#include <math.h>

void ode2rk4(double (*ddfunc)(double x, double y, double yd),
             double x0, double y0, double yp0, double xe, int n, double y[]);
double ddfunc1(double x, double y, double yd);
double ddfunc2(double x, double y, double yd);
double realfunc(double x);

void main()
{
   int i, n=20;  // nÀº ºÐÇÒ ¼ö
   double a=1, alpha=-1.0/2.0, b=2, beta=log(2.0);    // ÃʱâÄ¡
   double y1[100], y2[100], result[100];
   double x, h=(b-a)/n;

   ode2rk4(ddfunc1, a, alpha, 0, b, n, y1);
   ode2rk4(ddfunc2, a, 0, 1, b, n, y2);

   for(i=0; i<=n; i++)
      result[i] = y1[i] + (beta-y1[n])/y2[n] * y2[i];
   
   printf(" Xi      y1(1,i)      y2(1,i)        Wi          y(Xi)      |y(Xi)-Wi|\n");   

   for(i=0; i<=n; i++) {
      x = a + h*i;
      printf("%4.2f  %11.9f  %11.9f  %11.9f  %11.9f  %11.9e\n",
         x, y1[i], y2[i], result[i], realfunc(x), fabs(realfunc(x)-result[i]) );
   }
}

// Á¤È®ÇÑ ÇÔ¼ö
double realfunc(double x)
{
   return (exp(2)/(exp(4)-1.0) * (exp(2*x)-exp(-2*x))+x);
}

// ÀÔ·Â ÇÔ¼ö ºÎºÐ 1
// y'' = p(x)y' + q(x)y + r(x)
double ddfunc1(double x, double y, double yd)
{
   return ( -4.0/x * yd - 2.0/(x*x) * y -2.0*log(x)/(x*x) );
}

// ÀÔ·Â ÇÔ¼ö ºÎºÐ 2
// y'' = p(x)y' + q(x)y
double ddfunc2(double x, double y, double yd)
{
   return ( -4.0/x * yd - 2.0/(x*x) * y );
}

// 2°è »ó¹ÌºÐ ¹æÁ¤½ÄÀÇ ÇØ¸¦ ±¸ÇÏ´Â ÇÔ¼ö - 4Â÷ RK ¹ý ÀÌ¿ë
// ÃʱâÄ¡ : y(x0)=y0, y'(x0)=yp0
// ±¸°£ÀÇ ³¡Á¡ : xe
// ºÐÇÒ¼ö : n
// °á°ú´Â y[]¿¡ ÀúÀå : y[0]=y0, y[1]=y1, ....    
void ode2rk4(double (*ddfunc)(double x, double y, double yd),
             double x0, double y0, double yp0, double xe, int n, double y[])
{
   int i;
   double  h, k, xi, ui, udi, a, b, c, d, e, f, beta, delta;

   h = (xe-x0)/n;
   k = h*0.5;
   y[0] = ui = y0;
   udi = yp0;
   for(i=1, xi=x0; i<=n; i++, xi+=h) {
      a = (*ddfunc)(xi, ui, udi)*k;
      beta = (udi+a/2)*k;
      b = (*ddfunc)(xi+k, ui+beta, udi+a)*k;
      c = (*ddfunc)(xi+k, ui+beta, udi+b)*k;
      delta = h*(udi+c);
      d = (*ddfunc)(xi+h, ui+delta, udi+2*c)*k;
      e = (a+b+c)/3.;
      f = (b+c+d)/3.;
      ui += (udi+e)*h;
      udi += (e+f);
      y[i] = ui;
   }
}