/* 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 "ambiente.h"


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


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

                        
// (60) selecione uma função
float	f(float	x)
{
  return pow(x,5)*cos(x) + pow(x,2)  + sin(x) + 1;
}


float	df(float	x)
{
    float y = 5*pow(x,4)*cos(x);
    y = y + pow(x,5)*sin(x) + 2*x + cos(x);
    return(y);
}


float	busca_binaria(float a, float b, int n)
{
  float	x = (a+b)/2;
  if(n == 0) return(x); 
  else
  {   
      if(f(x)*f(a) == 0) return(x);
      else
      { 
        if(f(a)*f(x) < 0)  return(busca_binaria(a, x, n-1));
          else return(busca_binaria(x,b,n-1));    
      }
  } 
}

float	raiz_secante(float a, float b, int n)
{
    float	m, x;
    m	= (f(b)-f(a))/(b-a);
    x = a - f(a)/m;
    if(n == 0) return(x);
    else
    {
      if(f(x)*f(a) == 0) return(x);
      else
      {
        if( f(a)*f(x) < 0 ) { b = x; return(raiz_secante(a, b, n-1));}
          else {a = x; return(raiz_secante(a, b, n-1));}
      }
    
    }
}

float	raiz_tangente(float a, float b, int n)
{
    float  x;
    x = a - f(a)/df(a);
    if(n == 0) return(x);
    else
    {
      if(f(x)*f(a) == 0) return(x);
      else
      {
        if(f(a)*f(x) < 0 ) { b = x; return(raiz_tangente(a, b, n-1));}
          else {a = x; return(raiz_tangente(a, b, n-1));}
      }
    
    }
}  



/*

	(10) Em C zero é falso e qualquer valor diferente de zero é
	  verdadeiro.  Assim, se teste for zero, então  !teste  que
	  significa  (não teste) é verdadeiro então a mensagem sobre
	  não haver encontrado raízes será emitida.
	  Claro, se tiver encontrando alguma raíz então terá sido acionado
	  algum dos  teste++ =  teste = teste + 1  e portanto  
	  teste não será zero, neste caso  (!teste) é falso e portanto
	  a condição "else" será acionada imprimindo o número de
	  intervalos que foram encontrados.
	  

	(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 
                  

*/
