/* Programa    raizes.c  -  versão final
   Assunto:		Estudo das raizes de uma funcao definida no programa.
   
	Condicionantes:
	Programa sem erros
	Os resultados deste programa foram bons em vários testes.
	
	compilar com
		gcc -Wall -oprog -lm raizes.c
         
	Descricao:	Varre um intervalo com uma malha dada 
		procurando quando f troca 	de sinal, ao encontrar uma
		troca de sinal desencadeia os três métodos
      busca binária com 10 iteradas, método da secante 
      e método da tangente.
      
      Quando a raiz for tipo tangente usa a troca de sinal da derivada
      e verifica o módulo máximo
      
		    
	Palavras-chave:	troca de sinal, raiz, varredura, métodos clássicos             
	por Tarcisio Praciano Pereira - 10 licões para aprender C
	Sobral, Agosto de 2003   - UVA
*/
                  

#include <stdio.h>
#include <math.h>
#include "traducao.h"
#include "ambiente.h"


double	f(double	x); //  A função cujas raízes serão procuradas
double	df(double	x); //  podia ser uma macro, mas não gosto delas...
double	busca_binaria(double a, double b, inteiro n);
double	raiz_secante(double a, double b, inteiro n);
double	raiz_tangente(double a, double b, inteiro n);


inteira	principal()
{
	double	a=-10,b=10,delta=0.05; // valores predefinidos
	double	epsilon;
	inteira teste = 0; // (10) se nao houver raizes 
	imprima("Raizes aproximadas - metodos da secante e tangente \n");
	imprima("Forneca-me o intervalo [a,b] para busca de raizes: \n");
	a = entrada_float("a = ", a); // (20) definida em ambiente.h
	b = entrada_float("b = ", b); // (20) definida em ambiente.h
	imprima("Forneca-me o passo da malha para a  busca:\n");
	imprima("Sugestao  0.01 <  delta   <  0.5  \n");
	delta = entrada_float("delta  = " , delta);  // (20) 	
	imprima("busca de raizes no intervalo [%f, %f] \n ",a,b);	
	imprima("Precisao da malha %f \n ", delta);
	se (delta > 1) { epsilon = 0.1;}
		senao { epsilon = 0.1*delta;}	
	apeteco2();  // (20) 	
	enquanto ( a <= b)
	{
		se ( ( f(a)*f(a+delta) <=0) )
			{
				double  raiz; // (40) variável local
				double	ini=a, fine=a+delta; // (40) variáveis locais
				inteira	N=10; // (40) variável local
				teste++; // se houver raiz  teste conta quantas	há
				imprima("============= Três métodos ===========\n");
 				imprima("Raiz provável da função no intervalo ");
				imprima("[%lf, %lf] \n ", ini, fine);				
				imprima("========1o método: por busca binária ======= \n");
			   raiz =  busca_binaria(ini, fine, N);								
				imprima("f(%lf) =  %lf  \n",raiz,f(raiz));				
				imprima("========2o método: pelo método da secante ========= \n");
				raiz = raiz_secante(ini, fine, N);							
				imprima("f(%lf) =  %lf  \n",raiz,f(raiz));					
				imprima("========3o método: pelo método da tangente ======== \n");
				raiz = raiz_tangente(ini, fine, N);
				imprima("f(%lf) =  %lf  \n",raiz,f(raiz));				
				imprima("========  fim do caso troca de sinal  ======== \n\n\n");
				a = a + delta; // pula um subintervalo				
			}
		senao se  ( ( df(a)*df(a+delta) < 0 ) && ( f(a)*f(a+delta)  < epsilon)  )
			{
				// (70) testa troca de sinal da derivada e  f(a) pequena
				double raiz=(a + a+delta)/2; // Var local - ponto médio do intervalo
				teste++; // conta as raizes 
				imprima("==== Quando a derivada troca de sinal - tangência ===== \n");
				imprima("Raiz, por tangência, provável, da função no intervalo \n");
				imprima("[%lf, %lf] \n", a, a+delta);
				imprima("f(%lf) =  %lf  \n",raiz,f(raiz));				
				imprima("f(%lf) = %lf  \n",raiz,f(raiz));
				imprima("====   fim do caso troca de sinal da derivada  ===== \n\n\n");
				a = a + 2*delta; // pula dois subintervalos
			}		
	a = a + delta;
	}
	se (!teste)
	// se teste for zero, nao encontrou raizes
	{
	imprima("Nao encontrei raízes...mas isto não significa que \n");
	imprima("nao as haja!  apenas eu não consegui encontrá-las !\n");
	imprima("Rode, novamente, o programa, com passo mais fino...\n");
	imprima("ou em  intervalo  diferente. \n");
	}
	senao
	{
	se (teste == 1)
		imprima("Encontrei 1 intervalo onde h\'a raizes \n");
	senao
	  imprima("Encontrei %d intervalos onde h\'a raizes \n", teste);
	}
 	voltar(0);
}

                        
// (60) selecione uma função
double	f(double	x)
{
      //float v,p,t,a,b;
      //float pi=3.14159265358979323848;
		//voltar(0.001*(x-1)*(x+2)*(x+2)*(x-2)*(x-2)*(x*x*x*x*x + x*x*x*x + x*x*x + x*x + x + 1));
		//voltar((x+3)*(x+3)*(x+1)*(x-2)*(x-2)); 
		// voltar(x*x);
		// voltar((x+3.4)*(x+3.4)*(x+3.4)*(x+3.4)*(x+3)*(x+3)*(x+2)*(x+2)*(x+2)*(x-1)*(x-1)*(x-3)*sin(x/(x*x + 1)));
		//return(x*sqrt(4-pow(x,2)));
		//v = sqrt(x); p = pow(x,2) - 2; t = v*x/4.0 ; a=(2*t - pi/2.0)/p;
      //b = pi - 2*a;
      //return( a*pow(x,2) + b - 2*t - pi/2);
      float y = pow(1+x,24);
      // 1000*x*(1+x)^24 - 61.62*(1+x)^24+ 61.62
      return(y*(1000*x - 61.62) + 61.62);
}


