João Araujo
Dr. en Informatique, Université de Versailles, França.

Primeira Prova 2007-2

Enunciado

Uma constante de especial interesse na física é a chamada constante da estrutura fina, α. Esta constante combina a velocidade da luz, c, a carga elétrica do elétron, e, a constante de Planck, h, e a chamada permissividade do vácuo, ɛ0. A relação entre estas quantidades, dada pela fórmula α=e2/2ɛ0hc, determinam as características de nosso universo. Uma pequena variação em seus valores faria com que a fusão nuclear nas estrelas fosse impossível ou que a matéria não pudesse se agregar, tornando nosso universo inviável.

  1. Escreva um programa em ANSI C que leia do teclado um número seguido por um espaço e então por uma letra. Se a letra for 'c' ou 'C', o programa deve considerar a entrada como a nova velocidade da luz; se for 'e' ou 'E', deve considerar como a nova carga do elétron; se for 'h' ou 'H', a nova constante de Planck e se for 'p' ou 'P', a nova permissividade do vácuo. O programa deve calcular a nova constante de estrutura fina ou emitir uma mensagem de erro, se a letra ou os números estiverem errados. Imprima este valor e seu inverso, ou seja, α e 1/α, com 10 casas decimais. (3 pts)
  2. Use um arquivo constantes.h que tenha os valores das constantes citadas acima. As constantes seriam C_LUZ (299792458 m/s), E_ELETRON (1.602176487×10-19C), H_PLANCK (6.62606896×10-34J.s), P_VACUO (8.854187817×10-12F/m). (1pt)
  3. Faça uma função que compare o valor calculado com os novos valores e aquele calculado com as constantes clássicas. Dê a diferença em valores absolutos e em porcentagem. (1 pt).
  4. Modifique seu programa de modo a que ele faça incrementos de 1% na constante fornecida, caso o valor da constante seja maior que o valor real; ou decrementos de 1%, caso o valor calculado seja menor que o real, até que a diferença da constante da estrutura fina fique mais de 4% diferente do valor real. Neste valor, o nível de energia do núcleo de carbono seria tão alterado que a produção deste elemento cessaria nas estrelas, criando um universo onde seria impossível a vida baseada em carbono. (3pts)
  5. Faça com que seu programa possa alterar até as 4 constantes numa única linha. Cada constante segue o padrão da questão 1. (2pt)

Resolução

Vamos começar definindo algumas constantes:

#define C_LUZ 299792458 //m/s
#define E_ELETRON 1.602176487e-19 // C
#define H_PLANCK 6.62606896e-34 // J.s
#define P_VACUO 8.854187817e-12 // F/m

Feito isso, podemos calcular alfa universal também como constante:

#define ALFA  ((E_ELETRON*E_ELETRON)/(2*P_VACUO*H_PLANCK*C_LUZ))

Também vamos definir algumas constantes auxiliares:

#define MAXLINE 100
#define ERRO 0

Agora, vamos começar a garantir o primeiro item.

Item 1

Primeiro, vamos ler a linha, com nosso clássico getline(), e converter tudo para maiúsculas, para não ter que esquentar a cabeça com letras minúsculas.

getline(line,MAXLINE);
convertemaiusculas(line); //converte todas as letras para maiúsculas

Depois, vamos validar a linha lida e separar os elementos número e letra, que vai dar o que teremos que modificar na chamada da função que vai calcular alfa.

