December 2008 - Artículos

Anoche, por pura conjunción astral (estaban agotadas las entradas para "El intercambio" de Clint Eastwood, y otras películas más "apetecibles" empezaban ya muy tarde), y violando un principio que intento seguir las pocas veces que voy al cine, el de no elegir remakes de películas clásicas, que casi nunca (por no decir nunca) salen bien paradas ante mis ojos en comparación con sus originales, entramos a ver "Ultimátum a la Tierra", versión "modernizada" del clásico de ciencia-ficción "El día que paralizaron la Tierra" ("The Day the Earth Stood Still", Robert Wise, 1951).

La película confirmó la regla al 100%, y no tengo mucho que contar de ella. Probablemente lo que más llamó mi atención fue el mercantilismo descarado (blatant sería el adjetivo en inglés) que parece imperar en este tipo de cine "comercial" de hoy. Ante los ojos del espectador pasan sin tapujo alguno y a pantalla completa imágenes de productos de los "patrocinadores" que seguramente a cambio de esta publicidad ayudaron a costear los gastos de la película. Más aún, la mayoría de las veces esas imágenes se muestran de forma tal que el nombre de la marca quede bien visible, como ocurre en el momento en que la protagonista mira su reloj para ver la hora y las manecillas no estorban la lectura de la marca del reloj - ¡hubo suerte! En este aspecto, Microsoft fue tal vez un pelín más sutil: lo que aparece es el logo de Windows, sobre una gran pantalla multi-touch que me pareció un enorme Surface.


El bit matemático: Ya de madrugada, entre la almohada y yo hicimos el cálculo de la probabilidad de que, si se mira el reloj en un momento aleatorio del día, ni el horario ni el minutero estén entre las 10 y las 2. Obtuvimos 4/9 (0,444). ¿Correcto?

El bit nostálgico: Como todo no podía ser negativo, al menos ver esta película me ha traído a la mente gratos recuerdos asociados a las veces que vi la versión original: la primera de ellas aún siendo un adolescente, con mi padre (gran cinéfilo), por televisión; la siguiente, con mi gran amigo Alfonso Alonso (ninguna relación con el alcalde de Vitoria/Gastéiz), en el cine La Rampa de La Habana y alrededor de 1985, si la memoria no me traiciona.

 

Publicado por Octavio Hernández | 4 comment(s)
Archivado en:

Respondiendo a la invitación de mi buen amigo Rodrigo, posteo aquí (perdón por el Spanglish, que a veces me sabe a gloria) mi solución al descifrado del mensaje navideño hexadecimal enviado por Pablito. El hecho de que lo primero que me vino a mí a la mente fue un método extensor a-la-LINQ, mientras que a Rodrigo un algoritmo concurrente, me ha traído a la mente una frase que usaba a menudo mi abuela, "cada loco con su tema" (más sobre eso al final). Aunque obvia decir que lo de "loco" es en sentido figurado: yo a lo mejor lo estoy, pero difícilmente se pueda encontrar tanto en nuestra profesión como fuera de ella a alguien más "cuerdo" que Rodrigo.

