quinta-feira, 21 de agosto de 2008

Uso do Diagrama de Nassi-Schneiderman

A solução para o mesmo problema, agora com o uso do diagrama Nassi-Schneiderman:

 

Equação 2o. Grau

 

Este diagrama também é chamado de Diagrama de Chapin.

Referências:

 

Até a próxima.

Uso do Diagrama de Blocos

Para resolver o problema proposto, a seguir temos a seqüência lógica dos procedimentos necessários apresentada através do recurso Diagrama de Blocos:

 

Equação 2o.Grau

 

Links indicados para leitura complementar:

http://www.manzano.pro.br/tutor/algoritmo/ptalg006.zip

http://www.fw.uri.br/~leticia/ApostilaAlgoritmos2006.pdf

 

Até a próxima.

quarta-feira, 20 de agosto de 2008

Uma abordagem para a resolução das raízes de uma equação de 2º grau

Algoritmo expresso em forma textual de uma seqüência imperativa de comandos:

1) Obter coeficientes a, b, c;
2) Coeficiente a = 0 ?
    2.1) Então: preparar Resposta = "equação inválida";
    2.2) Senão:
        2.2.1) Calcular delta = b^2 - 4*a*c;
        2.2.2) Valor de delta < 0 ?
            2.2.2.1) Então: preparar Resposta = "inexistência de solução Real";
            2.2.2.2) Senão: valor de delta = 0 ?
                2.2.2.2.1) Então:
                    2.2.2.2.1.1) Calcular x = - b / 2 * a;
                    2.2.2.2.1.2) Preparar Resposta = "X = " + ConverterParaTexto( x );
                2.2.2.2.2) Senão:
                    2.2.2.2.2.1) Calcular x1 = ( - b + RaizQuadrada( delta ) ) / 2 * a;
                    2.2.2.2.2.2) Calcular x2 = ( - b - RaizQuadrada( delta ) ) / 2 * a;
                    2.2.2.2.2.3) Preparar Resposta = "    X1 = " +
                                                        ConverterParaTexto( x1 ) + 
                                                    "    X2 = " +
                                                        ConverterParaTexto( x2 );
3) Apresentar Resposta;

 

Considerações:

1) o conceito de biblioteca de funções, previamente implementadas na maioria das linguagens de programação de alto nível, permite a abstração de certas operações elementares e corriqueiras, como exemplo a linguagem de programação C Ansi oferece:

  • obtenção de raiz quadrada:  sqrt( valor );
  • conversão/concatenação de dados diversos para texto: sprintf( buffer, "formatação", variáveis );

2) as operações aritméticas básicas são normalmente representadas pelos símbolos: + - * /

3) o operador de exponenciação ou potenciação vai depender da linguagem de programação: ** ou ^ são os casos mais usuais, porém tomando a linguagem de programação C Ansi como exemplo, existe a função de biblioteca pow(a, n) para calcular a elevado a n;

4) também é comum a necessidade de concatenção de textos, variando muito entre as linguagens de programação, mas podendo ser representada pelo operador + ou & ou até mesmo por funções de biblioteca; no caso da linguagem C Ansi podemos usar a mesma função sprintf() mencionada acima;

5) ao fazer uso de operadores relacionais >, < e = devemos tomar cuidado para não confundir o teste de igualdade com a operação de atribuição:

Atribuição Teste de igualdade Linguagem
delta = pow(b,2) - 4 * a * c if ( delta == 0 ) C ansi, C++
delta := b ** 2 - 4 * a * c if ( delta = 0 ) Pascal, Delphi

6) por último, uma consulta ao dicionário Michaelis (http://michaelis.uol.com.br/moderno/portugues/index.php?lingua=portugues-portugues&palavra=dentear) nos apresenta o verbo: "dentear (den.te.ar) (dente+ear) vtd 1 Formar dentes em. 2 Recortar, chanfrar. Var: dentelar.". Reparar que o algoritmo acima apresentado em forma textual, assim como a escrita de comandos na maioria das linguagens de programação de alto nível, devem usar este recurso para facilitar a leitura dinâmica dos mesmos e agilizar a compreensão do raciocínio, assim como acelerar e manter um controle sobre o fluxo de execução das instruções; ou seja, um hábito a ser desenvolvido.

 

Até a próxima.

 

Propondo um problema clássico para estudo

Dada uma equação de 2º grau genérica:

image

Encontrar a solução para f(x) = 0, obedecendo a restrição do domínio dos números Reais.

Os coeficientes a, b, c deverão ser informados como entrada para o algoritmo a ser desenvolvido.

Utilizar o método de Bhaskara (http://pt.wikipedia.org/wiki/Bhaskara) e como resposta considerar as possibilidades:

1) equação inválida;

2) inexistência de solução Real;

3) uma raiz apenas;

4) duas raízes;

 

Até a próxima.

LG1 - Segundo semestre de 2008

 

