/* 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"


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


inteira	principal()
{
	real	a=-10,b=10,delta=0.05; // valores predefinidos
	real	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) )
			{
				real  raiz; // (40) variável local
				real	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("[%f, %f] \n ", ini, fine);				
				imprima("========1o método: por busca binária ======= \n");
			   raiz =  busca_binaria(ini, fine, N);								
				imprima("valor de f no ponto %f  --> %f  \n",raiz,f(raiz));
				imprima("========2o método: pelo método da secante ========= \n");
				raiz = raiz_secante(ini, fine, N);								
				imprima("valor de f no ponto %f  --> %f  \n",raiz,f(raiz));				
				imprima("========3o método: pelo método da tangente ======== \n");
				raiz = raiz_tangente(ini, fine, N);
				imprima("valor de f no ponto %f  --> %f  \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
				real 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("[%f, %f] \n", a, a+delta);
				imprima("valor de f no ponto %f  --> %f  \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
real	f(real	x)
{
		//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)));
}


real	df(real	x)
{
    real	delta = 0.00001; //  variável local
    voltar( (f(x+delta)-f(x))/delta ) ;
}


real	busca_binaria(real a, real b, inteiro n)
{
  real	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));    
      }
  } 
}

real	raiz_secante(real a, real b, inteiro n)
{
    real	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));}
      }
    
    }
}

real	raiz_tangente(real a, real b, inteiro n)
{
    real	 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 
                  

*/
