Mostrando las entradas con la etiqueta Programación. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Programación. Mostrar todas las entradas

domingo, 16 de febrero de 2014

Editores de texto y programación - mi perspectiva desde el uso, el abuso y la desazón

Todo estudiante de ciencias* pasa por aquella época de la vida donde debe programar (o por lo menos, intentarlo). Dejando de lado todas las peripecias asociadas con esta empresa, quiero concentrar esta entrada en mi experiencia personal con los editores de texto y los entornos integrados de programación (IDE).
* se habla de lo que se conoce.

Emacs

Emacs forma parte de la comunidad GNU. Si bien, es un editor de texto útil, la necesidad recurrente de atajos de teclado que no podía memorizar fácilmente me hacían perderle un poco el respeto.
Se comporta muy bien al trabajar desde consola, pero también ofrece una interfaz gráfica.
Una de las características más llamativas es la gran cantidad de plug-ins disponibles. Por ejemplo, hay un plugin para integrar emacs sistemas de control de versiones (como git), hay un plugin de WYSIWYG para la edición de textos en latex. La lista sigue, incluso hay plugins que ofrecen juegos de arcade.
No recomendaría este editor para los neófitos en la programación, suelo bromear diciendo que emacs es el editor de texto preferido de Davy Jones

Así se sienten los atajos de teclado demasiado largos

KDevelop

Fui usuario asiduo del entorno de escritorio KDE. Un día por recomendación de un amigo me enteré de la existencia de KDevelop, un entorno de desarrollo muy poderoso. Igual que emacs posee reconocimiento de sintaxis en varios lenguajes, y permite configurar control de versiones con git. Otra característica importante es el autocompletado de palabras, lo cual acelera el proceso de escritura. Toda una maravilla si se tiene suficiente RAM a disposición.
Pero como todo en la vida, no hay nada perfecto: los requisitos de memoria del KDevelop, así como una reciente racha de crashes hicieron que retomase mis intentos por utilizar un editor que había probado tiempo atrás: Vim

VIM (VI Improved)

Vim pareciera ser un editor de texto bastante simple, sin embargo, no hay que dejarse engañar. Puedo resumir diciendo que vim es uno de los editores de texto más potentes que he podido utilizar. Posee gran versatilidad en su sistema de comandos, además de reconocer la sintaxis de más de 200 lenguajes de programación (incluyendo TeX y Latex), permite una personalización muy amplia al punto de permitir cosas como definir sistemas de resaltado de sintaxis propios, esquemas de color y comandos personalizados. Comparándolo con emacs, vim utiliza instrucciones más simples y fáciles de recordar, tan sencillas que es posible programar usando una mano (obviamente son escasas las situaciones donde esto será necesario). Además de su versatilidad, la curva de aprendizaje es suave y basta con usarlo por algunas horas para acoplarse a esta "power tool" como lo llama su creador. Sin lugar a dudas, uno de los mejores editores que he utilizado.
Me llamó mucho la atención enterarme que vim forma parte de una campaña para apoyar niños en Uganda a través de donaciones. Buen trabajo equipo vim!!!

Vim: The power tool for everyone!
El proceso de personalización el editor vim toma tiempo, hay un sitio en particular donde se puede aprender como. Un amigo mío dispone de un repositorio en github donde publica un conjunto de configuraciones muy útiles para quienes programamos en C++, los invito a que se den una pasada por https://github.com/muzgash/vim


Y a que viene todo esto?

El proceso de programación y escritura debe ser una experiencia reconfortante, por lo tanto es importante disponer de un buen editor de texto. Para programar puede usarse cualquier editor de texto y cada cual elije el editor que más le convenga en función de sus necesidades particulares. Opté por mencionar los editores de texto más significativos entre los que he usado durante mis proyectos de programación (que consisten básicamente en aprendizaje de lenguajes). Dentro de los editores que he probado están UltraEdit(Windows), Geany (Un IDE escrito en GTK), Kate, y la lista se extiende.
Pese a todo, lo que importan son las habilidades de programación que se tienen, y no el editor se use para programar.

Enlaces de interés

  1. Página del proyecto GNU Emacs http://www.gnu.org/software/emacs/
  2. Página del proyecto KDevelop http://kdevelop.org/
  3. Página del proyecto VIM http://www.vim.org/about.php
  4. Repositorio de configuraciones de VIM https://github.com/muzgash/vim
  5. IDE Geany http://www.geany.org/
  6. Para aprender a usar vim http://code.tutsplus.com/articles/25-vim-tutorials-screencasts-and-resources--net-14631
  7. Para aprender más de otros editores

