Saturday, March 27, 2010

Usando dSFMT

Antes de empezar el Master de Física Computacional y Aplicada sólo había usado generadores de números aleatorios escritos en Fortran.
En la asignatura Simulación con Dinámica Molecular y Monte Carlo tuve que hacer una simulación del modelo de Ising para la que necesitaba un buen generador escrito en C.
Googleando un poco acabé encontrando el Mersenne Twister desarrollado en 1997 por Makoto Matsumoto y Takuji Nishimura, que, según Wikipedia:
... provides for fast generation of very high-quality pseudorandom numbers, having been designed specifically to rectify many of the flaws found in older algorithms.
Ahora para el proyecto final del máster estoy utilizando la versión 2.1 en C del Double precision SIMD-oriented Fast Mersenne Twister (dSFMT) que es una variante del Mersenne Twister que introdujeron Mutsuo Saito y Makoto Matsumoto en el 2006. La librería se puede descargar de la página web de los inventores.

Esta variante es mucho más rápida que el MT en la mayoría de las plataformas. Además cuenta con la ventaja de que proporciona directamente numeros reales de doble precisión.

Existen implementaciones de SFMT en otros lenguajes (aún no de dSFMT) que han sido realizadas por voluntarios.

Lo último que han hecho ha sido una versión del MT para GPUs.

Funciones con un número indeterminado de argumentos en C

En el proyecto de fin de master utilicé listas de argumentos variables para poder pasar diferentes sistemas de ecuaciones diferenciales a la función con la que calculo exponentes de Lyapunov.

Como ese código es demasiado largo para ponerlo aquí, pondré las pequeñas pruebas que hice para aprender.

Se puede encontrar una explicación muy buena de las funciones variádicas (funciones que pueden aceptar un número indeterminado de argumentos) en un apartado del apéndice A del manual de The GNU C Library.
En este manual hay un ejemplo en el que se le pasa a una función un número indeterminado de enteros para que esta devuelva su suma.
Este es el ejemplo del manual con los comentarios traducidos y resaltando las líneas más importantes:
#include 
#include 

int suma (int count,...)
{
    va_list ap; //Lista de parámetros
    int i, sum;

    /* Inicializa la lista de argumentos */
    va_start (ap, count);         

    sum = 0;
    for (i = 0; i < count; i++)
    {
        /* Obtiene el siguiente argumento. */
        sum += va_arg (ap, int);    
    }
    
    /* Limpia la lista */
    va_end (ap);       
    
    return sum;
}

