Olá. Essa aqui é a resolução comentada do exercício 1.1.8 da página 34 do livro Estrutura de dados em C que transcrevo aqui:
Escreva uma especificação de TDA para os números complexos, a+
Tenenbaum, Langsam e Augesnstein (2013)
bi, onde abs(a+bi) é sqrt(a2+b2), (a+bi)+(c+di) é (a+c)+(b+d)i, (a+b)*(c+di) é
(a*c-b*d)+(a*d+b*c)i e -(a+bi) é (-a)+(-b)i
Falou Grego. Entendi lhufas!
Pois é, sem zoeira, quando vi esse enunciado, quase que desisti de tentar implementar. Pra que simplificar se é possível complicar?
Decifrando o enunciado:
Depois de tomar um café e assistir uns filmes no YT, tentei entender de novo esse enunciado, que ficou assim:
Escreva uma especificação de TDA para os números complexos (a+bi) onde:
- abs(a+bi) = sqrt(a2 + b2)
- (a+bi) + (c+di) = (a+c) + (b+d)i
- (a+b) * (c+di) = (a*c-b*d) + (a*d+b*c)i
- -(a+bi) = (-a) + (-b)i
Melhorou. mas aí veio o Antenor da Silva, o alter ego, e completou com linguagem de programador normal:
Crie um TDA – Tipo de Dado Abstrato que receba parâmetros e:
1- Calcule o valor absoluto, de acordo com a equação nr 1, acima.
Antenor da Silva
2- Calcule a soma de dois números imaginários, conforme com a eq. nr 2.
3- Multiplique dois números imaginários, na forma da eq. nr 3, acima.
4- Aplique a propriedade do sinal, de acordo com a eq. nr 4, acima.
Ahhh tahhhhh!
Antes de continuarmos:
Meu caro. Se esse artigo lhe ajudar e de alguma forma der um adianto para ti, vou ficar muito feliz se você clicar nos links de meus anunciantes e dar uma olhada no que eles tem para te oferecer. Grato :-).
Alguns pontos importantes:
A implementação de um TDA, já foi abordada anteriormente. Se quiser conferir: basta clicar aqui nesse link -> Tipo de Dados Abstratos<-
A implementação dessa solução pode ser baixada diretamente no repositório do GitHub, clicando aqui.
Eu sei que existe a biblioteca std::complex para manuseio de números complexos e poderia a utilizar para simplificar a implementação do código. Preciso lembrar que objetivo desse exercício é criar um TDA e as fórmulas dadas no enunciado são um pano de fundo para a parte principal, que é criar o TDA em si.
Sabe o que é bacana dessa implementação?
Se você não gostar da solução que eu dei, basta apagar, mantendo os testes unitários. Daí, ao executar os testes unitários, vão subir os erros e aí é só você ir montando um código, chamando as funções, resolvendo os erros e implementando a solução no seu estilo. Tem jeito melhor de estudar?
A implementação:
Conforme imagem abaixo segue a organização do projeto, começando pela pasta “Source” que contém a pasta “Headers”.
A pasta “Teste_unitario” foi inserida recursivamente nas pastas “Source” e “Headers”.
Na pasta “Source” ficam os arquivos: main.c, funcoes.c e o tda_nr_abstrato.c.
Na pasta “Headers” ficam os arquivos: funcoes.h e tda_nr_abstrato.h .
Na pasta “Teste_unitario” ficam os arquivos Cutest.h, teste_tda_nr_abstrato.h, Cutest.c e teste_tda_nr_abstrato.c.
Função dos arquivos:
main.c:
Esse arquivo é o início do programa. Ele contém os includes que permitem a importação da biblioteca que implementa o TDA e a biblioteca dos testes unitários, que são os arquivos “tda_nr_abstrato.h” e “Teste_unitario/teste_tda_nr_abstrato.h”, respectivamente.
Para facilitar a operação e desenvolvimento, foi implementado um controle que permite escolher entre 2 modos de operação independentes.
- Modo de “operação ou debug”. Nesse modo o programa fica para rodar no modo operação normal, ou no modo debug, quando roda os testes unitários.
- Modo de execução contínua ou única. Escolhendo o modo contínuo, o programa fica rodando em loop indefinidamente ou executa uma vez e termina.
A leitura do código main é bastante simples, pois as variáveis são inicializadas conforme o necessário e em seguida são realizadas as chamadas dos métodos do TDA que foi implantado.
Para simplificar o programa, ao invés de permitir ao usuário inserir dados, foi criada uma função “gera_randomico(double val) para fazer a inserção aleatória de dados no sistema.
O main, também é responsável por fazer a formatação da impressão e ele segue abaixo:
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "tda_nr_abstrato.h"
#include "Teste_unitario/teste_tda_nr_abstrato.h"
#include "funcoes.h"
/*
Exercício:
Escreva uma especificacao de TDA para os numeros complexos, a+
bi, onde abs(a+bi) eh sqrt(a^2+b^2), (a+bi)+(c+di)e(a+c)+(b+d)
i, (a+b)*(c+di) eh (a*c-b*d)+(a*d+b*c)i e -(a+bi) eh (-a)+(-b)i
Fonte: Tenembaum, Estrutura de dados usando C, ex 1.1.8, pg34.
Autor da soulucao: Renato de Pierri - nets-nuts.com.br
Interpretacao do exercicio:
Escreva uma especificacao de TDA para os numeros complexos a+bi onde:
1: abs(a+bi) = sqrt(a^2 + b^2)
2: (a+bi) + (c+di) = (a+c) + (b+d)i
3: (a+b) * (c+di) = (a*c-b*d) + (a*d+b*c)i
4: -(a+bi) = (-a) + (-b)i
Interpretacao da interpretacao da questão:
Criar um TDA - Tipo de Dado Abstrato que receba parametros e:
Calcule o valor absoluto, de acordo com a equação nr 1.
Calcule a soma de dois numeros imaginarios, de acordo com a equacao nr 2.
Multiplique dois numeros imaginarios, na forma da equacao nr 3.
Aplique a propriedade do sinal, de acordo com a equacao nr 4.
*/
//Suite de testes
CuSuite* CuGetSuite();
CuSuite* CuStringGetSuite();
int main()
{
//int debug = 1;
int debug = 0;
int continuo = 1;
//int continuo = 0;
double val[7];
char operadores[3];
op_imaginaria nr_img = Op_imaginaria_new();
do{
if (debug == 1){
RunAllTests();
}else{
printf("Implementação de Tipo de Dado Abstrato - TDA\n\n");
//=====================================================================
gera_randomico(val);
printf("Calculando o valor absoluto do numero imaginario "
"(%.1f + %.1fi)\n",val[0],val[1]);
operadores[0]='+';
absoluto(nr_img,val,operadores);
printf("O absoluto de (%.1f %c %.1fi)"
" eh (%.1f %c %.1f) = %.1f\n\n",
val[0],operadores[0],val[1],val[4],
operadores[0],val[5],(val[4]+val[5]));
//=====================================================================
gera_randomico(val);
operadores[0] = '+';
printf("Calculando a soma de %.1f + %.1fi com %.1f + %.1fi\n",
val[0],val[1],val[2],val[3]);
soma_2_imaginarios(nr_img,val,operadores);
printf("O valor da soma de (%.1f + %.1fi) %c (%.1f + %.1fi)"
" eh: (%.1f %c %.1fi)\n\n", val[0],val[1],operadores[0],
val[2], val[3], val[4],operadores[1],val[5]);
//=====================================================================
gera_randomico(val);
printf("Multiplicando os termos (%.1f + %.1f) com um nr imaginario "
"(%.1f + %.1fi) \n",val[0],val[1],val[2],val[3]);
operadores[0] = '*';
multiplica_termos_x_imaginario(nr_img,val,operadores);
printf("A multiplicacao dos termos (%.1f + %.1f) por (%.1f + %.1fi)"
" eh: (%.1f %c %.1fi)\n\n", val[0],val[1],
val[2], val[3], val[4],operadores[1], val[5]);
//=====================================================================
printf("Aplicando a regra do sinal \n");
gera_randomico(val);
operadores[0] = '-';
regra_sinal(nr_img,val,operadores);
printf("-(%.1f + %.1fi) eh: (%.1f) + (%.1fi)\n\n",
val[0],val[1],val[4],val[5]);
//=====================================================================
}
system("pause");
system("cls");
}while(continuo);
}
funcoes.h e funcoes.c
Esses dois arquivos contém a função gera_randomico(), conforme indicado abaixo:
funcoes.h:
#ifndef FUNCOES_H_INCLUDED
#define FUNCOES_H_INCLUDED
#include "tda_nr_abstrato.h"
void gera_randomico(double val[]);
#endif // FUNCOES_H_INCLUDED
funcoes.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "funcoes.h"
void gera_randomico(double val[]){
val[0] = rand() % 10;
val[1] = rand() % 10;
val[2] = rand() % 10;
val[3] = rand() % 10;
}
tda_nr_abstrato.h e tda_nr_abstrato.c
Esses dois arquivos contém o protótipo das operações permitidas ao TDA (tipo de dado abstrato) e a implementação do TDA, propriamente dita.
tda_nr_abstrato.h:
#ifndef TDA_NR_ABSTRATO_H_INCLUDED
#define TDA_NR_ABSTRATO_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
//Interface.
//Aqui lista a estrutura e as operacoes que podem ser
//realizadas na estrutura, bem como os parametros necessários.
typedef struct Op_imaginaria *op_imaginaria;
op_imaginaria Op_imaginaria_new(void);
//Conjunto de operacoes permitidas para a operacao com numeros imaginarios.
extern size_t obj_size(struct Op_imaginaria *);
extern void absoluto(struct Op_imaginaria *,double valores[], char operadores[]);
extern void soma_2_imaginarios(struct Op_imaginaria *, double valores[],
char operadores[]);
extern void multiplica_termos_x_imaginario(struct Op_imaginaria *,double valores[],
char operadores[]);
extern void regra_sinal(struct Op_imaginaria *,double valores[], char sinais[]);
extern void destroi_op_imaginaria(struct Op_imaginaria *);
#endif // TDA_NR_ABSTRATO_H_INCLUDED
tda_nr_abstrato.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "tda_nr_abstrato.h"
#include "Teste_unitario/teste_tda_nr_abstrato.h"
typedef struct Op_imaginaria{
double registro[7];
char op_in_out[3];
}opimg;
op_imaginaria Op_imaginaria_new(void){
op_imaginaria op_img = malloc(sizeof(struct Op_imaginaria));
int controle = 0;
while (controle <= 5){
op_img->registro[controle]=0;
controle++;
}
op_img->registro[6]='\0';
strcpy(op_img->op_in_out," \0");
return op_img;
}
void destroi_op_imaginaria(struct Op_imaginaria *op_img){
free(op_img);
}
//Implementacao das operacoes permitidas para o tipo op_imaginaria:
size_t obj_size(struct Op_imaginaria *op_img){
return sizeof op_img;
}
void absoluto(struct Op_imaginaria *op_img,
double valores[],
char operadores[]){
valores[4] = pow(valores[0],2);
valores[5] = pow(valores[1],2);
operadores[1] = '+';
}
void soma_2_imaginarios(struct Op_imaginaria *op_img,
double valores[],
char operadores[]){
valores[4] = valores[0] + valores[2];
valores[5] = valores[1] + valores[3];
operadores[1] = '+';
}
void multiplica_termos_x_imaginario(struct Op_imaginaria *op_img,
double valores[],
char operadores[]){
valores[4] = (valores[0] * valores[2]) - (valores[1] * valores[3]);
valores[5] = (valores[0] * valores[3]) + (valores[1] * valores[2]);
operadores[1] = '+';
}
void regra_sinal(struct Op_imaginaria *op_img, double valores[], char sinais[] ){
if (sinais[0]=='-'){
valores[4] = valores[0]* -1;
valores[5] = valores[1]* -1;
}else{
valores[4] = valores[0];
valores[5] = valores[1];
}
}
teste_tda_nr_abstrato.h e teste_tda_nr_abstrato.c
Esses arquivos correspondem à implementação dos testes unitários suportados pela suíte de testes open source: CuTest.h e CuTest.c.
Olhando com cuidado, você vai perceber que deu mais trabalho e ficou mais longo desenvolver os testes do que implementar o TDA de fato. Mesmo tendo acontecido isso, os testes unitários já estão prontos, então caso alguém deseje adicionar alguma funcionalidade nessa solução, as coisas já estão mastigadas e basta seguir em frente =P.
teste_tda_nr_abstrato.h:
#ifndef TESTE_TDA_NR_ABSTRATO_H_INCLUDED
#define TESTE_TDA_NR_ABSTRATO_H_INCLUDED
#include "CuTest.h"
CuSuite*StrUtilGetSuite();
void RunAllTests(void);
// Testes unitarios
void TesteValorAbsoluto1(CuTest *tc);
void TesteValorAbsoluto2(CuTest *tc);
void TesteSoma_2_Imaginarios1(CuTest *tc);
void TesteSoma_2_Imaginarios2(CuTest *tc);
void TesteMultiplica_termos_x_imaginario1(CuTest *tc);
void TesteMultiplica_termos_x_imaginario2(CuTest *tc);
void TesteRegraSinal(CuTest *tc);
#endif // TESTE_TDA_NR_ABSTRATO_H_INCLUDED
teste_tda_nr_abstrato.c:
#include <stdio.h>
#include <stdlib.h>
#include "teste_tda_nr_abstrato.h"
#include "../tda_nr_abstrato.h"
#include "CuTest.h"
#include "string.h"
CuSuite* StrUtilGetSuite();
void RunAllTests(void){
CuString* output = CuStringNew();
CuSuite* suite = CuSuiteNew();
CuSuiteAddSuite(suite, StrUtilGetSuite());
CuSuiteRun(suite);
CuSuiteSummary(suite, output);
CuSuiteDetails(suite, output);
printf ("%s\n\n", output->buffer);
}
// Testes unitarios
void TesteValorAbsoluto1(CuTest *tc){
CuString* str = CuStringNew();
op_imaginaria nr_img = Op_imaginaria_new();
double val[7];
char operadores[3];
char resp[4];
char resultado[8];
//Inicializando o teste
int controle = 0;
val[0]=1;
val[1]=7;
val[2]=0;
val[3]=0;
for(controle = 0;controle <=7;controle++){
resultado[controle]='\0';
}
operadores[0]='+';
//Testando a funcao
absoluto(nr_img,val,operadores);
//Preparando o resultado para assercao
for (controle = 0;controle<=6;controle++){
itoa((int)val[controle],resp,10);
strcat(resultado,resp);
}
CuStringAppend(str,resultado );
CuAssertStrEquals(tc, "17001490", str->buffer);
}
void TesteValorAbsoluto2(CuTest *tc){
CuString* str = CuStringNew();
op_imaginaria nr_img = Op_imaginaria_new();
double val[7];
char operadores[3];
//Inicializando o teste
val[0]=1;
val[1]=7;
val[2]=0;
val[3]=0;
operadores[0]='+';
//Testando a funcao
absoluto(nr_img,val,operadores);
//Preparando o resultado para assercao
CuStringAppend(str,operadores );
CuAssertStrEquals(tc, "++", str->buffer);
}
void TesteSoma_2_Imaginarios1(CuTest *tc){
CuString* str = CuStringNew();
op_imaginaria nr_img = Op_imaginaria_new();
double val[7];
char operadores[3];
char resp[4];
char resultado[9];
//Inicializando o teste
int controle = 0;
val[0]=9;
val[1]=4;
val[2]=8;
val[3]=8;
for(controle = 0;controle <=8;controle++){
resultado[controle]='\0';
}
operadores[0]='+';
//Testando a funcao
soma_2_imaginarios(nr_img,val,operadores);
//Preparando o resultado para assercao
for (controle = 0;controle<=6;controle++){
itoa((int)val[controle],resp,10);
strcat(resultado,resp);
}
CuStringAppend(str,resultado );
CuAssertStrEquals(tc, "948817120", str->buffer);
}
void TesteSoma_2_Imaginarios2(CuTest *tc){
CuString* str = CuStringNew();
op_imaginaria nr_img = Op_imaginaria_new();
double val[7];
char operadores[3];
//Inicializando o teste
val[0]=9;
val[1]=4;
val[2]=8;
val[3]=8;
operadores[0]='+';
//Testando a funcao
absoluto(nr_img,val,operadores);
CuStringAppend(str,operadores );
CuAssertStrEquals(tc, "++", str->buffer);
}
void TesteMultiplica_termos_x_imaginario1(CuTest *tc){
CuString* str = CuStringNew();
op_imaginaria nr_img = Op_imaginaria_new();
double val[7];
char operadores[3];
char resp[4];
char resultado[9];
//Inicializando o teste
int controle = 0;
val[0]=3;
val[1]=1;
val[2]=2;
val[3]=3;
for(controle = 0;controle <=8;controle++){
resultado[controle]='\0';
}
operadores[0]='+';
//Testando a funcao
multiplica_termos_x_imaginario(nr_img,val,operadores);
//Preparando o resultado para assercao
for (controle = 0;controle<=6;controle++){
itoa((int)val[controle],resp,10);
strcat(resultado,resp);
}
CuStringAppend(str,resultado );
CuAssertStrEquals(tc, "31233110", str->buffer);
}
void TesteMultiplica_termos_x_imaginario2(CuTest *tc){
CuString* str = CuStringNew();
op_imaginaria nr_img = Op_imaginaria_new();
double val[7];
char operadores[3];
//Inicializando o teste
val[0]=3;
val[1]=1;
val[2]=2;
val[3]=3;
operadores[0]='+';
//Testando a funcao
absoluto(nr_img,val,operadores);
CuStringAppend(str,operadores );
CuAssertStrEquals(tc, "++", str->buffer);
}
void TesteRegraSinal(CuTest *tc){
CuString* str = CuStringNew();
op_imaginaria nr_img = Op_imaginaria_new();
double val[7];
char operadores[3];
int controle;
char resultado[5];
//Inicializando o teste
for (controle=0;controle<=4;controle++){
resultado[controle]='\0';
}
char temp[3];
val[0] = 1;
val[1] = 7;
val[2] = 0;
val[3] = 0;
operadores[0]='-';
//Testando a funcao
regra_sinal(nr_img,val,operadores);
//Preparando o resultado para assercao
for(controle = 4;controle<=5;controle++){
itoa((int)val[controle],temp,10);
strcat(resultado,temp);
}
CuStringAppend(str,resultado );
CuAssertStrEquals(tc, "-1-7", str->buffer);
}
CuSuite*StrUtilGetSuite(){
CuSuite* suite = CuSuiteNew();
SUITE_ADD_TEST(suite,TesteValorAbsoluto1);
SUITE_ADD_TEST(suite,TesteValorAbsoluto2);
SUITE_ADD_TEST(suite,TesteSoma_2_Imaginarios1);
SUITE_ADD_TEST(suite,TesteSoma_2_Imaginarios2);
SUITE_ADD_TEST(suite,TesteMultiplica_termos_x_imaginario1);
SUITE_ADD_TEST(suite,TesteMultiplica_termos_x_imaginario2);
SUITE_ADD_TEST(suite,TesteRegraSinal);
}
Pessoal:
Gente, entenda como alguém fazendo um passatempo Coquetel e sei que provavelmente devem existir soluções mais elegantes e ou mais corretas.
Se houver algo para melhorar nessa implementação e queira contribuir, me avise que terei prazer em conversar sobre o assunto para vermos o que pode ser feito.
Como sempre, muito obrigado e não esqueça de clicar nos anúncios e ver o que os anunciantes tem de bom para te oferecer.
Publicado por Renato de Pierri em 19/01/2023.
Bibliografia:
TENENBAUM, Aaron M.; LANGSAM, Yedidyah; AUGESNSTEIN, Moshe J.. Estruturas de Dados Usando C. São Paulo: Pearson, 2013. 884 p. ISBN 13: 978-85-346-0348-5