Criando um TDA, Tenenbaum 1.1.8

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+
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

Tenenbaum, Langsam e Augesnstein (2013)

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:

  1. abs(a+bi) = sqrt(a2 + b2)
  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

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.
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.

Antenor da Silva

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.

Essa solução utiliza as bibliotecas de teste unitário CuTest que é de código aberto e pode ser baixada diretamente no site do SourceForge, 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.

Arquivos do projeto

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

Last updated by at .

Deixe um comentário