miércoles, 30 de octubre de 2013

Conozcamos la STL (Standard Template Library) de C++ - Primera entrega: std::map - Parte 2 de 2

Introducción

Mucha personas (como yo en el pasado cercano) ignorarán el poder oculto detrás de las siglas STL. Se trata de nada más ni nada menos que una de las "cosas" que convierte a C++ en uno de los lenguajes de programación más poderosos. La STL o Standard Template Library 
La STL proporciona una colección de estructuras de datos contenedoras y algoritmos genéricos que se pueden utilizar con éstas.
Dada la extensión que pretendía dar a este tema, decidí dividirlo en dos entradas independientes y complementarias.
La primera parte de esta entrega (disponible aquí) consiste en la implementación del contenedor std::map con los tipos de datos incluidos en el estándar de C++.
En la segunda parte (este post) abordaré la implementación del contenedor std::map haciendo uso de una clase propia, es decir, una clase que hemos hecho nosotros mismos, tal como lo ilustramos en una entrega previa, donde hemos definido una clase para la manipulación de vectores.

Usando std::map con una clase propia

Supongamos ahora que creamos una clase y queremos usarla en una variable tipo std::map. Para tal fin es necesario crear un criterio de comparación, específicamente, es necesario definir el operador< dentro de nuestra clase, puesto que std::map se basa en el para realizar el ordenamiento.
En una entrega previa hemos definido una clase para la manipulación de vectores y hemos definido el operador< dentro de la misma tal como lo requiere el std::map.

La clase cVector y su código de implementación pueden descargarse usando este enlace.
Mirando el código de ejemplo:


#include <iostream>
#include <map>
#include "cVector.hpp"

int main(void)
{

    cVector I_vector;
    cVector J_vector;
    cVector K_vector;
 
/*
Aqui implementamos un mapa que contiene elementos de la clase cVector,
No debe representar problemas puesto que el operador< ha sido definido para la clase
como puede verse en cVector.hpp
*/

    std::map<int,cVector> mi_mapav;
 
    I_vector.colocarCoordenadas(1,0,0);
    J_vector.colocarCoordenadas(0,2,0);
    K_vector.colocarCoordenadas(0,0,3);

 
mi_mapav[0]=I_vector;
mi_mapav[1]=J_vector;
mi_mapav[2]=K_vector;

    std::cout << "Producto punto entre I y K " << I_vector*K_vector << std::endl;
 
    std::cout << "La magnitud de la suma vectorial entre I y J " << (I_vector+J_vector).normaVector() << std::endl;
 
    if( (I_vector+J_vector)<K_vector)
    {
std::cout << "La magnitud de I + J es menor que la de K " << std::endl;
}
else
{
std::cout << "La magnitud de I + J es mayor que la de K " << std::endl;
}

for(int i=0;i<1;i++)
{
std::cout << "Usando el std::map tenemos la norma de la suma de vectores consecutivos" << (mi_mapav[i]+mi_mapav[i+1]).normaVector() << std::endl;

}
}


lunes, 12 de agosto de 2013

Conozcamos la STL (Standard Template Library) de C++ - Primera entrega: std::map - Parte 1 de 2

Introducción