if (valida(line,MAXLINE)) {
   constante=getnumber(line);
   switch (letra=getletter(line)){
      case 'C': alfa=calcula_alfa(E_ELETRON,P_VACUO,H_PLANCK,constante);
	            break;
      case 'E': alfa=calcula_alfa(constante,P_VACUO,H_PLANCK,C_LUZ);
	            break;
      case 'P': alfa=calcula_alfa(E_ELETRON,constante,H_PLANCK,C_LUZ);
	            break;
      case 'H': alfa=calcula_alfa(E_ELETRON,P_VACUO,constante,C_LUZ);
	            break;
      default: printf("Letra errada");
	            break;
   }
   printf("O valor de alfa= %12.10e e 1/alfa=%12.10e\n",alfa, 1/alfa);

Vamos agora codificar as funções:
convertemaiusculas() é fácil, mas temos que lembrar de incluir ctype.h:

void convertemaiusculas(char line[])
 {
	 int i;
	 for(i=0;line[i]!='\0';i++)
		 line[i]=toupper(line[i]);
 }

A função de validação vai ser mais chatinha, mas nada impossível, os comentários estão no próprio código:

/** função  int valida(char[],int);	
*   retorna ERRO se não for válida a string de entrada.
*   ou primeira posição após o fim da string válida
*/
int valida(char line[],int max){
 
	int i=0;
 
	//pula espaços em branco.
	while (line[i]==' ')
		i++;
 
	// testa se começa com dígito ou ponto.
	if (!isdigit(line[i]) && line[i]!='.')
		return ERRO;
 
	//pula todos os digitos 
	while(isdigit(line[++i]))
		 ;
 
	// o caractere seguinte pode ser ponto...
	// e devemos pular outros digitos até o fim do número.
	if (line[i]=='.')
		while (isdigit (line[++i]))
			;
 
        // ou "E", para o expoente
	if (line[i]=='E'){
		// testa se o expoente tem sinal
		if (line[++i]=='-' || line[i]=='+') 
			i++; //pula sinal.
		if (isdigit(line[i])) 
			   while (isdigit (line[++i]))
			       ;
		else // se não for sinal nem dígito, depois de "E", é erro.
			return ERRO;
	}	
 
	// agora tem que vir espaço.
	if (line[i]!=' ')
		return ERRO;
 
	//agora a letra.
	switch (line[++i]){
		case 'C':
		case 'P':
		case 'H':
		case 'E':
			return ++i;
		    break;
	 	default: return ERRO;
	}
}

O cálculo de alfa também é simples:

/* função calcula_alfa
   retorna o valor de alfa, dadas as constantes.
*/
double calcula_alfa(double e_eletron,
		    double p_vacuo,
		    double h_planck,
		    double c_luz)
{
    return (e_eletron*e_eletron)/(2*p_vacuo*h_planck*c_luz);	
}

Falta a função getnumber(), que nem precisaria estar aqui, pois bastaria usar atof() da stdlib.h, que deve ser incluída no programa, mas fiz isto para manter uma unidade no programa.

/* função getnumber
   retorna o valor em double de string.
   poderia ser usado apenas atof no programa principal.
*/
double getnumber (char line[]){
	return atof(line);
}

e, finalmente, getletter(), que retorna a letra da constante que devemos converter.

/* retorna o primeiro caractere depois do espaço 
   em branco na string de entrada 
   esta função pressupõe uma string já validada.
*/
char getletter (char line[]){
	int i;
	char c;
 
	for (i=0;isdigit(c=line[i])||c=='.' || c=='E'||c=='-' || c=='+';i++)
		;
	return line[++i];
}

Item 2

O item 2 é ponto dado. basta criar um arquivo com as constantes e inclui-lo no início de seu programa.

#include "prova2007-2p1.h"

Item 3

Vamos criar uma função show_dif() que recebe o alfa calculado e compara com a constante universal:

/* imprime os valores absoluto e percentual de diferença  */
void show_dif(double alfa_calculado)
{
	double dif=ALFA-alfa_calculado;
 
	dif=(dif<0)?-dif:dif;
	printf("Diferença absoluta= %12.10e\n",dif);
	printf("Diferença percentual= %.4f%%\n",100*dif/ALFA);
}

Item 4

Este item é mais trabalhoso, mas nada difícil. vamos colocar um switch no programa principal para chamar a função com os valores corretos. Para cada letra, chamamos modifica_alfa() com parâmetros diferentes.

  switch (letra){
      case 'C': modifica_alfa(letra, E_ELETRON,P_VACUO,H_PLANCK,constante);
	            break;
      case 'E': modifica_alfa(letra, constante,P_VACUO,H_PLANCK,C_LUZ);
	            break;
      case 'P': modifica_alfa(letra, E_ELETRON,constante,H_PLANCK,C_LUZ);
	            break;
      case 'H': modifica_alfa(letra, E_ELETRON,P_VACUO,constante,C_LUZ);
	            break;
      default: printf("Letra errada");
	            break;
   }

A função modifica_alfa() fica assim:

/* função modifica_alfa
   modifica a constante em 1% até que alfa seja
   modificado de mis de 4%
*/
void modifica_alfa( char letra, 
		    double e_eletron,
		    double p_vacuo,
		    double h_planck,
		    double c_luz)
{
	double dif, alfa;
	double umporcento;
	int sentido;
 
	alfa=calcula_alfa(e_eletron,p_vacuo,h_planck,c_luz);
	sentido=(alfa<ALFA)?-1:1;
	dif=ALFA-alfa;
 
	dif=(dif<0)?-dif:dif;
	show_dif(alfa);
 
	//calcula 1% da variável em questão.
	switch (letra){
		 case 'E': umporcento=0.01*e_eletron;
		 		   break;
		 case 'P': umporcento=0.01*p_vacuo;
		 		   break;
		 case 'H': umporcento=0.01*h_planck;
		 		   break;
		 case 'C': umporcento=0.01*c_luz;
			       break;
		 default: printf("Erro\n");
		           break;
	 }
 
	// incrementa ou decrementa de acordo com sentido.
	umporcento*=sentido;
 
	while ( 100*dif/ALFA<4){
	 switch (letra){
		 case 'E': alfa=calcula_alfa(e_eletron+=umporcento,p_vacuo,h_planck,c_luz);
			       printf("nova e_eletron=%.10e\n",e_eletron);
		 		   break;
		 case 'P': alfa=calcula_alfa(e_eletron,p_vacuo+=umporcento,h_planck,c_luz);
			       printf("nova p_vacuo=%.10e\n",p_vacuo);
		 		   break;
		 case 'H': alfa=calcula_alfa(e_eletron,p_vacuo,h_planck+=umporcento,c_luz);
			       printf("nova h_planck=%.10e\n",h_planck);
		 		   break;
		 case 'C': alfa=calcula_alfa(e_eletron,p_vacuo,h_planck,c_luz+=umporcento);
			       printf("nova c luz=%.0f\n",c_luz);
			       break;
		 default: printf("Erro\n");
		           break;
	 }
	 dif=ALFA-alfa;
	 dif=(dif<0)?-dif:dif;
	 show_dif(alfa);
	}
}

Item 5

O item 5 pede que tratemos até as 4 constantes numa única linha de entrada. A abordagem usada foi converter uma constante de string para double, apagá-la da string e converter a próxima. O processo é repetido até acabar a linha ou uma constante inválida for detectada.

/* calcula alfa com várias constantes modificadas numa única linha
*/
void calcula_todas(char line[],int max)
{
	int indice,i,j;
	char letra;
	double constante, 
	       c_luz=C_LUZ,
	       e_eletron=E_ELETRON,
	       h_planck=H_PLANCK,
	       p_vacuo=P_VACUO,
	       alfa;
 
	// valida a constante na string, até que não haja mais
	// constante a ser lida.
	while (indice=valida(line,max)){
		constante=getnumber(line);
      switch (letra=getletter(line)){
        case 'C': c_luz=constante;
	            break;
	case 'E':e_eletron=constante;
	            break;
	case 'P': p_vacuo=constante;
	            break;
	case 'H': h_planck=constante;
	            break;
        default: printf("Letra errada");
	            break;
     }
	 // copia o restante da string para o início, eliminando a que já 
	 // foi convertida.
	 for (i=0,j=indice+1;(line[i]=line[j])!='\0';i++,j++)
		 ;
	}
	alfa=calcula_alfa(e_eletron, p_vacuo,h_planck,c_luz);
	printf("O valor de alfa= %12.10e, e 1/alfa=%12.10e\n",alfa, 1/alfa);
}

programa final

Durante prova, estes itens devem ir se construindo pouco a pouco. Aqui, apresento o resultado final. Primeiro o arquivo prova2007-2p1.h:

/***************************************************************************
 *            prova2007-2p1.h
 *
 *  Fri Oct 26 15:00:33 2007
 *  Constantes da física
 ****************************************************************************/
#define C_LUZ 299792458 //m/s
#define E_ELETRON 1.602176487e-19 // C
#define H_PLANCK 6.62606896e-34 // J.s
#define P_VACUO 8.854187817e-12 // F/m

Agora o programa completo:

/***************************************************************************
 *            prova2007-2p1.c
 *
 *  Fri Oct 26 14:58:46 2007
 *  Copyright  2007  João Araujo
 ****************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "prova2007-2p1.h"
 
// calcula alfa como constante.
#define ALFA  ((E_ELETRON*E_ELETRON)/(2*P_VACUO*H_PLANCK*C_LUZ))
#define MAXLINE 100
#define ERRO 0
 
int getline(char[],int);
void convertemaiusculas(char line[]);
int valida(char[],int);
double calcula_alfa(double,double,double,double);
double getnumber (char[]);
char getletter (char[]);
void show_dif(double);
void modifica_alfa(char, double, double,double,double);
void calcula_todas(char[], int);
 
int main(){
 
char line[MAXLINE];
char numero;
char letra;
double alfa, constante;	
printf("O valor de alfa= %12.10e, e 1/alfa=%12.10e\n",ALFA, 1/ALFA);
printf("\nQuestão 1: Ler apenas um valor e variar no cálculo de alfa\n");
getline(line,MAXLINE);
convertemaiusculas(line); //converte todas as letras para maiúsculas
 
if (valida(line,MAXLINE)) {
   constante=getnumber(line);
   switch (letra=getletter(line)){
      case 'C': alfa=calcula_alfa(E_ELETRON,P_VACUO,H_PLANCK,constante);
	            break;
      case 'E': alfa=calcula_alfa(constante,P_VACUO,H_PLANCK,C_LUZ);
	            break;
      case 'P': alfa=calcula_alfa(E_ELETRON,constante,H_PLANCK,C_LUZ);
	            break;
      case 'H': alfa=calcula_alfa(E_ELETRON,P_VACUO,constante,C_LUZ);
	            break;
      default: printf("Letra errada");
	            break;
   }
 
   printf("O valor de alfa= %12.10e e 1/alfa=%12.10e\n",alfa, 1/alfa);
   printf("\nQuestão 2: É apenas a inclusão do header de constantes\n");
   printf("\nQuestão : Dar diferença em valores absolutos e relativos\n");
 
   show_dif(alfa);
 
   printf("\nQuestão 4: Variar constante até que alfa seja mais de 4%% diferente\n");
   switch (letra){
      case 'C': modifica_alfa(letra, E_ELETRON,P_VACUO,H_PLANCK,constante);
	            break;
      case 'E': modifica_alfa(letra, constante,P_VACUO,H_PLANCK,C_LUZ);
	            break;
      case 'P': modifica_alfa(letra, E_ELETRON,constante,H_PLANCK,C_LUZ);
	            break;
      case 'H': modifica_alfa(letra, E_ELETRON,P_VACUO,constante,C_LUZ);
	            break;
      default: printf("Letra errada");
	            break;
   }
 
   printf("\nQuestão 5: Tratar até 4 constantes numa única linha\n");
   getline(line,MAXLINE);
   calcula_todas(line, MAXLINE);
  }
  else
    printf("Erro\n");
 
}
 
/* getline:  get line into s, return length (copiado do livro K&R)*/
int getline(char s[], int lim)
   {
       int c, i;
 
       i = 0;
       while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
           s[i++] = c;
       if (c == '\n')
           s[i++] = c;
       s[i] = '\0';
       return i;
   }
 
void convertemaiusculas(char line[])
 {
	 int i;
	 for(i=0;line[i]!='\0';i++)
		 line[i]=toupper(line[i]);
 }
 
/** função  int valida(char[],int);						*
*   retorna ERRO se não for válida a string de entrada.	*
*   ou primeira posição após o fim da string válida     *  
*														*/
int valida(char line[],int max){
 
	int i=0;
 
	//pula espaços em branco.
	while (line[i]==' ')
		i++;
 
	// testa se começa com dígito ou ponto.
	if (!isdigit(line[i]) && line[i]!='.')
		return ERRO;
 
	//pula todos os digitos 
	while(isdigit(line[++i]))
		 ;
 
	// o caractere seguinte pode ser ponto...
	// e devemos pular outros digitos até o fim do número.
	if (line[i]=='.')
		while (isdigit (line[++i]))
			;
 
    // ou "E", para o expoente
	if (line[i]=='E'){
		// testa se o expoente tem sinal
		if (line[++i]=='-' || line[i]=='+') 
			i++; //pula sinal.
		if (isdigit(line[i])) 
			   while (isdigit (line[++i]))
			       ;
		else // se não for sinal nem dígito, depois de "E", é erro.
			return ERRO;
	}	
 
	// agora tem que vir espaço.
	if (line[i]!=' ')
		return ERRO;
 
	//agora a letra.
	switch (line[++i]){
		case 'C':
		case 'P':
		case 'H':
		case 'E':
			return ++i;
		    break;
	 	default: return ERRO;
	}
 
}
 
/* função calcula_alfa
   retorna o valor de alfa, dadas as constantes.
*/
double calcula_alfa(double e_eletron,
					double p_vacuo,
					double h_planck,
					double c_luz)
{
 
	return (e_eletron*e_eletron)/(2*p_vacuo*h_planck*c_luz);	
}
 
/* função getnumber
   retorna o valor em double de string.
   poderia ser usado apenas atof no programa principal.
*/
double getnumber (char line[]){
	return atof(line);
}
 
/* retorna o primeiro caractere depois do espaço 
   em branco na string de entrada 
   esta função pressupõe uma string já validada.
*/
char getletter (char line[]){
	int i;
	char c;
 
	for (i=0;isdigit(c=line[i])||c=='.' || c=='E'||c=='-' || c=='+';i++)
		;
	return line[++i];
}
 
/* imprime os valores absoluto e percentual de diferença  */
void show_dif(double alfa_calculado)
{
	double dif=ALFA-alfa_calculado;
 
	dif=(dif<0)?-dif:dif;
	printf("Diferença absoluta= %12.10e\n",dif);
	printf("Diferença percentual= %.4f%%\n",100*dif/ALFA);
}
 
/* função modifica_alfa
   modifica a constante em 1% até que alfa seja
   modificado de mis de 4%
*/
void modifica_alfa( char letra, 
		    double e_eletron,
		    double p_vacuo,
		    double h_planck,
		    double c_luz)
{
	double dif, alfa;
	double umporcento;
	int sentido;
 
	alfa=calcula_alfa(e_eletron,p_vacuo,h_planck,c_luz);
	sentido=(alfa<ALFA)?-1:1;
	dif=ALFA-alfa;
 
	dif=(dif<0)?-dif:dif;
	show_dif(alfa);
 
	//calcula 1% da variável em questão.
	switch (letra){
		 case 'E': umporcento=0.01*e_eletron;
		 		   break;
		 case 'P': umporcento=0.01*p_vacuo;
		 		   break;
		 case 'H': umporcento=0.01*h_planck;
		 		   break;
		 case 'C': umporcento=0.01*c_luz;
			       break;
		 default: printf("Erro\n");
		           break;
	 }
 
	// incrementa ou decrementa de acordo com sentido.
	umporcento*=sentido;
 
	while ( 100*dif/ALFA<4){
	 switch (letra){
		 case 'E': alfa=calcula_alfa(e_eletron+=umporcento,p_vacuo,h_planck,c_luz);
			       printf("nova e_eletron=%.10e\n",e_eletron);
		 		   break;
		 case 'P': alfa=calcula_alfa(e_eletron,p_vacuo+=umporcento,h_planck,c_luz);
			       printf("nova p_vacuo=%.10e\n",p_vacuo);
		 		   break;
		 case 'H': alfa=calcula_alfa(e_eletron,p_vacuo,h_planck+=umporcento,c_luz);
			       printf("nova h_planck=%.10e\n",h_planck);
		 		   break;
		 case 'C': alfa=calcula_alfa(e_eletron,p_vacuo,h_planck,c_luz+=umporcento);
			       printf("nova c luz=%.0f\n",c_luz);
			       break;
		 default: printf("Erro\n");
		           break;
	 }
	 dif=ALFA-alfa;
	 dif=(dif<0)?-dif:dif;
	 show_dif(alfa);
	}
}
 
/* calcula alfa com várias constantes modificadas numa única linha
*/
void calcula_todas(char line[],int max)
{
	int indice,i,j;
	char letra;
	double constante, 
	       c_luz=C_LUZ,
	       e_eletron=E_ELETRON,
	       h_planck=H_PLANCK,
	       p_vacuo=P_VACUO,
	       alfa;
 
	// valida a constante na string, até que não haja mais
	// constante a ser lida.
	while (indice=valida(line,max)){
		constante=getnumber(line);
      switch (letra=getletter(line)){
        case 'C': c_luz=constante;
	            break;
	case 'E':e_eletron=constante;
	            break;
	case 'P': p_vacuo=constante;
	            break;
	case 'H': h_planck=constante;
	            break;
        default: printf("Letra errada");
	            break;
     }
	 // copia o restante da string para o início, eliminando a que já 
	 // foi convertida.
	 for (i=0,j=indice+1;(line[i]=line[j])!='\0';i++,j++)
		 ;
	}
	alfa=calcula_alfa(e_eletron, p_vacuo,h_planck,c_luz);
	printf("O valor de alfa= %12.10e, e 1/alfa=%12.10e\n",alfa, 1/alfa);
}

O total de linhas, sem contar as linhas de comentário, foi de 181 linhas.

c/primeira_prova_-_2007-2.txt · Última modificação: 28/10/2007 20:53:53 (edição externa)
geomatica Creative Commons License Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0