Básicamente, lo que hice fue crear un método extensor de string que produce una secuencia con los caracteres que componen el mensaje de entrada. Aquí va todo el código fuente:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace ConsoleApplication5
{
  class Program
  {
    const string message =
      "%46%65%6C%69%63%65%73%20%46%69%65%73" +
      "%74%61%73%2C%20%63%61%63%68%6F%20%66" +
      "%72%69%6B%69%21%20%41%68%6F%72%61%2C" +
      "%20%64%65%6A%61%74%65%20%64%65%20%74" +
      "%6F%6E%74%65%72%69%61%73%20%79%20%76" +
      "%65%74%65%20%61%20%65%6D%62%6F%72%72" +
      "%61%63%68%61%72%74%65%20%75%6E%20%70" +
      "%6F%71%75%69%6E%21%21%20%4B%65%65%70" +
      "%20%52%6F%63%6B%69%6E%27%21%21";

    static void Main(string[] args)
    {
      Solution1();
      Solution2();

      const int TIMES = 100000;

      Console.WriteLine("Solution 1: " +
        Helper.Measure(Solution1, TIMES));
      Console.WriteLine("Solution 2: " +
        Helper.Measure(Solution2, TIMES));

      Console.ReadLine();
    }

    static void Solution1()
    {
      var sb = new StringBuilder();
      foreach (char c in message.DecryptedChars())
        sb.Append(c);
      Debug.WriteLine("Translation: " + sb.ToString());
    }

    static void Solution2()
    {
      var sb = new StringBuilder();
      foreach (char c in message.DecryptedChars2())
        sb.Append(c);
      Debug.WriteLine("Translation: " + sb.ToString());
    }
  }

  static class Helper
  {
    public static IEnumerable<char> DecryptedChars(this string source)
    {
      if (source == null)
        throw new ArgumentException("Source cannot be null");
      int times = source.Length / 3;
      for (int i = 0; i < times; i++)
      {
        yield return (char)int.Parse(source.Substring(3 * i + 1, 2),
          System.Globalization.NumberStyles.AllowHexSpecifier);
      }
    }

    public static IEnumerable<char> DecryptedChars2(this string source)
    {
      if (source == null)
        throw new ArgumentException("Source cannot be null");
      int times = source.Length / 3;
      char[] chars = new char[times];
      Parallel.For(0, times,
        (i) =>
        {
          chars[i] = (char)int.Parse(source.Substring(3 * i + 1, 2),
            System.Globalization.NumberStyles.AllowHexSpecifier);
        });
      for (int i = 0; i < times; i++)
        yield return chars[i];
    }

    public static long EllapsedTicks(Action action)
    {
      var sw = new Stopwatch();
      sw.Start();
      action();
      sw.Stop();
      return sw.ElapsedTicks;
    }

    public static long Measure(Action action, int times)
    {
      Debug.Assert(times > 0);
      long avg = 0;
      for (int i = 0; i < times; i++)
        avg += EllapsedTicks(action);
      return avg / times;
    }
  }
}

Originalmente, mi solución solo incluía el método DecryptedChars. Inspirado en el post de Rodrigo, y pensando en que el tipo de procesamiento se presta idealmente para la paralelización (se accede solo para lectura y a segmentos que no se solapan de la cadena de entrada), he creado una segunda variante del método que utiliza Parallel.For. En mi máquina de doble núcleo, no obstante, la variante secuencial es un 100% más eficiente; lo que indica que en la versión concurrente el coste de la creación del array temporal y los cambios de contexto supera las ventajas de la operación en paralelo. Pero en presencia de 4 ó más procesadores, el panorama podría ser diferente.


El bit nostálgico: Con "cada loco con su tema", mi abuela aludía frecuentemente a la exhuberancia sonora que se vivía en mi casa: un tipo de música diferente en cada habitación, todas sonando simultáneamente. Mi abuelo era un gran amante de la música tradicional cubana, y mi padre del jazz; mientras que yo me decantaba exclusivamente por el pop/rock de finales de los 60 y los 70. Mirando atrás, creo que mi hermano fue capaz de extraer y combinar lo mejor de todo aquello; yo en ese aspecto fui presa durante mucho tiempo de uno de los mayores males que pueden aquejar al ser humano en cualquier faceta de la vida: el sectarismo, totalitarismo, "pensamiento único" o como quiera que queramos llamar a ese state of mind en el que se considera que una sola cosa vale y todas las demás son 100% pura basura.

 

Publicado por Octavio Hernández | 6 comment(s)
Archivado en: ,,

Otra de las nuevas características que aparecerán en Visual Studio 2010 para simplificar el desarrollo de aplicaciones que acceden a las librerías COM de Microsoft Office es la que se conoce simplemente como "No PIA". La idea básica es la de que podamos librarnos de la necesidad de distribuir los ensamblados PIA (Primary Interoperability Assembly) correspondientes a las librerías COM que componen la suite Office con nuestras aplicaciones. En principio, esta tecnología podrá aplicarse en el futuro a cualquier otro componente COM. En este post mostraremos de manera práctica cómo funciona esta característica en VS 2010 CTP.