Mucha personas (como yo en el pasado cercano) ignorarán el poder oculto detrás de las siglas STL. Se trata de nada más ni nada menos que una de las "cosas" que convierte a C++ en uno de los lenguajes de programación más poderosos. La STL o Standard Template Library 
La STL proporciona una colección de estructuras de datos contenedoras y algoritmos genéricos que se pueden utilizar con éstas.
(tomado de aquí: http://decsai.ugr.es/~jfv/ed1/c++/cdrom4/paginaWeb/stl.htm)

En esta entrega trataré de ilustrar el uso del contenedor map, a través de algunos ejemplos prácticos.

Dada la extensión que pretendía dar a este tema, decidí dividirlo en dos entradas independientes y complementarias.
La primera  parte de esta entrega (es decir, este post) consiste en la implementación del contenedor std::map con los tipos de datos incluidos en el estándar de C++.

En la segunda parte (disponible aquí) abordaré la implementación del contenedor std::map haciendo uso de una clase propia, es decir, una clase que hemos hecho nosotros mismos, tal como lo ilustramos en  una entrega previa, donde hemos definido una clase para la manipulación de vectores.

Contenedor std::map de la STL

Generalidades del contenedor std::map

Uno de esos contenedores incluidos en la STL corresponde a map, un contenedor de datos donde cada uno posee una clave(key en inglés) que lo identifica. Para utilizar map es necesario incluirlo en la cabecera de nuestro código fuente:
#include<map>
De esta manera, es posible hacer el llamado
std::map<tipo_variable_1 clave,tipo_variable_2 valor, criterio_comparación_clave> variable_map;
 De esta manera, se puede declarar una varible tipo map, en este caso: variable_map. Esta definición parece un poco ambigua de entender, pero todo es más claro en cuanto se entiende que la variable map lo que hace es etiquetar con la variable clave lo que contiene la variable valor. Para realizar el ordenamiento, el contenedor map utiliza un criterio de comparación basándose en alguna operación de comparación, específicamente, usando el operador< definido para del tipo_variable_1, es por esta razón que el operador< debe estar definido para el tipo de variable utilizado como clave.
Para realizar la asignación de valores a nuestro mapa, basta con escribir
variable_map[valor_tipo_variable_1]=valor_tipo_variable_2;
Para ver claramente lo que acabo de exponer, observemos el siguiente ejemplo (código c++, obviamente)



#include<iostream>
#include<string>
#include<map>


int main(void)
{
        std::map<int /*indice o clave*/, std::string /*contenido*/> mi_mapa;

       std::string palabra;

        for(int i(0);i<5;i++)
        {
                std::cout << "Ingrese una palabra: " << std::endl;
                std::cin>>palabra;
                mi_mapa[i]=palabra;
        }


        for(i=0;i<5;i++)
        {
                std::cout << "Palabra almacenada con clave " << i << " es " << mi_mapa[i] << std::endl;
        }
}


Vemos que en el ejemplo hemos usado map como si se tratase de un array. Sin embargo, la diferencia sustancial es que la información se ha guardado de manera ordenada en función del valor de i. Este comportamiento no es visible a simple vista, puesto que el orden de entrada de los datos ya están ordenados, pero considere el siguiente ejemplo

#include<iostream>
#include<string>
#include<map>

int main(void)
{
        std::map<int /*indice o clave*/, std::string /*contenido*/> mi_mapa;
        std::string palabra;
        int numero;


        for(int i(0);i<5;i++)
        {
                std::cout << "Ingrese un número: " << std::endl;
                std::cin >> numero;

                std::cout << "Ingrese una palabra: " << std::endl;
                std::cin >> palabra;


                mi_mapa[numero]=palabra;
        }


        for(i=0;i<5;i++)
        {
                std::cout << "Palabra almacenada con clave " << i << " es " << mi_mapa[i] << std::endl;
        }

}

En este caso, vemos que para cada valor no repetido de i, se muestra un valor de palabra. es decir, que para cada int i, se ha asignado una variable std::string. Este uso sigue siento familiar con el uso de los arrays. Podemos probar cambiando los tipos de variable en la definición de la variable tipo map. Considere el siguiente ejemplo

#include<iostream>
#include<string>
#include<map>

int main(void)
{
        std::map<std::string /*indice_palabra*/,int /*indice_numero*/> mi_mapa;
        std::string palabra;
        int numero;

        mi_mapa["hola"]=10;
        mi_mapa["alfabeto"]=5;
        mi_mapa["zoo"]=0;
        mi_mapa["a"]=3;
        mi_mapa["marmota"]=9;


        std::cout << " La palabra \"alfabeto\" tiene asignado el número " << mi_mapa["alfabeto"] << std::endl;
        std::cout << " La palabra \"a\" tiene asignado el número " << mi_mapa["a"] << std::endl;

        std::cout << " La palabra \"hola\" tiene asignado el número " << mi_mapa["hola"] << std::endl;
        std::cout << " La palabra \"marmota\" tiene asignado el número " << mi_mapa["marmota"] << std::endl;



}

A cada std::string se ha asignado un valor numérico tipo int, de esta manera, los llamados a cada int se realizan mediante el std::string correspondiente a su clave.

Considere ahora el siguiente ejemplo

#include<iostream>
#include<string>
#include<map>

int main(void)
{
        std::map<std::string /*indice_palabra*/,int /*indice_numero*/> mi_mapa;
        std::string palabra;
        int numero;


        for(int i(0);i<5;i++)
        {
                std::cout << "Ingrese un número: " << std::endl;
                std::in >> numero;

                std::cout << "Ingrese una palabra: " << std::endl;
                std::in >> palabra;


                mi_mapa[palabra]=numero;
                std::cout << " La palabra << palabra << " tiene asignado el número " << mi_mapa[palabra] << std::endl;

        }

}

En este caso, a cada palabra ingresada por el usuario, se ha asignado un valor numérico también ingresado por el usuario. El ordenamiento se hace según el operador< definido en la clase std::string.

miércoles, 1 de mayo de 2013

El uso de clases y objetos en la programación científica


Esta es una de mis entradas más pretenciosas, quizá el título de esta entrada es un tanto pueril para muchos programadores experimentados.
Mi motivación para la misma es el hecho que pocas veces logra darse la preponderancia suficiente a este asunto en los cursos de programación de las carreras científicas.
Por lo general, se orienta la programación hacia el paradigma de la programación estructurada, paradigma poco elegante si se quiere trabajar en proyectos grandes o si se quiere implementar fácilmente el código fuente escrito, si queremos que otros utilicen nuestro código.

Como científico, es preciso aprovechar todas las herramientas disponibles para resolver nuestros problemas de investigación o de cualquier otra índole académica. Si bien no soy experto en programación, mi experiencia programando desde hace unos 3 años me ha permitido darme cuenta de la importancia que tiene el paradigma de la programación orientada a objetos si se quiere trabajar en el diseño de simulaciones y/o en instrumentación científica. 


Una idea de lo que es una clase


Dejando de lado los formalismos, pienso que una clase se puede definir como un tipo (abstracto) de datos (tipo de variable) más unos métodos propios de la clase (del tipo de datos) a la que pertenecen. Así, cuando se crea una clase, es posible implementarla en nuestros programas, incluir cambios y funciones den la clase y automáticamente los cambios de propagarán a los programas donde la clase se implemente. Para no dejar las cosas en el aire, pensemos en una aplicación al álgebra de vectores como un problema de programación y miremos su solución desde el punto de vista de la programación estructurada y la programación orientada a objetos.

Manipulando vectores con programación estructurada

Mediante la programación estructurada, la salida rápida para le problema se hace a través del uso de arreglos (arrays) lo cual está bien, pero es poco elegante, por ejemplo, para definir el vector i que apunta en la dirección x, puede hacerse algo como esto (código fuente C/C++)

    double i_vector[3];

    i_vector[0]=1;
    i_vector[1]=0;
    i_vector[2]=0;

Lo cual servirá, pero como dije antes, es poco elegante, para tener la base completa {i,j,k} tendríamos el siguiente lío

    double i_vector[3];
    double j_vector[3];
    double k_vector[3];

    i_vector[0]=1;
    i_vector[1]=0;
    i_vector[2]=0;

    j_vector[0]=0;
    j_vector[1]=1;
    j_vector[2]=0;

    k_vector[0]=0;
    k_vector[1]=0;
    k_vector[2]=1;

Ahora, pensemos que queremos definir un producto interno entre vectores (producto punto). Hasta ahora nuestro código solo tiene arreglos definidos, por lo tanto, necesitamos crear una función que lleve a cabo la tarea de calcular el producto punto. Por ejemplo


double productoPunto(double vector1[],double vector2[])
{
    int i=0;
    double res=0;
 
    for(i=0;i<sizeof(vector1);i++)
    {
        res = vector1[i] * vector2[i] + res;
    }
 
    return res;
}


la cual puede llamarse así
 
    punto(i_vector,k_vector)

Funciona, pero siempre queda la sensación que hace falta algo, la sensación que nuestro programa puede ser mejor. Y de hecho, es posible.


Manipulando vectores con programación orientada a objetos


Había mencionado que la programación orientada a objetos hacía uso del concepto de clase a la hora de programar, también había dicho que la clase incluye funciones. Siguiendo con nuestro problema modelo, he escrito una clase llamada cVector (el nombre lo he puesto yo), la clase sirve para manipular vectores en un espacio 3-D. La definición se da a continuación


#include<iostream>
#include<string>
#include <cmath>

class cVector
{
private:

// private quiere decir que las variables a continuación solo pueden accederse desde la clase misma
// es decir, no pueden ser modificadas al momento de implementar el codigo
// por esta razon hay que crear alguna funcion que modifique estos valores
// más adelante veremos las funciones que manipulan estas variables


// Defino una variable para cada coordenada espacial
        double coordenada_x;
        double coordenada_y;
        double coordenada_z;

public:

// public quiere decir que todo lo que se defina a continuacion puede ser accedido al momento de
// implementar la clase

// esta funcion se encarga de modificar las variables privadas de coordenadas

        void colocarCoordenadas(double dX,double dY, double dZ);

// esta funcion retorna la norma del vector
        double normaVector();



// esta funcion permite la igualacion de vectores, es decir, tener por ejemplo vector_a y vector_b
// y hacer que vector_b contenga lo mismo que vector_a solo con hacer
// vector_b=vector_a;
// este proceso se conoce como "sobrecarga de operadores" y consiste en definir las operaciones
// para los operadores de uso común, en este caso, el operador de asignación

        cVector& operator= ( const cVector &rhs );

// esta sobrecarga del operador <, calcula las normas de los vectores y nos dice cual tiene una norma mayor
        bool operator< ( const cVector& other) const;

//con esta sobrecarga implementamos el producto punto entre vectores
        double operator*( const cVector& other ) const;

// con esta sobrecarga se implementa la suma de vectores
        cVector&  operator+(const cVector &other);

};


// Luego de haber declarado la clase y sus funciones, se debe colocar el código de la implementacion de las // funciones, es decir, lo que hacen
void cVector::colocarCoordenadas(double dX,double dY, double dZ)
{
        coordenada_x=dX;
        coordenada_y=dY;
        coordenada_z=dZ;
}


double cVector::normaVector()
{
         return sqrt( coordenada_x*coordenada_x + coordenada_y*coordenada_y + coordenada_z*coordenada_z);
}


cVector& cVector::operator= ( const cVector &rhs )
{

 if ( this == &rhs )    //Verifico si se trata del mismo objeto
    {
      return *this;
    }
  else
    {

        coordenada_x=rhs.coordenada_x;
        coordenada_y=rhs.coordenada_y;
        coordenada_z=rhs.coordenada_z;


        return *this;
    }

}

bool cVector::operator< ( const cVector& other) const
{
    return  ( sqrt( coordenada_x*coordenada_x + coordenada_y*coordenada_y + coordenada_z*coordenada_z) < sqrt( other.coordenada_x*other.coordenada_x + other.coordenada_y*other.coordenada_y + other.coordenada_z*other.coordenada_z) );
}

double cVector::operator*(const cVector &other) const
{
    return coordenada_x*other.coordenada_x + coordenada_y*other.coordenada_y + coordenada_z*other.coordenada_z;
}

cVector&  cVector::operator+(const cVector &other) //const
{
     coordenada_x+=other.coordenada_x;
     coordenada_y+=other.coordenada_y;
     coordenada_z+=other.coordenada_z;
   
     return *this;
}

A la hora de utilizar esta clase, basta con incluirla en los archivos de cabecera y utilizar cada una de sus funciones fácilmente

#include "cVector.hpp"

int main(void)
{
    cVector I_vector;
    cVector J_vector;
    cVector K_vector;

    I_vector.colocarCoordenadas(1,0,0);
    J_vector.colocarCoordenadas(0,1,0);
    K_vector.colocarCoordenadas(0,0,1);

    std::cout << "El producto punto entre I y K es = " <<  I_vector*K_vector  << std::endl;
    std::cout << "La magnitud de la suma vectorial entre I y J " << (I_vector+J_vector).normaVector() << std::endl;
 
//vemos como la suma de vectores se incorpora fácilmente
    if( (I_vector+J_vector)<K_vector)
    {
std::cout << "La magnitud de I + J es menor que la de K " << std::endl;
}
else
{
std::cout << "La magnitud de I + J es mayor que la de K " << std::endl;
}

}

La elaboración de la clase nos permite un control mayor de todas las cosas que pasan con nuestras variables, a la hora de implementar la clase, todo el código detrás de las funciones queda "oculto" pudiéndonos concentrar más en como aprovechar la clase y no en como encajar nuestro problema en la programación estructurada.

La clase cVector y su código de implementación pueden descargarse usando este enlace