Boas-vindas para todos e expresso aqui meus votos para que tenham um proveitoso semestre.

Um grande abraço e até a próxima.

terça-feira, 24 de junho de 2008

Trabalhando com objetos da classe Fila<AnsiString> no Borland C++ Builder


Fila ADT
Uma fila é um tipo abstrato de dados (ADT: abstract data type) que pode ser implementado em C++ como mostra a classe a seguir.
Começando pela declaração da interface da classe:
// início do arquivo "Fila.h"
//---------------------------------------------------------------------------
#ifndef FilaH
#define FilaH
// interface da classe Fila<ADT>
template <class objectType>
class Fila
{
        private:
                class Node
                {
                        public:
                                objectType *objetoCorrente;
                                Node *nodeSucessor;
                        public:
                                Node( objectType* );    // construtor
                                ~Node( void );          // destrutor
                };
        private:
                Node *nodeInicial, *nodeFinal;
                int qtdNodes;
        public:
                Fila( void );                           // construtor
                ~Fila( void );                          // destrutor
                void Guardar( objectType* );
                objectType* Retirar( void );
                int Tamanho( void );
};
//---------------------------------------------------------------------------
// Implementação da classe Fila<ADT>
//---------------------------------------------------------------------------
#include "Fila.cpp"
//---------------------------------------------------------------------------
#endif
// fim do arquivo "Fila.h"
A seguir temos a implementação dos métodos:
// início do arquivo "Fila.cpp"
//---------------------------------------------------------------------------
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Atenção: RETIRAR A LINHA #include "Fila.h"
//---------------------------------------------------------------------------
// construtor da classe "Fila"
template <class objectType>
Fila<objectType> :: Fila( void )
{
        this->qtdNodes = 0;
        this->nodeInicial = NULL;
        this->nodeFinal = NULL;
}
// destrutor da classe "Fila"
template <class objectType>
Fila<objectType> :: ~Fila( void )
{
        Node *_nodeCorrente = this->nodeInicial,  *_nodeSucessor;
        while ( _nodeCorrente != NULL ) {
                // guardar ponteiro para node sucessor
                _nodeSucessor = _nodeCorrente->nodeSucessor;
                // destruir objeto corrente
                delete _nodeCorrente->objetoCorrente;
                // destruir node corrente
                delete _nodeCorrente;
                // posicionar no node sucessor
                _nodeCorrente = _nodeSucessor;
        }
}
// guardar um objeto na fila
template <class objectType>
void Fila<objectType> :: Guardar( objectType *__objetoCorrente )
{
        // instanciar um novo node
        Node *_nodeCorrente = new Node( __objetoCorrente );
        // verificar se a fila está vazia
        if ( this->qtdNodes == 0 )
        {
                // atualizar o node inicial da fila
                // para o node recem instanciado
                this->nodeInicial = _nodeCorrente;
        }
        else
        {
                // atualizar o node sucessor do final corrente da fila
                // para o node recem instanciado
                this->nodeFinal->nodeSucessor = _nodeCorrente;
        }
        // atualizar o novo node final da fila
        // para o node recem instanciado
        this->nodeFinal = _nodeCorrente;
        // incrementar qtd de nodes na fila
        this->qtdNodes ++;
}
// retirar um objeto da fila
template <class objectType>
objectType* Fila<objectType> :: Retirar( void )
{
        // guardar node inicial da fila
        Node *_nodeCorrente = this->nodeInicial;
        // obter ponteiro do objeto corrente
        objectType *_objetoCorrente = _nodeCorrente->objetoCorrente;
        // fixar novo início da fila no node sucessor
        this->nodeInicial = _nodeCorrente->nodeSucessor;
        // decrementar qtd de nodes na fila
        this->qtdNodes --;
        // se esvaziar, apontar node final para NULL
        if ( this->qtdNodes == 0 )
        {
                this->nodeFinal = NULL;
        }
        // deletar node corrente
        delete _nodeCorrente;
        // retornar ponteiro do objeto retirado do início da fila
        return ( _objetoCorrente );
}
// consultar a quantidade de objetos na fila
template <class objectType>
int Fila<objectType> :: Tamanho( void )
{
        return ( this->qtdNodes );
}
// construtor da classe "Node"
template <class objectType>
Fila<objectType> :: Node :: Node( objectType *__objetoCorrente )
{
        this->objetoCorrente = __objetoCorrente;
        this->nodeSucessor = NULL;
}
// destrutor da classe "Node"
template <class objectType>
Fila<objectType> :: Node :: ~Node( void )
{
}