Supongamos que hemos creado la aplicación que utiliza la librería nativa de Word para crear un documento RTF que hemos presentado en un post anterior. Para compilar esa aplicación, fue necesario agregar una referencia al ensamblado de interoperabilidad, como muestra el Explorador de soluciones:

Figura 1

Si lanzamos Red Gate Reflector y estudiamos el ejecutable resultante, no veremos nada especialmente interesante:

Figura 2

Pero vayamos ahora al Explorador de soluciones, seleccionemos el ensamblado Microsoft.Office.Interop.Word, y en la ventana de Propiedades cambiemos a true el valor de Embed Interop Types.

Figura 3

Después de recompilar la aplicación y refrescar la vista de Reflector, veremos lo siguiente:

Figura 4 

Básicamente, la idea que subyace a No PIA es la embeber los tipos necesarios para comunicar con la librería nativa en nuestro propio ensamblado, en vez de generar un ensamblado de interoperabilidad o utilizar el PIA suministrado por el fabricante.

Al activar esta característica, deja de ser necesario el ensamblado de interoperabilidad, que no habrá que distribuir con nuestra aplicación ni cargar en memoria durante su ejecución. Pero aún hay más: como puede deducir de la imagen, los únicos tipos y métodos que se incorporarán a nuestro ensamblado son aquellos que nuestra aplicación necesita, lo que puede representar un enorme ahorro de espacio y tiempo de carga.


El bit nostálgico: Este post me ha traído a la mente una característica con ciertos tintes de similitud (el enlace selectivo de únicamente las características necesarias de una librería) que ofrecían los compiladores de Borland hace muchos años, y que se dio en llamar entonces "smart linking". Esta no es la única vez que, revisando las novedades de VS 2010 y C# 4.0, me vienen recuerdos de aquellos tiempos: con la nueva palabra reservada dynamic, me parece (y creo que no solo a mí) que C# está repitiendo la historia de Delphi.

Publicado por Octavio Hernández | 2 comment(s)
Archivado en:

Entre las "pequeñas cosas" que quedan ocultas en la CTP de Visual Studio 2010, eclipsadas por otras más novedosas, cabe destacar la presencia de un nuevo operador de consulta estándar de LINQ llamado Zip, que he encontrado, claro está, "buceando" con el Explorador de objetos. El operador Zip nos permitirá ir recorriendo simultáneamente la secuencia de entrada y una segunda secuencia, mientras ambas tengan elementos, produciendo una secuencia de salida con los elementos obtenidos mediante la aplicación de una función f(x, y) sobre los elementos correspondientes de las dos secuencias originales. Un pequeño ejemplo, como casi siempre, ilustrará mejor la utilidad de este operador:

using System;
using System.Linq;

static class Program
{
    static void Main(string[] args)
    {
        int[] a = { 1, 3, 5, 7, 9 };
        int[] b = { 2, 4, 6, 8 };

        var q = a.Zip(b, (x, y) => x * x + y * y);
        foreach (var n in q)
            Console.WriteLine(n);

        Console.ReadLine();
    }
}

El programa anterior produce en la consola la siguiente salida:

5
25
61
113

La CTP de Visual Studio 2010 está disponible aquí.

Rock tip (un poco forzado, la verdad :-). Como he escrito este post mientras estaba de viaje, pensé en titularlo "One More From the Road", pensando en este álbum, aunque luego cambié de idea. De la amplísima discografía de ese monster act del rock sureño que es Lynyrd Skynyrd, éste es el disco en directo que recomiendo: además de que fue el último en el que cantó Ronnie Van Zant (EPD), contiene mi versión favorita de ese himno del rock'n'roll que es "Free bird".

 

Publicado por Octavio Hernández | 5 comment(s)
Archivado en: ,,