int main(void)
{
    /* Esta llamada imprime 16. */
    printf ("%d\n", suma (3, 5, 5, 6));

    /* Esta llamada imprime 19. */
    printf ("%d\n", suma (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    
    return (0);
}
En este ejemplo se debe destacar lo siguiente:
  • Para poder pasar un número indeterminado de argumentos se debe incluir la cabecera stdarg.h de la librería estándar de C.
  • En la lista de argumentos se usan tres puntos para indicar el comienzo de los argumentos variables.
  • Se debe declarar una variable de tipo va_list que se encargará de contener la lista de argumentos.
  • Se utiliza la macro va_start para inicializar la lista indicándole cuál es el último argumento fijo.
  • Se utiliza la macro va_arg para extraer los argumentos de la lista indicándole cuál es su tipo de datos. 
  • Se utiliza la macro va_end para limpiar la memoria.  
Este es el resultado de ejecutar el ejemplo anterior:
$ ./test1 
16
55
En este otro ejemplo usé el mismo procedimiento para pasar un número indeterminado de argumentos variables con tipos de datos definidos por el usuario:
#include  
#include 

typedef struct s_Fecha
{
    unsigned int anyo;
    unsigned int mes;
    unsigned int dia;
}t_Fecha;

t_Fecha setFecha(unsigned short dia, unsigned short mes,unsigned short anyo);
void imprimeFecha(t_Fecha fecha);

/* Imprime varias fechas */
void imprimeFechas(unsigned int numFechas, ...)
{
    va_list ap;
    int i;

    /* Se inicializa la lista de argumentos */
    va_start (ap, numFechas);         

    for (i = 0; i < numFechas; i++)
    {
        // Se saca el siguiente argumento de la lista
        imprimeFecha(va_arg (ap, t_Fecha));
    }
    
    printf("\n");
    
    //Se limpia la memoria
    va_end (ap);          
    
    return;
}

int main(void)
{
    t_Fecha fecha1, fecha2, fecha3;
    
    fecha1=setFecha(1,1,2009);
    fecha2=setFecha(2,2,2009);
    fecha3=setFecha(3,3,2009);
    
    /* Esta llamada imprime 1/1/2009 */
    imprimeFechas(1, fecha1);

    /* Esta llamada imprime 1/1/2009 2/2/2009*/
    imprimeFechas(2, fecha1, fecha2);
    
    /* Esta llamada imprime 1/1/2009 2/2/2009 3/3/2009*/
    imprimeFechas(3, fecha1, fecha2, fecha3);

    return (0);
}

/* Devuelve una variable de tipo t_Fecha */
t_Fecha setFecha(unsigned short dia, unsigned short mes,unsigned short anyo)
{
    t_Fecha fecha;
    
    fecha.dia=dia;
    fecha.mes=mes;
    fecha.anyo=anyo;
    
    return fecha;
}

/*Imprime una fecha*/
void imprimeFecha(t_Fecha fecha)
{
    printf("%d/%d/%d ",fecha.dia,fecha.mes,fecha.anyo);
    return;
}
Este es el resultado:
$ ./test2 
1/1/2009 
1/1/2009 2/2/2009 
1/1/2009 2/2/2009 3/3/2009 

Agenda mensual con calendario en PHP (y V)

Por último la clase Mes.
Las clases van contenidas unas dentro de otras a modo de "matrioska".
La clase Mes es la que conecta con la BD.
/* Clase Mes */
class Mes
{
    private $anyo;    
    private $mes;
    private $numDiasMes;
    private $numSemanasMes;
    private $semanas;

    
    /* Constructor */
    public function __construct($anyo, $mes)  
    {
        //Inicializo los miembros
        $this->setAnyo($anyo);
        $this->setMes($mes);
        $this->numDiasMes = Fechas::getFinMes($anyo,$mes);
        $this->crearSemanasMes();  
        $this->addEventos();
    }       
    
    /* Métodos de acceso */
    public function setAnyo($anyo) 
    {
        $this->anyo = $anyo;
    }

    public function getAnyo() 
    {
        return $this->anyo;
    }
    
    public function setMes($mes) 
    {
        $this->mes = $mes;
    }

    public function getMes() 
    {
        return $this->mes;
    }

    public function getNumDiasMes() 
    {
        return $this->numDiasMes;
    }

    public function getNumSemanasMes() 
    {
        return $this->numSemanasMes;
    }
   
    public function getSemanas() 
    {
        return $this->semanas;
    }
    
    /* Métodos */
    
    /* Genera las semanas de un mes */
    private function crearSemanasMes()
    {   
        /*Se inicializan las variables antes del bucle*/
        
        $i = 0;
        
        /*Dia en que nos encontramos al recorrer la agenda*/
        $diaActual = 1; //Se inicializa a 1
        
        /*Mientras no hayamos entrado en otro mes*/
        while( $diaActual <= $this->numDiasMes )
        {
            /*Se crean las semanas*/  
            $this->semanas[$i] = new Semana();
            
            $this->semanas[$i]->creaDiasSemana($diaActual, $this->anyo,
                                               $this->mes,$this->numDiasMes);
            
            $i = $i + 1;
        }  
        
        /*Se guarda el número de semanas del mes*/
        $this->numSemanasMes = $i;
       
    }
    
    /* Añade un evento a la agenda */
    public function addEvento($dia, $evento) 
    {
        $numSemanaIni = Fechas::getSemanaAnyo($this->anyo, $this->mes, 1);
        
        $numSemana = Fechas::getSemanaAnyo($this->anyo, $this->mes, $dia);
        
        //Si la primera semana del año es la 59
        if(53==$numSemanaIni)
        {
            $numSemanaIni = 0;
            
            //Si además el evento es esa semana
            if(53==$numSemana)
            {
                $numSemana = 0;    
            }
        }
        
        $indiceSemana = $numSemana - $numSemanaIni;
        
        $diaSemana = Fechas::getDiaSemana($this->anyo, $this->mes, $dia);
        
        $this->semanas[$indiceSemana]->setEvento($evento, $diaSemana);
    }
    
    /* Obtiene un evento de la agenda */
    public function getEvento($dia) 
    {
        $numSemanaIni = Fechas::getSemanaAnyo($this->anyo, $this->mes, 1);
    
        $numSemana = Fechas::getSemanaAnyo($this->anyo, $this->mes, $dia);
        
        //Si la primera semana del año es la 59
        if(53==$numSemanaIni)
        {
            $numSemanaIni = 0;
            
            //Si además el evento es esa semana
            if(53==$numSemana)
            {
                $numSemana = 0;    
            }
        }
        
        $indiceSemana = $numSemana - $numSemanaIni;
        
        $diaSemana = Fechas::getDiaSemana($this->anyo, $this->mes, $dia);           
        
        return $this->semanas[$indiceSemana]->getEvento($diaSemana);
    }
    
    /* Muestra un evento de la agenda */
    public function muestraEvento($dia) 
    {
        $numSemanaIni = Fechas::getSemanaAnyo($this->anyo, $this->mes, 1);
    
        $numSemana = Fechas::getSemanaAnyo($this->anyo, $this->mes, $dia);
        
        //Si la primera semana del año es la 59
        if(53==$numSemanaIni)
        {
            $numSemanaIni = 0;
            
            //Si además el evento es esa semana
            if(53==$numSemana)
            {
                $numSemana = 0;    
            }
        }
        
        $indiceSemana = $numSemana - $numSemanaIni;
        
        $diaSemana = Fechas::getDiaSemana($this->anyo, $this->mes, $dia);           
        
        $this->semanas[$indiceSemana]->muestraEvento($diaSemana);
    }
    
    /* Muestra el HTML de un mes */
    public function muestraCalendario()
    {   
        $nombreMeses = array('Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio',
                             'Agosto','Septiembre','Octubre','Noviembre','Diciembre');
        $nombreDias = array('Lun','Mar','Mie','Jue','Vie','Sab','Dom');                                  
        
        
        /*Se obtiene el nombre del mes*/
        $nombreMes = $nombreMeses[$this->mes - 1];
        
        
        /*Se colocan los botones*/
        printf("<table class=\"tablaBotones\"><tr><td>
                <input type=\"submit\" name=\"restaMes\" value=\"<<\" onClick=\"verMesAnterior()\">
                </td><td class=\"caption_text\">%s %d</td><td>
                <input type=\"submit\" name=\"sumaMes\" value=\">>\" onClick=\"verMesSiguiente()\">
                </td></tr><table>\n", $nombreMes, $this->anyo);
                
        /*Se abre la tabla*/
        printf("<table>\n");
        
        /*Se abre el cuerpo de la tabla*/ /*Se abre la tabla*/
        printf("<tbody>\n");
        /*Se crea la primera fila de la tabla*/
        printf("<tr>\n");
        
        /*La primera casilla va vacía*/
        printf("<th class=\"dia\"></th>\n");
        
        /*Se generan las casilla de los días de la semana*/
        for($i=0;$i<7;$i++)
        {   
           /*Se escribe en el HTML el texto del día de la semana */
           printf("<th class=\"dia\"> %s </th>\n", $nombreDias[$i]);     
        }
     
        printf("</tr>\n");

        /* Semanas */
        $this->muestraSemanas();
        
        /*Se cierra el cuerpo de la tabla*/
        printf("</tbody>\n");
        
        /*Se cierra la tabla*/
        printf("</table>\n");

    }
    
    /* Genera el HTML de todas las semanas del mes */
    public function muestraSemanas()
    {
        foreach($this->semanas as $semana)
        {
            $semana->muestraSemana();
        }
    }
    
    /* Añade al calendario del mes los eventos que están en la BD */
    public function addEventos()
    {
        require_once 'login.php';
        
        //Se intenta conectar con la BD
        $db_server = mysql_connect($db_hostname,$db_username,$db_password);
                
        //Si ha habido errores se aborta y se informa al usuario
        if(!$db_server)
        {
            die( "No se pudo conectar con MySQL: " . mysql_error() );
        }
        
        mysql_select_db($db_database)
            or die( "No se pudo selecionar la BD: " . mysql_error() );
        
        //Consulta SQL
        $query = "select id_evento, nombre, DATE_FORMAT(fecha_hora,'%d-%m-%y'),
                  TIME_FORMAT(fecha_hora,'%H:%k'), descripcion, lugar, DAY(fecha_hora)
                  from calendariov where MONTH(fecha_hora) = '$this->mes'
                  and YEAR(fecha_hora) = '$this->anyo'";
        
        $result = mysql_query($query);

        //Si hubo fallos se informa al usuario
        if(!$result)
        {
            die("Fallo en el acceso a la BD: " . mysql_error());
        }

        //Si todo fue bien
        $numEventos = mysql_num_rows($result);

        for($j = 0;$j < $numEventos; ++$j)
        {
            $row = mysql_fetch_row($result);
                      
            //Se inserta el evento en el calendario
            $this->addEvento( (int) $row[6], new Evento($row[0], $row[1], $row[2], 
                                                        $row[3], $row[4], $row[5]));
        }

        mysql_close($db_server);

    }
            
}  

?>     

Agenda mensual con calendario en PHP (IV)

Esta es la clase Semana.
/* Clase Semana */
class Semana
{
    /* Miembros */
    private $dias;
    private $numSemanaAnyo;
    
    /* Métodos de acceso */
    public function getNumSemanaAnyo() 
    {
        return $this->numSemanaAnyo;
    }
    
    public function getDias() 
    {
        return $this->dias;
    }
    
    /* Metodos */
    
    /* Genera los días de una semana */
    public function creaDiasSemana(&$diaActual, $anyo, $mes, $finMes)
    {          
        /*Se crea la semana*/
        $this->numSemanaAnyo = Fechas::getSemanaAnyo($anyo, $mes, $diaActual);
         
        $diaSemana = Fechas::getDiaSemana($anyo, $mes, $diaActual);
        
        /*Se crea el dia actual*/
        $diaActAux = $diaActual; 
        
        /*Se calcula lo que hay que retroceder*/
        $atras = $diaSemana - 1;
        
        /*Retrocedemos*/
        for($i = 0; $i < $atras; $i++)
        {
            /*Se crea un nuevo día*/
            $this->dias[$diaSemana - 2 - $i] = new Dia($diaSemana - 1 - $i,0,false);
        }
             
        /*Se calcula lo que hay que avanzar*/
        $adelante= 7 - $diaSemana + 1;
        
        /*Avanzamos*/
        for($i = 0; $i < $adelante; $i++)
        {   
            /*Se comprueba si el día está dentro del mes*/
            $perteneceAlMes = ( $diaActAux <= $finMes );

            /*Se crea un nuevo día*/
            $this->dias[$diaSemana - 1 + $i] = new Dia($diaSemana + $i, $diaActAux, $perteneceAlMes);
            
            /*Se incrementa el valor del día actual si se está dentro del mes*/    
            $diaActAux = $diaActAux + 1;
        }
         
        /*Se actualiza el día actual de forma que la próxima semana empiece en Lunes*/
        $diaActual = $diaActual + $adelante;
        return;
    }
    
    public function setEvento($evento, $diaSemana)
    {
        $this->dias[$diaSemana - 1]->setEvento($evento);
    }
    
    public function getEvento($diaSemana)
    {
        return $this->dias[$diaSemana - 1]->getEvento();
    }
    
    public function muestraEvento($diaSemana)
    {
        $this->dias[$diaSemana - 1]->muestraEvento();
    }
    
    /* Muestra el HTML correspondiente a una semana */
    public function muestraSemana()
    {
        /*Se abre la fila*/
        printf("<tr>\n");
        
        /*La primera columna lleva el número de semana*/
        printf("<td class=\"semana\"> %d </td>\n", $this->numSemanaAnyo);
        
        /*Se genera el HTML de los días*/
        foreach($this->dias as $dia)
        {
            $dia->muestraDia();
        }
        
        /*Se cierra la fila*/
        printf("</tr>\n"); 
    }
}

Thursday, March 25, 2010

Agenda mensual con calendario en PHP (III)

Esta es la clase para los días.

En este caso lo he limitado a un evento por día pero usando un array se puede modificar para recoger varios eventos por día.

/* Clase Dia */
class Dia
{   
    /* Miembros */
    private $perteneceAlMes; //Indica si pertenece al mes que muestra en el calendario
    private $numDia;         //Número del día en el mes
    private $diaSemana;      //Número del día de la semana
    private $evento;         //Objeto de la clase evento que contiene los datos asociados a un evento
    private $hayEvento;
    
    /* Constructor */
    public function __construct($diaSemana, $diaActual, $perteneceAlMes)  
    {

        //Pertenece al mes
        $this->setPerteneceAlMes($perteneceAlMes);
        
        //Día del mes
        if(!$perteneceAlMes)
        {
           $this->setNumDia(-1);
        }
        else
        {
           $this->setNumDia($diaActual);
        }
        
        //Día de la semana
        $this->setDiaSemana($diaSemana);
        
        //En principio no hay ningún evento
        $this->setHayEvento(false);
        
    }

    /* Métodos de acceso */
    public function setHayEvento($hayEvento) 
    {
        $this->hayEvento = $hayEvento;
    }
    
    public function getHayEvento() 
    {
        return $this->hayEvento;
    }
    
    public function setPerteneceAlMes($perteneceAlMes) 
    {
        $this->perteneceAlMes = $perteneceAlMes;
    }
    
    public function getPerteneceAlMes() 
    {
        return $this->perteneceAlMes;
    }

    public function setNumDia($numDia) 
    {
        $this->numDia = $numDia;
    }

    public function getNumDia() 
    {
        return $this->numDia;
    }
    
    public function setDiaSemana($diaSemana) 
    {
        $this->diaSemana = $diaSemana;
    }
    
    public function setEvento($evento) 
    {
        $this->evento = $evento;
        $this->setHayEvento(true); 
    }

    public function getEvento() 
    {
        return $this->evento;
    }
    
    public function muestraEvento()
    {
        $this->evento->muestraEvento();
    }
    
    /* Métodos */
    
    /* Muestra el HTML correspondiente a un día */
    public function muestraDia()
    {
        //Si el día pertenece al mes    
        if($this->getPerteneceAlMes())
        {
            //Si hay un evento en el día
            if($this->getHayEvento())
            {
                $numDia = $this->getNumDia();
                printf( "<td class =\"hayEvento\"<a href=\"#\" onClick=\"verEvento(%d)\">
                         %d</a></td>\n", 
                         $numDia, $numDia );                           
            }
            //Si no lo hay
            else
            {
                printf( "<td class=\"noHayEvento\">%d</td>\n", $this->getNumDia() );
            }
        }
        //Si el día no pertenece al mes
        else
        {
            printf("<td></td>\n");
        }
    }
}

Tuesday, March 23, 2010

Agenda mensual con calendario en PHP (II)

Esta clase la uso para los eventos de la agenda:
    
/* Clase Evento */
class Evento
{
    /* Miembros */
    private $referencia;
    private $nombre;
    private $fecha;
    private $hora;
    private $lugar;
    private $descripcion;
    
    /* Constructor */
    public function __construct($referencia, $nombre, $fecha, $hora, $descripcion, $lugar)  
    {
        $this->setReferencia($referencia);
        $this->setNombre($nombre);
        $this->setFecha($fecha);
        $this->setHora($hora);
        $this->setLugar($lugar);
        $this->setDescripcion($descripcion);
    }
    
    /* Métodos de acceso */
    public function getReferencia()
    {
        return $this->referencia;
    }
    
    public function setReferencia($referencia)
    {
        $this->referencia = $referencia;
    }
    
    public function getNombre()
    {
        return $this->nombre;
    }
    
    public function setNombre($nombre)
    {
        $this->nombre = $nombre;
    }
    
    public function getFecha()
    {
        return $this->fecha;
    }
    
    public function setFecha($fecha)
    {
        $this->fecha = $fecha;
    }
    
    public function getHora()
    {
        return $this->hora;
    }
    
    public function setHora($hora)
    {
        $this->hora = $hora;
    }
    
    public function getLugar()
    {
        return $this->lugar;
    }
    
    public function setLugar($lugar)
    {
        $this->lugar = $lugar;
    }
    
    public function getDescripcion()
    {
        return $this->descripcion;
    }
    
    public function setDescripcion($descripcion)
    {
        $this->descripcion = $descripcion;
    }
    
    /* Métodos */
    public function muestraEvento()
    {
       printf("%s \n", $this->getNombre());
       printf("Fecha: %s \n", $this->getFecha());
       printf("Hora: %s \n", $this->getHora());
       printf("Lugar: %s \n", $this->getLugar());
       printf("Descripción: %s \n",
                                              $this->getDescripcion());   
    }
}

Agenda mensual con calendario en PHP (I)

Hace poco hice un calendario en PHP para prácticar.

Estas son algunas de las clases que creé:

Esta es una clase con métodos estáticos que sirven para hacer diferentes cálculos con fechas.
/* Clase Fechas */
class Fechas
{
    /* Obtiene el día de la semana a partir del año, del mes y del día */
    public static function getDiaSemana($anyo, $mes, $dia)
    {               
        /*Módulos acumulados del número de días antes del inicio de mes para años normales y bisisestos*/
        $modMeses = array(0,3,3,6,1,4,6,2,5,0,3,5);
        $modMesesBis = array(0,3,4,0,2,5,0,3,6,1,4,6); 
        
        /*Se comprueba si el año es bisiesto para saber cual de los dos vectores anteriores usar*/
        if( 1 == Fechas::esBisiesto($anyo))
        {
            $dMes = $modMesesBis[$mes-1];
        }
        else
        {
            $dMes = $modMeses[$mes-1];
        }
        
        /*Se calcula el día de la semana correspondiente a la fecha*/
        $divEntera1 = (int) ( ($anyo - 1.0) / 4.0 ); 
        $divEntera2 = (int) ( ($anyo - 1.0) / 100.0 );
        $divEntera3 = (int) ( ($divEntera2 + 1.0) / 4.0 );
        $divEntera4 =(int) ( $divEntera1 - 3 * $divEntera3 );
        
        /*Fórmula del día de la semana*/
        $diaSemana = ( (($anyo - 1) % 7) + ($divEntera4 % 7) + $dMes + ($dia % 7)  ) % 7;
        
        /*El 0 corresponde al Domingo*/
        if( 0 == $diaSemana) 
        {
            $diaSemana = 7;
        }
        return $diaSemana; 
    }
    
    /* Calcula la semana del año a partir del día, el mes y el año */
    public static function getSemanaAnyo($anyo, $mes, $dia)
    {   
        //Valores de los días acumulados antes del principio de cada mes
        $ordinalesNormal=array(0, 31, 59,  90, 120, 151, 181, 212, 243, 273, 304, 334);
        $ordinalesBisiesto=array(0,  31,  60,  91, 121, 152, 182, 213, 244, 274, 305, 335);
        
        //Según el año sea bisiesto o no se usan unos valores u otros
        if( 1 == Fechas::esBisiesto($anyo))
        {
           $ordinal= $ordinalesBisiesto[$mes - 1];
        }
        {
           $ordinal= $ordinalesNormal[$mes - 1];
        }
        
        //Se calcula el día ordinal
        $ordinal = $ordinal + $dia;
        
        //Se obtiene el número del día de la semana correspondiente a la fecha (L=1,...,D=7)
        $diaSemana = Fechas::getDiaSemana($anyo,$mes,$dia);
        
        //Se calcula la semana del año
        $semanaAnyo=(int) (( $ordinal - $diaSemana + 10)/7);
        
        //Si es cero quiere decir que es la última semana del año anterior
        if($semanaAnyo == 0)
        {
            $semanaAnyo = 53;
        }
        //Si es 53 es la última semana del año anterior
        else if($semanaAnyo == 53)
        {
            if( ( Fechas::getDiaSemana($anyo, $mes, 31) - 1 ) <= 2)
            {
                $semanaAnyo = 1;
            }
        }
        return $semanaAnyo;
    }
    
    /* Comprueba si un año es bisiesto */
    public static function esBisiesto($anyo)
    {            
        $a = (0 == $anyo%4); /*Año divisible por 4*/
        $b = (0 == $anyo%100); /*Año divisible por 100*/
        $c = (0 == $anyo%400);/*Año divisible por 400*/
        
        /*Un año es bisiesto si es divisible por 4 y por 400 
          o si es divisible por 4 pero no por 100 */
        $loEs = $a && ($c || !$b);
        
        return $loEs;
    }
    
    /* Devuelve el día en que acaba un mes */
    public static function getFinMes($anyo,$mes)
    {              
        /*Número de días de cada mes*/
        $diasMeses=array(31,28,31,30,31,30,31,31,30,31,30,31);
        $diasMesesBis=array(31,29,31,30,31,30,31,31,30,31,30,31);
        
        /*Según el año sea bisiesto o no, se usan unos valores u otros*/
        if( 1 == Fechas::esBisiesto($anyo) )
        {                
            $finMes = $diasMesesBis[$mes-1];
        }
        else
        {
            $finMes = $diasMeses[$mes-1];
        }

        return $finMes;
    }

}

Sunday, March 21, 2010

Completísimo curso de C++ orientado a objetos

He encontrado un curso de C++ orientado a objetos que está muuuy bien.
Me hubiera sido muy útil mientras hacía la parte de C++ de la asignatura de Introducció al desenvolupament de programari, que la verdad tenía muy poco de introducción.

Master Software Libre UOC: Introducció al Desenvolupament de programari

El semestre pasado hice la asignatura de Introducció al desenvolupament de programari de la UOC. Aprendí mucho y al final me fue muy bien, pero considero que hay una serie de cosas que sería interesante saber antes de matricularse.
Este es un extracto del análisis que posteé en el foro de CAUOC:
...lo de Introducció no es cierto. El ritmo de la asignatura y el nivel de exigencia y dimensión de las PACs, han hecho que la mayoría de las personas sin experiencia en programación acabaran abandonando la asignatura. Si no han programado nunca, esta no es la asignatura para empezar a aprender.

...el material de la asignatura es insuficiente para poder sacar las PACs adelante. Sólo se salva la parte de C. En las de C++ y Java casi no hay ejemplos y se pasa por encima o sólo se nombran cosas que luego son importantísimas para poder sacar adelante las PACs.

He aprendido bastante y al final he conseguido sacarla, pero considero que, a causa de PAcs sobredimensionadas y con un nivel de exigencia muy superior al que se encuentra en los materiales que facilitan, he tenido que invertir en ella demasiado tiempo.

Espero que el aluvión de quejas que han recibido este semestre, sirva para que la asignatura mejore para próximos semestres.

Al final, en respuesta a las quejas, parece que la UOC piensa revisar el material de la asignatura y cambiar su nombre quitando la palabra "Introducció".

Esperemos que así sea.

Sunday, February 28, 2010

Miniprueba con SWIG

Hoy hice una pequeña prueba con SWIG.
El ejemplo que aparece en SWIG: donde C y Python se dan la mano (está muuuy bien explicado) hizo que me picará la curiosidad.

SWIG es una herramienta que permite conectar programas escritos en C/C++ con diferentes lenguajes de alto nivel (lenguajes que soporta).
En este caso, lo probé con Python y C.

Este es el header de mi código en C:
#ifndef __DATOS_PERSONALES_H__
#define  __DATOS_PERSONALES_H__

#include 
#include 

/* Tipos */
typedef struct {
  char nombre[150];
  int  edad;
}DatosPersona;

/* Prototipos */
extern int edad_get(DatosPersona a);
extern char * nombre_get(DatosPersona a);
extern void nombre_set(DatosPersona *a, char * nombre);
extern void edad_set(DatosPersona *a, int edad);
extern void muestra(DatosPersona a);

#endif /* __DATOS_PERSONALES_H__ */

Y este es el código en si:
#include "datosPersonales.h"

int edad_get(DatosPersona a)
{
    return a.edad;
}

char * nombre_get(DatosPersona a)
{
   return a.nombre;
}

void nombre_set(DatosPersona *a, char * nombre)
{
   strcpy(a->nombre, nombre);
}

void edad_set(DatosPersona *a, int edad)
{
    a->edad = edad;
}

void muestra(DatosPersona a)
{
    printf("Me llamo %s y tengo %d años.\n", a.nombre, a.edad);
}

Ahora viene lo interesante. Hay que definir una interfaz en un fichero con extensión .i, en la que se dan a SWIG instrucciones para construir el envoltorio para usar el código.
Hay muchas posibilidades, (la documentación es muy extensa), y después de pasarme unas horillas buscando llegué a lo siguiente:
%module datosPersonales
%{
#include "datosPersonales.h"
%}

typedef struct {
  char nombre[150];
  int  edad;
}DatosPersona;

%extend DatosPersona
{
    DatosPersona(char *nombre, int edad)
    {
        DatosPersona *datos = (DatosPersona *) malloc(sizeof(DatosPersona));
        strcpy ( datos->nombre, nombre );
        
        datos->edad = edad;
        return datos;
    }
    
    ~DatosPersona() 
    { 
        free(self); 
    }
    
    int getEdad()
    { 
        edad_get( *self ); 
    }
    
    char * getNombre()
    { 
        return nombre_get( *self ); 
    }
    
    void setNombre(char *nombre)
    {
        nombre_set(self, nombre);
    }
    
    void setEdad(int edad)
    {
        edad_set(self, edad);
    }
    
    void muestraDatos()
    {
        muestra(*self);
    } 
};

En esta interfaz se extiende el tipo de datos de C con una serie de funciones miembro que nos permitirán usar orientación a objetos en Python.

Para compilar hice lo siguiente:
$ swig -python datosPersonales.i
$ ls
datosPersonales.c  datosPersonales.i   datosPersonales_wrap.c  
datosPersonales.h  datosPersonales.py
$ gcc -c datosPersonales.c
$ ls
datosPersonales.c  datosPersonales.i  datosPersonales.py
datosPersonales.h  datosPersonales.o  datosPersonales_wrap.c
$ gcc -c datosPersonales_wrap.c -I /usr/include/python2.5/
$ ls
datosPersonales.c  datosPersonales.i  datosPersonales.py datosPersonales_wrap.o 
datosPersonales.h  datosPersonales.o  datosPersonales_wrap.c
$ gcc -shared datosPersonales.o datosPersonales_wrap.o -o _datosPersonales.so
$ ls
datosPersonales.c  datosPersonales.i  datosPersonales.py   datosPersonales_wrap.c  
datosPersonales.h  datosPersonales.o  _datosPersonales.so  datosPersonales_wrap.o

Ahora ya está todo listo para poder usar el módulo datosPersonales.py desde Python.

import datosPersonales as dp

datos = dp.DatosPersona("Lolo", 34)

print datos.getEdad()
print datos.getNombre()

datos.muestraDatos()

datos.setNombre("Javi")
datos.setEdad(31)
datos.muestraDatos()

del datos

Y esto es lo que resulta al ejecutar el script:

$ python runMe.py 
34
Lolo
Me llamo Lolo y tengo 34 años.
Me llamo Javi y tengo 31 años.

Este ejemplo no deja de ser una tontería, pero las posibilidades de SWIG son grandísimas (sólo hay que ver algunos de los artículos online que aparecen en Internet).
Más adelante, si tengo algo de tiempo, me gustaría correr alguna simulación escrita en C desde Python y usar MatPlotLib para hacer los gráficos.

Friday, February 26, 2010

Cómo escribir código imposible de mantener

En How To Write Unmaintainable Code se describe una serie de pasos que debemos seguir para dificultar la mantenibilidad de nuestro código. Este irónico artículo, al que llegué desde una respuesta en un foro de Java llamado Java Ranch, puede ayudarnos a escribir código más fácil de mantener.

Thursday, February 25, 2010

Como poner letras griegas en un gráfico de Gnuplot

Usando el terminal Enhanced Postscript se pueden escribir un montón de símbolos usando una sintáxis parecida a la de Latex.

Existe una guía de dicha sintaxis en la que aparecen un montón de ejemplos.

En el siguiente gráfico utilicé la terminal EPS para poder usar letras griegas en las etiquetas de los ejes:


Este es el script que utilicé:
reset 
#Rango
set xrange [0:3]
set yrange [-2.5:4.5]
#Rango e intervalo de los xtics
set xtics -3,0.5,10
#Rango e intervalo de los ytics
set ytics -2.5,0.5,4.5

#Etiquetas de los ejes con letras griegas
set xlabel "t/{/Symbol p}"
set ylabel "{/Symbol q}"

#Se establece la posición de la leyenda
set key
#Se establece el origen
set origin 0,0
#Se establece el ratio entre el alto y el ancho del gráfico
set size ratio 0.5

#Se establece como terminal de salida un eps en color con letra Arial de tamaño 11
set term post eps enhanced color "Arial" 11

#Tamaño del gráfico
set size 1,1
#Con marco 
set border

#Fichero de salida
set output "theta.eps"

#Se plotean los datos
plot 'pos1.dat' using 1:2 title 'E=0.25' with lines, \
        'pos2.dat' using 1:2 title 'E=0.50' with lines, \
        'pos3.dat' using 1:2 title 'E=0.75' with lines, \
        'pos4.dat' using 1:2 title 'E=1.00' with lines, \
        'pos5.dat' using 1:2 title 'E=1.25' with lines
]]>

Gnuplot not so Frequently Asked Questions

Gnuplot not so Frequently Asked Questions es un sitio que contiene muchísimos trucos para mejorar la calidad de tus gráficos hechos con Gnuplot.
Me sirvió muchísimo mientras hacía la asignatura de Introducción a la Física Computacional.
-----
Gnuplot not so Frequently Asked Questions is a site that contains a lot of tips and shortcuts to improve your Gnuplot graphics.
It helped me a lot during the Introducction to Computacional Physics course.