double	df(double	x)
{
    //double	delta = 0.00001; //  variável local
    //voltar( (f(x+delta)-f(x))/delta ) ;
    return( 1000*pow(1+x,24) + 24000*pow(1+x,23)*x);
}


double	busca_binaria(double a, double b, inteiro n)
{
  double	x = (a+b)/2;
  se (n == 0) voltar(x); 
  senao
  {   
      se (f(x)*f(a) == 0) voltar(x);
      senao
      { 
        se (f(a)*f(x) < 0)  voltar(busca_binaria(a, x, n-1));
          senao voltar(busca_binaria(x,b,n-1));    
      }
  } 
}

double	raiz_secante(double a, double b, inteiro n)
{
    double	m, x;
    m	= (f(b)-f(a))/(b-a);
    x = a - f(a)/m;
    se (n == 0) voltar(x);
    senao
    {
      se (f(x)*f(a) == 0) voltar(x);
      senao
      {
        se ( f(a)*f(x) < 0 ) { b = x; voltar(raiz_secante(a, b, n-1));}
          senao {a = x; voltar(raiz_secante(a, b, n-1));}
      }
    
    }
}

double	raiz_tangente(double a, double b, inteiro n)
{
    double	 x;
    x = a - f(a)/df(a);
    se (n == 0) voltar(x);
    senao
    {
      se (f(x)*f(a) == 0) voltar(x);
      senao
      {
        se (f(a)*f(x) < 0 ) { b = x; voltar(raiz_tangente(a, b, n-1));}
          senao {a = x; voltar(raiz_tangente(a, b, n-1));}
      }
    
    }
}  



/*

	(10) Alterei a lógica do  teste  -  agora  teste é também um
	contador de raízes - antes ela era 1  se não houvesse raiz.

	(40)	Variável local.  Em C, quando abrimos uma chave, estamos 
		criando um bloco lógico. No início de cada bloco lógico podemos
		definir novas variáveis. Toda variável fica restrita ao bloco
		lógico em que for definida. É local.  Terminada vigência do
		bloco lógico, a variável será destruida.


	(60) O símbolo //  transforma a linha em que ele se encontra, em um
		comentário, a partir do ponto em que ele estiver. Desta forma eu
      posso definir diversas equações para uma função, e 
      ligar uma em que eu esteja interessado  e 
      desligar as outras. 
               
  (70) Teste simultâneo (and) da troca de sinal da derivada e módulo 
  máximo da derivada. O módulo é desnecessário porque f tem sinal constante.
  Observe que estou usando f(a)*f(a+delta) que é positivo e se f for menor
  do que 1 então  f(a)*f(a+delta) < |f(a)| < delta 
                  

*/
