/* Programa    raizes_tangente.c
   Assunto:		Estudo das raizes de uma função definida no programa.
   
	Condicionantes:
	Programa sem erros, ver raizes012.c com mudança de variável
	Para compilar
			gcc -Wall -oprog raizes_tangente.c
	cria o executável  prog  que você pode rodar na linha de comandos
	em Linux.		
         
	Descrição:	Varre um intervalo com uma malha dada 
		procurando quando f troca 	de sinal.
		Lendo os comentários você pode alterar o programa com segurança
		
	Altere (0) logo abaixo para refletir a posição das bibliotecas
		na sua árvore de diretórios.	

	Palavras-chave:	troca de sinal, raiz, varredura             
	por Tarcisio Praciano Pereira - 10 lições para aprender C
	Sobral, Agosto de 2007   - UVA
*/
                  

#include <stdio.h>
#include <math.h>
#include "ambiente.h" // (0) Altere aqui

float	f(float	x);
float raiz_tangente(float a, float b);

int	main()
{
	float	a=-5,b=5,delta=0.1; // (10) valores default
	float	epsilon=0.1, raiz;
	int	teste=0; // caso nao encontre raizes, teste=1
	//  *********** entrada de dados 
	printf("Forneça-me o intervalo [a,b] para busca de raizes: \n");
	a = entrada_float("a = ", a); // definida em ambiente.h
	b = entrada_float("b = ", b); // definida em ambiente.h
	printf("Forneça-me o passo  delta da malha para a  busca:\n");
	printf("Sugestão  0.01 <  delta   <  0.5  \n");
	delta = entrada_float("delta  = ", delta);
	printf("Forneça-me o erro epsilon (módulo máximo) :\n");
	printf("Sugestão  0.01 <  epsilon    <  0.5  \n");	
	epsilon = entrada_float("epsilon   = ", epsilon);	
	printf("Sua busca de raízes no intervalo [%f , %f] \n ",a,b);	
	printf("Precisão da malha: %f \n ", delta);		
	printf("Erro  (módulo máximo): %f \n ", epsilon);	
	// ***************   fim da entrada de dados
	apeteco2();  // definida em ambiente.h
	while( a <= b)
	{
		// (30) procura troca de sinal e tamanho
		if (  f(a)*f(a+delta)<=0  ) 		{
		if ( f(a) == 0 )
		{
		   printf("Uma raíz exata %f \n", a);
		   a = a + delta; // salto extra
		   teste = teste + 1; // conta raízes
		}
		else if ( f(a+delta) == 0 )
		     {
			printf("Uma raíz exata %f \n", a+delta);
			a = a + delta; // salto extra
			teste = teste + 1; // conta raízes
		     }  
		     else
		     {
			printf("Troca de sinal da função no intervalo ");
			printf("[ %f , %f] \n", a, a+delta);
			raiz =  raiz_tangente(a,a+delta);
			printf("Raiz p/ método da tangente x =  %f \n", raiz);
			printf("Valor de f na raíz aprox f(%f)=%f\n",raiz,f(raiz));
			a = a + delta;  // salto extra
			teste = teste + 1; // conta raízes
		     }

		} 	
		a = a + delta;
	}
	if (!teste)
		{
		printf("Nenhuma raíz foi encontrada no intervalo dado !\n");
		printf("Rode, novamente, o programa, com passo mais fino...\n");
		}
	if (teste == 1)
		printf("Achei uma raíz \n");
	else   	printf("Achei %d intervalos onde há raíz \n", teste);
return(0);
}

// há várias equações, para escolher uma, apague o comentário //
float	f(float	x)
{
	//return(-(x+3)*(x+3)*(x-2)*(x+2) ); // (50)
	// return( x*x*x*x*x + x*x*x*x + x*x*x + x*x + x + 1);  // (50)
	// return(x*x);    // (50) escolha somente um return()
	// return(x); // (50) 
	// return( x*x*x*x*x - 4*x*x*x + x*x + 0.2*sin(19*x) - 0.10782); // função com vários gogos...
	return( x*x*x*x*x - 4*x*x*x + x*x + 0.2*sin(19*x) ); // função com vários gogos...
}

// reta tangente y = f(a) + df(a)(x - a) 
// zero da reta tangente  x0 =  a - f(a)/df(a)  
float raiz_tangente(float a, float b)
{
	float epsilon=(b-a)/1000;  // precisão para o cálculo da raíz
	float M = (f(b)-f(a))/(b-a); // (61)  memoriza crescimento em [a,b]
	float x=a, m = (f(x+epsilon) - f(x))/epsilon; // deriv. aproximada	
	if (m*M < 0)
	while (m*M < 0)  // (62) pode ser ponto extremo com m = 0
	{ 
		x = x + 20*epsilon; // corre um pouco
		m = (f(x+epsilon) - f(x))/epsilon; 
		x = x - f(x)/m;
	}
	else 	x = x - f(x)/m; // raiz da tangente com der. aproximada  m
return(x);
}


/*
	Comentários:  

(10) Os dados do programa podem ser aceitos apenas dando enter quando
	for feita pergunta sobre valores a fornecer. Rode o programa
	apenas dando enter na primeira vez.

(30) Há dois testes - troca de sinal  e módulo máximo 
		experimente apagar o módulo máximo, deixando 
		apenas
		se ( (f(a)*f(a+delta)<=0)  )
		copie o texto acima e coloque em lugar de se() em (30),
		mas não apague porque você vai precisar deste programa
		ainda. Torne um comentário aquilo que você apagaria
		usando o símbolo  //  
	
(40)  teste = 0  evita que seja escrita a mensagem informando
	que nenhuma raiz foi encontrada.
	
(50)	em uma função somente um return()  deve ser
	executado. em f() há vários, todos desligados, menos um que
	é o que está em vigor. Troque pela equação desejada ou
	escolha outra equação.


(60)    No módulo raiz_tangente 
(61)	M é o coeficiente angular da reta secante em (a,f(a)) (b,f(b))
	para memorizar o crescimento global de f no intervalo de troca
	de sinal
(62)    A função pode ter muitos gogos no intervalo [a,b], oscilando
	antes de chegar no zero procurado.  Se m*M for negativo ou zero
	pego o próximo ponto na malha fina e volto a testar até
	que  m*M  seja positvo - m tem o mesmo sinal de M


*/