// fim do arquivo "Fila.cpp"
Os conceitos básicos de uma fila determinam que os elementos que a formam devem ser organizados pela ordem de chegada, ou seja, o primeiro que chegar à fila será o primeiro a ser retirado dela (FIFO: first-in, first-out); os elementos podem ser representados por "nodes" (ou "nós") que guardam 2 ponteiros: um para a estrutura de dados que desejamos organizar e o outro para o "node" seguinte na ordem de chegada da fila.
Usando a Fila ADT em outros projetos
Como exemplo, foi escolhido um caso de uso de strings do tipo Ansi, mas que poderia ser de outro tipo de dados como float, int, double, etc, inclusive outro tipo ADT como Números Complexos ou Números Racionais.
A seguir temos trechos de códigos para o projeto de teste:
1) Incluir no projeto as definições da classe "Fila":
        #include "Fila.h"
2) Definir um ponteiro para um objeto da classe Fila<AnsiString>:
Fila<AnsiString> *minhasstrings;
3) Instanciar o objeto da classe Fila<AnsiString>:
this->minhasstrings = new Fila<AnsiString>();
4) Inserindo objetos AnsiString na fila:
        this->minhasstrings->Guardar( new AnsiString( "São Paulo" ) );
        this->minhasstrings->Guardar( new AnsiString( "Rio de Janeiro" ) );
        this->minhasstrings->Guardar( new AnsiString( "Salvador" ) );
        this->minhasstrings->Guardar( new AnsiString( "Recife" ) );
        this->minhasstrings->Guardar( new AnsiString( "Fortaleza" ) );
        this->minhasstrings->Guardar( new AnsiString( "Manaus" ) );

5) Retirando objetos AnsiString da fila:
        this->ListBox1->Clear() ;
        // deixar os ultimos da fila para testar funcionalidade do
        // método destrutor da Fila<AnsiString>

        while( this->minhasstrings->Tamanho() > 2 )
        {
                AnsiString *valor = this->minhasstrings->Retirar();
                this->ListBox1->Items->Add( (*valor) );
                delete valor;
        }

6) Destruir o objeto da classe Fila<AnsiString> e consequentemente realizar uma varredura e destruição dos possíveis nodes remanescentes, também destruindo os respectivos objetos do tipo AnsiString associados a estes nodes:
        delete this->minhasstrings;
7) Não esquecer de habilitar o CodeGuard para certificar se tudo correrá como previsto, pelo menos durante o desenvolvimento.
Até a próxima.       

segunda-feira, 23 de junho de 2008

Usando Dll no Borland C++ Builder

 

Recomendações para o desenvolvimento dos dois projetos isolados em pastas separadas:

 

1) Criar novo projeto: File -> New -> Other -> Dll Wizard

        Project1 -> ProjDll.bpr
        Unit1 -> DllMain.cpp

2) Acrescentar um Header File para a DLL: File -> New -> Other -> Header File

        File1.h -> DllMain.h

3) Incluir em DllMain.h a diretiva de compilador:

        #include "MinhaClasse.h"

4) Incluir em DllMain.cpp a diretiva de compilador:

        #include "DllMain.h"

5) Criar nova Unit: File -> New -> Unit

        Unit2.cpp -> MinhaClasse.cpp
        Unit2.h -> MinhaClasse.h

6) Declarar a classe em MinhaClasse.h com a especificação:

        class __declspec(dllexport) MinhaClasse
        {
            ...
        };

7) Gerar a DLL: Project -> Build ProjDLL

8) Depurar erros da DLL e prosseguir somente quando estiver tudo correto.

9) Criar novo projeto: File -> New -> Application

        Project1.bpr -> ProjDemo.bpr
        Project1.cpp -> ProjDemo.cpp
        Unit1.cpp -> DemoFormMain.cpp
        Unit1.h -> DemoFormMain.h

10) Copiar da pasta do projeto da DLL os arquivos:

        ProjDll.lib
        ProjDll.dll
        DllMain.h
        MinhaClasse.h

11) Acrescentar no ProjDemo: Project -> Add to Project...

        Selecionar aruivos do tipo Library (*.lib)
        Indicar o arquivo a ser adicionado ao projeto: ProjDll.lib

12) Acrescentar no DemoFormMain.h a diretiva de compilador:

        #include "DllMain.h"

14) Substituir a diretiva de compilador em MinhaClasse.h de/para:

        dllexport -> dllimport

15) A partir deste estágio, já podemos declarar variáveis do tipo MinhaClasse:

        MinhaClasse obj1MinhaClasse;
        MinhaClasse *obj2MinhaClasse;

16) Se a declaração for para objeto estático, usar:

            obj1MinhaClasse.Atributo
            obj1MinhaClasse.Método()

17) Se a declaração for para objeto dinâmico, usar:

            obj2MinhaClasse = new MinhaClasse();
            ...
            obj2MinhaClasse->Atributo
            obj2MinhaClasse->Método()
            ...
            delete obj2MinhaClasse

18) Atenção para o ciclo vida dos objetos instanciados:

        estaticamente -> escopo da função
        dinamicamente -> requer Delete antes do término da função/programa

Até a próxima.