/// OPTIMİZASYON
//  Newton-ikiyebölme kök bulma yöntemi (ve türev ) kullanarak optimizasyon 
import java.util.*;
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
import javax.swing.*;

class fc extends f_x
{
   public double func(double D)
   {   double V=0.5e-3;
	   return Math.PI*D*D/2.0-4.0*V/D;}
}

class fb extends f_x
{
   public double func(double D)
   { double V=0.5e-3;
     return Math.PI*D-4.0*V/(D*D);}
}

public class FOPO3A
{

public static double derivative(f_x df,double x)
{
// türev alt programı	
// df fonksiyonunun türevini hesaplar
double h0=0.256;
int i,m;
int n=7;
//derivative of a simple function
double T[][];
T=new double[n][n];
double h[];
h=new double[n];
//vector<double> h(n,0);
for(i=0;i<n;i++)
{
  h[i]=0;
  for(int j=0;j<n;j++)
    T[i][j]=0;
}
h[0]=h0;
double r=0.5;
for( i=1;i<n;i++)
{
h[i]=h0*Math.pow(r,i);
}

for(i=0;i<n;i++)
{
T[i][0]=( df.func(x + h[i]) - df.func( x - h[i]))/(2.0*h[i]);
}
for(m=1;m<n;m++)
{
  for(i=0;i<n-m;i++)
  {
  T[i][m]=(h[i]*h[i]*T[i+1][m-1] - h[i+m]*h[i+m]*T[i][m-1])/
          (h[i]*h[i]- h[i+m]*h[i+m]);
  }
}
double xx=T[0][n-1];
return xx;
}

public static double dfx(f_x f,double x,double h)
{ //Türev hesabı
  double hh=1.0/h; 
  return (-f.func(x+2.0*h)+8.0*f.func(x+h)-8.0*f.func(x-h)+f.func(x-2.0*h))/12.0*hh;
}

public static double newton_bisection(f_x fx, double x1, double x2)
{
double xacc=1.0e-10; //iterasyonlar arasındaki fark, bu rakamdan 
// küçük olduğunda çözüme ulaştığımızı kabul edeceğiz
double h=0.0001; //türev step büyüklüğü
int MAXIT=100;  //Maksimum iterasyon sayısı
int j;
double dfr,dx,dxold,fr,fh,fl;
double temp,b,a,r;
fl=fx.func(x1);
fh=fx.func(x2);
//Bölgemizde kök değeri varmı kontrol et
if ((fl > 0.0 && fh > 0.0) || (fl < 0.0 && fh < 0.0))
System.out.println("verilen sınırlar içinde kök değeri yok");
if (fl == 0.0) return x1;
if (fh == 0.0) return x2;
if (fl < 0.0)   { a=x1;b=x2;} 
else            { b=x1;a=x2;}
r=0.5*(x1+x2); //orta nokta değeri 
dxold=Math.abs(x2-x1); 
dx=dxold; 
fr=fx.func(r);   //fonksiyonun r noktasındaki değeri
dfr=dfx(fx,r,h); //fonksiyonun türevinin r noktasındaki değeri
for (j=1;j<=MAXIT;j++) 
{ 
if ((((r-b)*dfr-fr)*((r-a)*dfr-fr) > 0.0) || (Math.abs(2.0*fr) > Math.abs(dxold*dfr))) 
    { //ikiye bölme 
	  dxold=dx;
      dx=0.5*(b-a);
      r=a+dx;
      if (a == r) return r; //çözüm!!!!
    } 
else{ //Newton-Raphson
	  dxold=dx;
      dx=fr/dfr;
      temp=r;
      r -= dx;
      if (temp == r) return r;  //çözüm!!!!!
    }
if (Math.abs(dx) < xacc) return r; //çözüm!!!!!
fr=fx.func(r);
dfr=dfx(fx,r,h);
if (fr < 0.0) 
a=r;
else
b=r;
}
System.out.println("Maksimum iterasyon sayısı aşıldı");
return 0.0; //program buraya gelmemeli 
}

     public static void main (String args[])  
     { 
	 fc  f=new fc();
	 fb df=new fb();  
     double x0,x1;
     x0=Double.parseDouble(JOptionPane.showInputDialog(" alt sınırı giriniz  x0 : "));
     x1=Double.parseDouble(JOptionPane.showInputDialog(" üst sınırı giriniz  x1 : "));
     double r;
     r= newton_bisection(df,x0,x1);
     JOptionPane.showMessageDialog(null," optimizasyon değeri  : "+r+"\nFonksiyon değeri : "+f.func(r),
     "Newton-ikiye ayırma optimizasyon : ",JOptionPane.PLAIN_MESSAGE);
     System.exit(0);
     } 
}