Entradas de la categoría ‘Desarrollo’

Iniciar a los niños en el mundo de la programación informática con Scratch

Scratch

Scratch

Si eres un “developer, developer, developer!”, como diría Steve Ballmer, y tienes hijos pequeños, es muy probable que te agrade la posibilidad de que, en un futuro (o ya), tu retoño dirija sus pasos hacia el mundo del desarrollo informático. Puede parecer una misión compleja, teniendo en cuenta los entornos de desarrollo actuales tan avanzados, pero siempre hay alguien dispuesto a echarnos una manita de manera altruista y muy profesional.  

Scratch es una herramienta gratuita para que los más pequeños de la casa se inicien en el cruel mundo del desarrollo de software (sí, cruel he dicho). Si me apuras, los mayores que no tengan ni repajolera idea de escribir un programa informático podrían hacer uso también de ella para sus primeros pinitos, aunque en principio el software está diseñado para los niños entre 6 y 16 años. De todas las herramientas que conozco para iniciar a los pequeños en la programación, esta es la que más me ha gustado con diferencia por su facilidad de uso, su interfaz intuitiva y, sobre todo, porque su curva de aprendizaje tiene muy poco de curva y mucho de aprendizaje. (Por cierto, aunque parezca mentira, esto no es un post patrocinado ni nada por el estilo).  

Scratch se basa en scripts o guiones de acciones por lotes que se asocian a objetos (sprites) o escenas en pantalla. Los sprites son pequeños elementos visuales que representan una imagen o icono, no en vano Scratch está eminentemente preparado para que los niños aprendan creando una historia interactiva, un juego o una animación, es decir, que aprendan jugando. Cada objeto es susceptible de tener diversos disfraces o personalizaciones, así como sonidos asociados, lo que permite variar el objeto en función de determinadas circunstancias. Esto nos recuerda a la propiedad de los personajes de cualquier juego de cambiar su apariencia dependiendo de la dirección en la que caminen, si saltan, corren o pierden una vida.  

Pantalla principal de Scratch

Pantalla principal de Scratch

La característica más importante de Scratch es la falta de necesidad de introducir una sola línea de código para generar un programa. La aplicación funciona por medio de los denominados bloques, agrupados en paletas según sus características. Un bloque es una pieza o elemento que encierra una acción que puede ser de apariencia, de sonido, de movimiento, de decisión, de control, etcétera. Los bloques se arrastran de la Paleta de bloques al Panel de script, creando pilas o conjuntos de bloques que constituyen en sí mismos pequeños programas o subrutinas del programa general al que pertenecen.  

Por ejemplo, en la siguiente imagen se muestra un script que hará moverse el objeto formando un cuadrado en cinco ocasiones consecutivas. Entre cada acción se ha insertado un retardo de un segundo para apreciar bien los movimientos; además, el disparador del comienzo de la acción es la pulsación de la barra espaciadora.  

Script en Scratch

Script en Scratch

Como se puede apreciar, Scratch es sumamente sencillo de manejar. Simplemente habrá que ir arrastrando bloques de acciones para crear programas que afectarán a un objeto o a una escena completa. Cada objeto y cada escena tienen sus propios grupos de bloques que funcionan de manera independiente, ejecutando cada tarea en el momento preciso.  

Scratch dispone de bloques de acciones totalmente engarzados con la estructura de la programación “adulta” actual orientada a objetos, y ese es su mejor medio de presentación para el aprendizaje. Disponemos de estructuras de control, repeticiones y bucles, sentencias condicionales, empleo de variables globales y locales, manejo de cadenas de texto, listas o matrices unidimensionales de objetos, operadores aritméticos y booleanos, comparaciones, control de eventos, etcétera. Es más que posible desarrollar cualquier programa sencillo con Scratch, además de las animaciones y juegos a los que está orientado. Para estos últimos también gozamos de características implementadas de fábrica como el movimiento de personajes, el rebote de objetos o el control de colisiones.  

Además de todo ello, Scratch tiene una característica bastante interesante, que es la de subir al sitio web de la aplicación nuestras últimas creaciones para compartirlas con toda la comunidad (bajo licencia Creative Commons); y todo ello de una manera automática. Estas aplicaciones en línea se reproducen sobre un applet de Java, sin embargo, para ejecutar los programas en local deberemos tener instalada la herramienta en sí, ya que Scratch no dispone de un compilador al uso que nos permita generar un archivo ejecutable compatible con nuestro sistema operativo.  

Y para los más friquis también tenemos importantes noticias, ya que Scratch es capaz de conectar con los productos LEGO WeDo y dispone de bloques de acciones específicamente diseñados para interactuar con los motores de tus diseños de robótica. Simplemente habremos de conectar nuestro robot LEGO con el ordenador vía USB y generar el programa correspondiente desde Scratch con la misma facilidad que hemos comentado anteriormente.

En el siguiente vídeo (en inglés) se puede ver el desarrollo de una aplicación en Scratch que maneja un robot de LEGO WeDo con forma y movimientos de portero de fútbol.

Imagen de previsualización de YouTube 

¿Te he convencido ya? ¿Todavía no? Esto de Scratch parece salido de la mente de un padre rarito que quería que su hijo aprendiera a programar y le diseño una herramienta, ¿verdad? Pues espera a oír leer lo que sigue.  

Scratch es una herramienta multilingüística, gratuita y de software libre creada por el grupo Lifelong Kindergarten Group del MIT Media Lab, el departamento de tecnología y multimedia del Instituto Tecnológico de Massachusetts (MIT), en Estados Unidos. Está disponible para sistemas Windows, Linux y Mac OS X (qué pena de Solaris, pero nadie es perfecto), y es un proyecto dirigido por Mitchel Resnick y financiado por la National Science Foundation (Fundación Nacional de Ciencia) estadounidense, Microsoft, Intel, Nokia, Iomega y los consorcios de investigación del MIT Media Lab, además de otros organismos, universidades y empresas privadas.  

Es uno de los softwares educativos más reconocidos a nivel mundial y especialmente recomendado por el Observatorio Tecnológico del Ministerio de Educación español. Se utiliza en todo el mundo en muchos entornos diferentes: escuelas, museos, centros de aprendizaje, hogares, ayuntamientos…  

El 15 de diciembre de 2009, la comunidad web de Scratch contaba con más de 408.227 miembros registrados (95.033 de ellos habían colgado sus proyectos), con un total de 796.359 proyectos compartidos por la comunidad. El sitio web obtiene cerca de 7.000.000 de páginas vistas al mes. En el año 2010, la web de Scratch cuenta con más de un millón de proyectos alojados y compartidos (código fuente incluido). Además, cada cierto tiempo se celebra el Scratch Design Studio, un evento basado en desafíos que fomentan la creación y el intercambio de ideas y proyectos. Asimismo, disponen de una comunidad en línea exclusiva para educadores denominada ScratchEd.  

El éxito de la herramienta es tal que se ha desarrollado incluso algún que otro mod, o modificación alternativa derivada del original, basado en el código fuente de Scratch y que agrega nuevos bloques de funciones o cambios en la interfaz gráfica, siendo los más relevantes BYOB (programado por Jeans), Panther (por Panther Team) y Streak (de Billyedward).  

¿Cómo se te queda el cuerpo ahora? La verdad es que es la herramienta ideal a la disposición de niños y adolescentes para iniciarse en el mundo del desarrollo de software. Y hablamos de iniciarse, por lo que nadie espere conexión con bases de datos distribuidas, herencia y polimorfismo o recursividad; tampoco hay que pasarse. Aunque si piensas que  sólo vas a poder desarrollar estúpidas animaciones infantiles, te recomiendo que recorras la galería de proyectos destacados de la web de Scratch y visualices joyas como Sonic Advance 2, Piano~, 3D duplivert wave o Tarati.  

Scratch es la mejor opción para comenzar desde cero (from scratch, en inglés) y obtener una sólida base que permita posteriormente migrar a entornos de desarrollo más “serios”.

(HTML5 + CSS3) – Flash = Web futura

Adobe herida de muerte

Adobe herida de muerte

Flash is nearly dead, i’m sorry. Fue bonito mientras duró, pero a la tecnología Flash le quedan cuatro telediarios. Tuvo un auge muy importante en su época y representó una revolución importantísima para el desarrollo web dinámico, pero hemos llegado a un momento en el que no tiene sentido o, por lo menos, no tanto como antes.   

En mayo de 1995, una pequeña empresa de San Diego (California) llamada FutureWave Software desarrolló una aplicación para crear animaciones basadas en imágenes vectoriales con el fin de aumentar las capacidades de una herramienta anterior que permitía el dibujo vectorial. Aquella aplicación de animación se llamó FutureSplash Animator.   

En aquella época, la forma de crear animaciones para la floreciente World Wide Web era exclusivamente a través de Java, por lo que decidieron inventar algún sistema que permitiera embeber esas animaciones vectoriales en una página web. La tecnología tuvo tanto éxito entre los desarrolladores que importantes sitios web la integraron en sus interfaces de navegación, como por ejemplo MSN de Microsoft, la web oficial de The Simpsons o la web de Disney.   

Por aquel entonces, Disney trabajaba también con productos de Macromedia, y eso propició que ambas empresas, Macromedia y FutureWave Software, comenzaran a trabajar juntas para conseguir una conexión entre sus softwares. Finalmente, en diciembre de 1996, Macromedia compró FutureWave Software, convirtiendo la aplicación FutureSplash Animator en Macromedia Flash 1.0. Casi una década después, en 2005, la todopoderosa Adobe Systems compraría Macromedia y convertiría el producto, ya consolidado en el mercado, en el actual Adobe Flash.   

Durante más de diez años, Flash se convirtió en una herramienta indispensable para el desarrollador web. Prácticamente todos los sitios web se sentían obligados a incorporar animaciones para estar a la moda. Posteriormente se comenzaron a desarrollar web completas en Flash, totalmente dinámicas, animadas, interactivas y espectaculares. Con la aparición del formato Flash Video, las webs que incorporaban tecnología Flash se multiplicaron, y aparecieron sitios como YouTube o Google Vídeos utilizando dicha herramienta.   

Sin embargo, Flash acarrea muchos problemas. Para empezar es un formato propietario de Adobe, no abierto ni estandarizado. Esto hace que una sola empresa controle una tecnología que, al extenderse demasiado, puede convertirse en un peligroso monopolio, y para nada casa con la filosofía a la que tiende cada vez más Internet.   

Otro problema es el peso de las animaciones. Un archivo de Flash puede llegar a ocupar bastante espacio, con lo que la descarga desde una página web se convierte en tediosa. Además el consumo de recursos es notable, y los pequeños ordenadores modernos (netbooks), o los PC de bolsillo se las ven y se las desean para refrigerarse cuando hay Flash de por medio.   

Los buscadores tampoco se llevan nada bien con Flash. Al ser un producto encapsulado en su propio archivo, los motores de búsqueda no pueden acceder a su interior para indizar textos, enlaces o fotografías. Esto no es del todo cierto, pues Google y otros buscadores ya indexan desde hace años el contenido de los SWF, sin embargo no queda muy claro hasta qué punto se realiza esto y que importancia tiene (o le da Google) con respecto a otras tecnologías como HTML o XML.   

El camino que debemos seguir es el que nos lleva a la denominada web semántica, y Flash no es paradigma de ese futuro precisamente. Otras tecnologías en fase de creación, como la versión 5 de HTML, o la versión 3 de CSS sí van por el buen camino. HTML 5 es la quinta revisión del leguaje básico de la web. Sus nuevas características hacen de él muchísimo más estructural y semántico, y bastante potente, con funcionalidades a través de una interfaz estandarizada para, por ejemplo, reproducir audio y vídeo.   

El consorcio mundial de la web (WC3) hasta ahora había estado centrado en el desarrollo de SGML, XML, XForms, RSS, CSS e incluso AJAX, por lo que este cambio era necesario. Seguir utilizando un lenguaje que no ha cambiado desde 1999 es seguir siendo hombres de las cavernas. Nuestros navegadores ahora tienen pestañas, utilizamos RSS y conocemos XML, etcétera, sin embargo seguimos haciendo básicamente lo mismo que la década pasada: tablas (<table>) y párrafos (<p>).   

Los recientes rifirrafes entre Adobe y Apple a causa de la no inclusión de soporte Flash en el iPad han hecho saltar todas las alarmas. Lo cierto es que Apple no ha acertado del todo con esa política, y es que es cierto que un uso excesivo de Flash se zamparía los recursos y la batería del tablet en cero coma, pero tanto como eliminar el soporte nativo, me parece excesivo.   

Apple no ha sido el único en rechazar Flash. Webs tan importantes como YouTube han anunciado que migraran a HTML 5 todos sus vídeos, cosa que ya están haciendo en fase de pruebas. Por si fuera poco, empresas como Google, Facebook, Microsoft o Scridb han emitido comunicados en los que apuestan claramente por el matrimonio HTML 5 y CSS 3 como estándar de futuro. Hasta el sitio web pornográfico YouPorn, uno de los más importantes para adultos del mundo, ha anunciado que pronto tendra su versión en HTML 5.  Además cada vez se dejan ver más animaciones impresionantes realizadas sólo con la nueva versión de HTML. 

En fin, parece claro que lo que nos depara el futuro de Internet abandona un poco en la cuneta a Adobe y a su Flash. Sin embargo no tengo tan claro que Flash debiera desaparecer por completo, ya que reorientando la herramienta podría sacársele mucho partido en áreas como el desarrollo de cedés o deuvedés interactivos, el software de los puntos de información en museos y ciudades o, qué sé yo, cartas de vino multimedia en los restaurantes. 

Adobe, en la presentación de la suite CS5, dio a conocer una nueva función dentro de Flash CS5 muy arriesgada pero muy inteligente a la vez. Se trata de una herramienta que convertirá las animaciones Flash a HTML5 bajo la nueva etiqueta <canvas>. Un audaz movimiento, pues vendría siendo, por decirlo de una forma simple, matar definitivamente el plugin de Flash pero mantener el lenguaje de programación para desarrolladores, y a la vez seguir imprimiendo dinero para la firma. Habrá que probar bien esta característica para ver cómo de bien o de mal funciona, incluso con animaciones antiguas. 

Por supuesto que todo lo aquí expuesto se hace extensible a la tecnología Silverlight de Microsoft, que llegó tarde, mal y a rastras a competir con Flash, y nadie le hizo mucho caso (aunque admito que, posiblemente, sea hasta mejor que el propio Flash). 

Flash es un muy buen producto, fácil de utilizar y con grandes posibilidades. Si en el futuro vemos esta tecnología pulular por la Red habrá de ser en pequeñas y contadas dosis, porque si no estaremos dando pasos hacia atrás.   

Web con acceso a datos sólo con Javascript y un TXT

Javascript + TXT

Javascript + TXT

En contra de lo que piensa el común de los mortales, es posible disponer de un sitio web con acceso a datos sin necesidad de utilizar ni una sola base de datos y ni una sola línea de código PHP o ASP. Es muy común descubrir foros de noticias donde los novatos preguntan cómo pueden acceder a una serie de datos almacenados sin necesidad de crear una web con código del lado del servidor, generando un acceso desde el propio navegador del lado del cliente. Y también es muy común encontrar las respuestas de “los entendidos” comentando que eso es imposible y que, si lo fuera, sería muy peligroso.  

Bueno, pues peligroso no sé, pero posible sí que es, y también muy sencillo. Sólo necesitamos un archivo de texto plano y unas cuantas sentencias en Javascript. ¿Empezamos?  

Si precisamos tener una web que almacene una gran cantidad de datos, como usuarios y contraseñas, artículos de una tienda, documentos o información de clientes y proveedores, se intuye necesario el camino más largo, esto es, un sitio con código de acceso a datos del lado del servidor (ASP, PHP…) y un gestor de bases de datos al uso (SQL Server, MySQL…). Sin embargo, en muchas ocasiones solamente es necesario mantener unos pocos datos que se actualizan a mano cada cierto tiempo, por ejemplo un listado de licitaciones abiertas de un ayuntamiento o una serie de ofertas de trabajo de una empresa.  

Cualquiera puede pensar que, en alguno de esos casos, la opción menos costosa sería la de modificar manualmente los archivos HTML cuando proceda y listo. Sin embargo, si la persona que tiene que realizar dichas modificaciones no es experta en diseño web (la secretaria del ayuntamiento, con respecto al ejemplo de las licitaciones, o la de la empresa, en el supuesto de las ofertas de trabajo) es más que probable que no sepa editar los documentos o que, si lo hace, los estropee para los restos.  

Para estas situaciones, o similares, existe un pequeño truco del que podemos hacer uso. El sistema consiste en pasar datos a un HTML como si de variables Javascript se tratara, enlazándolas desde un TXT externo. Veamos primero el archivo de texto y el HTML con Javascript para, después, pasar a comentarlos.  

  
Registro1="Administrador de sistemas";
Registro2="Programador en Java";
Registro3="Content Manager";
Registro4="Técnico Help Desk";
Enlace="empresa.html";
  
  
<html>

 <head>

  <script src="datos.txt"></script>

  <script type="text/javascript">
   function cargarDatos(){
    document.getElementById("Campo1").innerText=Registro1;
    document.getElementById("Campo2").innerText=Registro2;
    document.getElementById("Campo3").innerText=Registro3;
    document.getElementById("Campo4").innerText=Registro4;

    document.getElementById("CampoEnlace").href=Enlace;
   }
  </script>

 </head>

 <body onload="cargarDatos()">

  <table>
   <tr>
    <td colspan="3" id="Campo1"></td>
   </tr>

   <tr>
    <td id="Campo2"></td>
   </tr>

   <tr>
    <td id="Campo3"></td>
   </tr>

   <tr>
    <td id="Campo4"></td>
   </tr>
  </table>

  <br />
  <a id="CampoEnlace">Volver a la página anterior</a>

 </body>

</html>
  
Como podemos observar, el archivo de texto es muy sencillo, ya que sólo guarda una serie de constantes (Registro1, Registro2, Registro3, Registro4 y Enlace) con un valor alfanumérico asignado. Estas constantes las importamos desde el HTML como si de un archivo fuente de Javascript se tratase, concretamente en la línea <script src="datos.txt"></script>. De esta manera, el navegador adquiere el código externo para ser utilizado en la página actual, sólo que en este caso el código se compone exclusivamente de constantes y datos.  

Posteriormente se genera una función cargarDatos() (se inicia en el body onload) que lo que hace es asignar la información importada a cada etiqueta HTML identificada por su id, mediante la función document.getElementById. Hay que tener en cuenta el tipo de etiqueta que se quiere rellenar y sus peculiaridades particulares. Así pues, en el caso de los <td> (celdas regulares) se utiliza la propiedad innerText, y en el <a> (hipervínculo) se usa href para referirse al atributo que permite especificar el destino del enlace.  

Como vemos, es una técnica muy sencilla y altamente rentable, pues para pequeños conjuntos de información no sería necesario contratar alojamientos web de altas prestaciones en cuanto a acceso a datos se refiere. Además, lo único que debería aprender a manejar la persona al cargo es un software de FTP para poder subir el archivo TXT modificado cuando fuera necesario.  

Por supuesto que es un ejemplo muy sencillo, pero se puede complicar hasta el infinito. Imaginemos que deseamos ir añadiendo filas a la tabla dependiendo del número de registros, algo muy lógico; no siempre tienen por qué ser cuatro. El siguiente archivo de texto muestra un ejemplo de este caso.  

  
Registros=2;

Fecha1="11 de mayo de 2010";
Texto1="Contrato para el servicio de recepción y conserjería.";

Fecha2="11 de mayo de 2010";
Texto2="Contrato para el servicio de limpieza y mantenimiento.";
  
Veamos ahora cómo quedaría el código Javascript donde se define la función cargarDatos() en nuestro HTML.  

  
<script type="text/javascript">
 function cargarDatos(){
  var Elemento1;
  var Elemento2;

  for (i=1;i<=Registros;i++)
  {
   Elemento1="Fecha"+i;
   Elemento2="Texto"+i;
   document.getElementById(Elemento1).innerText=eval(Elemento1);
   document.getElementById(Elemento2).innerText=eval(Elemento2);
  }
 }
</script>
  
Podemos observar que ha cambiado sustancialmente. Ahora necesitamos un bucle (for) que recorra todos registros (variable Registros en el TXT) de uno en uno y vaya asignando valores a las etiquetas. En este caso hacemos uso de dos variables (Elemento1 y Elemento2) que nos sirven para generar los nombres de las etiquetas HTML para después pasárselas a la función getElementById. Además, por simplificar, hemos utilizado el mismo nombre de las etiquetas HTML para las constantes y deberemos evaluarlas con la función eval antes de asignarlas, porque si no Javascript no se entera al ser una cadena creada a mano mediante la concatenación de un texto y el valor del contador i.  

A continuación vemos el código Javascript para dibujar la tabla dependiendo del número de registros.  

  
<script type="text/javascript">
 document.write("<table>");
 for (i=1;i<=Registros;i++)
 { 
  document.write("<tr>");
  document.write("<td id='Fecha"+i+"'></td>");
  document.write("</tr>");

  document.write("<tr>");
  document.write("<td id='Texto"+i+"'></td>");
  document.write("</tr>");

  document.write("<tr><td>&nbsp;</td></tr>");
 }
 document.write("</table>");
</script>
  
Lo que hacemos simplemente es recorrer todos los registros e ir añadiendo filas y celdas con sus correspondientes etiquetas id. Al final de cada bucle se agrega una celda vacía (con un espacio) para separar un poco cada grupo.  

Evidentemente, el usuario deberá actualizar manualmente, además de los registros propiamente dichos, la constante que define el total de registros para que funcione todo bien. También habrá de preocuparse por escribir correlativamente los nombres de las constantes y no cometer ningún otro error en la generación del archivo.  

Lo que habíamos dicho al principio, si es un número reducido de registros de datos, y estos no se actualizan frecuentemente, nos puede ser de mucha utilidad el uso de esta técnica (hay que tener en cuenta que cada variable o constante es un espacio en memoria que ocupa sitio); para soluciones más complejas se nos queda corta. ¡Hala, a programar se ha dicho!

El cero negativo (-0) sí existe, lo siento mucho

-0

-0

Es curioso que en nuestro mundo cuadriculado de aritmética ordinaria, el cero (0) es cero y punto pelota. No tiene sentido un valor de nada con un signo, porque nada es eso, absolutamente nada. Sin embargo, en el mundo del desarrollo informático, y también de algunas ciencias experimentales (y de determinadas aplicaciones teóricas en la física estadística y otras disciplinas), algunas representaciones numéricas permiten la existencia de un cero negativo (-0), distinguiéndolo a la perfección del cero positivo (+0) y considerándolos dos valores diferentes. El concepto de cero con signo es contrario a la suposición general de la mayoría de los campos de matemáticas de que el cero negativo es lo mismo que cero.

El estándar de la IEEE para aritmética en coma flotante (IEEE 754) es el más extendido para las operaciones en doble precisión o punto flotante (un método de representación de números reales). Este estándar define formatos para la representación de números en coma flotante (incluyendo el cero) y valores no normalizados, así como valores especiales como infinito y NaN (Not a Number), con un conjunto de operaciones que trabaja sobre dichos valores.

El IEEE 754, presente en la mayoría de los ordenadores y de los lenguajes de programación, define pues un -0 y un +0. Estos dos ceros pueden ser considerados como una variante del conjunto extendido R de los números reales, que añadía dos elementos nuevos al conjunto básico R de números reales, el +∞ y el −∞. El menos cero se basa en el concepto de análisis matemático de acercarse a 0 desde abajo como un límite y, asimismo, puede ser utilizado, de manera informal, para referirse a un número negativo que se ha redondeado a cero. En las propias especificaciones del estándar se afirma que este valor hace que sea mucho más sencillo conseguir una buena precisión numérica en determinados problemas críticos, sobre todo si se calculan mediante funciones complejas elementales.

Las representaciones que permiten un cero negativo pueden llegar a ser una fuente de errores en programas si los desarrolladores de software no se dan cuenta (u olvidan) que, si bien ambos ceros se comportan como iguales ante comparaciones numéricas, son diferentes patrones de bits y dan resultados diferentes en algunas operaciones, como por ejemplo la división.

Representación binaria de 32 bits del cero negativo

Representación binaria de 32 bits del cero negativo

Supongamos dos valores x e y, además de los dos ceros (positivo y negativo), los dos infinitos (positivo y negativo) y el anteriormente comentado valor NaN. En la siguiente tabla se muestran los distintos resultados que producirían las diferentes divisiones entre ellos (fila divido entre columna).

/

+y

-y

+0

-0

+∞

-∞

NaN

+x

+z
-z
+∞
-∞
+0
-0
NaN

-x

-z
+z
-∞
+∞
-0
+0
NaN

+0

+0
-0
NaN
NaN
+0
-0
NaN

-0

-0
+0
NaN
NaN
-0
+0
NaN

+∞

+∞
-∞
+∞
-∞
NaN
NaN
NaN

-∞

-∞
+∞
-∞
+∞
NaN
NaN
NaN

NaN

NaN
NaN
NaN
NaN
NaN
NaN
NaN

Vamos a ver un pequeño programa codificado en Java que demuestre algunos de los resultados anteriores. El tipo de datos float de Java tiene completamente integrado el estándar IEEE 754, por lo que no tendremos ningún problema para comprobar los cocientes.

class CeroNegativo
{
 public static void main (String[] args)
 {
  float x,y,resultado;
  
  //+x:+y=+z
  x=1;
  y=1;
  resultado=x/y;
  System.out.println(x + "/" + y + "=" + resultado);
    
  //-x:-0=-infinito
  x=-1;
  y=0;
  resultado=x/y;
  System.out.println(x + "/" + y + "=" + resultado);
  
  //+x:-infinito=-0
  x=1;
  y=-1/new Float(-0.00);
  resultado=x/y;
  System.out.println(x + "/" + y + "=" + resultado);
  
  //0:0=NaN
  x=0;
  y=0;
  resultado=x/y;
  System.out.println(x + "/" + y + "=" + resultado);
 }
} 

Si nos fijamos en el segundo ejemplo (//+x:-infinito=-0), vemos que, como se explicaba en la tabla, un número positivo (+x) dividido entre menos infinito (−∞) da como resultado menos cero (-0). Para conseguir el valor de −∞, lo que hacemos es generar una división intermedia (-1/-0) cuyo cociente sea −∞ (siempre según la tabla), para que después este resultado pase a ser denominador del quebrado principal.

Esto anterior es perfectamente correcto en Java, y el resultado en línea de comandos sería lo siguiente.

1.0/1.0=1.0
-1.0/0.0=-Infinity
1.0/-Infinity=-0.0
0.0/0.0=NaN

Otras operaciones aritméticas con -0 arrojan distintos resultados. La multiplicación, por ejemplo, sigue sus mismas reglas de combinación de signos, esto es -0 × -0 = +0, y la raíz cuadrada de -0 (√-0) es igual a -0. Veamos estos dos ejemplitos en código Java.

import java.lang.Math;
 
class CeroNegativo
{
 public static void main (String[] args)
 {
  float x,y,resultado;
    
  //(-0)+(-0)=-0 
  x=new Float(-0.00);
  y=new Float(-0.00);
  resultado=x+y;
  System.out.println(x + "+" + y + "=" + resultado);
  
  //SQRT(-0)=-0 
  x=new Float(-0.00);
  resultado=(float)Math.sqrt(x);
  System.out.println("La raíz cuadrada de " + x + " es " + resultado);
 }
}

Y el resultado en línea de comandos sería el que sigue.

-0.0+-0.0=-0.0
La raíz cuadrada de -0.0 es -0.0

Con respecto a las comparaciones, se pueden utilizar los operadores comparativos usuales de los diversos lenguajes de programación, aunque, para evitar algunos errores, muchos lenguajes traen comparadores propios para este fin. Es el caso del método equals de la clase Double de Java.

Y aparte de la fricada informática que supone, ¿para qué demonios nos puede servir este absurdo número? Pues bien, como comentábamos al principio, en algunos ámbitos se puede utilizar de manera más o menos formal para establecer valores muy determinados. Por ejemplo, la notación -0 puede ser usada para indicar que se redondeó a cero un número negativo muy cercano a él. Esto puede ser útil cuando un signo negativo es significativo, por ejemplo en la tabulación de temperaturas en grados Celsius, donde un signo negativo significa algo muy preciso (temperaturas bajo cero). En este caso querría decir que la temperatura es algo inferior a cero, pero por próxima se redondeó.

Otro caso práctico sería el de la física estadística, en la que, a veces, se usan temperaturas negativas para describir sistemas con una inversión de población, que se puede considerar que tienen una temperatura mayor que el infinito positivo. En este contexto, una temperatura de cero negativo es una temperatura (teórica) más grande que cualquier otra temperatura negativa, correspondiente al máximo concebible de inversión de población.

En fin, que prácticamente el cero negativo es como un puñetero cero a la izquierda, o sea que no se utiliza para nada. Pero la próxima vez que algún matemático te diga que el -0 no existe, imprímele este post y explícale cómo los informáticos, a veces, tenemos ases en la manga que otros no tienen. Ajo y agua; lo siento mucho.

Algoritmos de ordenamiento

Flujo de un algoritmo

Flujo de un algoritmo

Los algoritmos de ordenación fueron para mí, en un época de mi vida, una especie de obsesión geek que me llevó a investigar, en los albores de Internet, miles de horas delante de la pantalla del ordenador con el único objeto de diseñar algo que fuera más rápido que lo que yo ya conocía. Eran tiempos en los que aún había más información en los libros que en la Red, y en el escritorio se apilaban revistas de informática, libros de programación, disquetes de 5,25″ y decenas de papeles con garabatos esbozados entre apuntes de direcciones web.

El hecho de disponer de una lista (numérica o alfanumérica) desordenada y conseguir ordenarla en un límite de tiempo lógico, ha traído de cabeza a los informáticos de medio mundo desde los tiempos aquellos en los que los primeros profesionales diseñaban aplicaciones bancarias para entidades financieras en lenguaje Cobol. El éxito consistía en lograr obtener un orden rápido y efectivo, ya que no era lo mismo esperar unos segundos para clasificar una matriz de 100 elementos que reordenar las cincuenta mil transacciones que se podían generar en una sucursal bancaria en un día.

El algoritmo de ordenamiento era, pues, muy importante. Pero cada algoritmo que se diseñaba para tal fin no era otra cosa que la genialidad de una mente preclara que, por casualidad o no, discurría un sistema de “cambiar éste de aquí por aquel de allí” para, sucesivamente, recorrer la lista de valores hasta ordenarla completamente.

Las máquinas computadoras, por definición, son tontas de manual. Un ordenador es incapaz de ordenar inteligentemente una lista de valores simplemente contemplándolos, como haría un ser humano. Es por ello que hay que desarrollar algoritmos, que no son ni más ni menos que una sucesión de procesos u operaciones perfectamente documentadas que se ejecutan con el fin de solucionar un problema dado. Posteriormente, estos algoritmos se codifican en un lenguaje de programación para que un ordenador los entienda y los maneje convenientemente.

Entonces, los algoritmos de ordenación son pautas que un software debe seguir para lograr ordenar una lista de elementos rápida y adecuadamente. Existen muchos y de muy variada condición y complejidad. Todos tienen pros y contras y todos contaron en su día (y cuentan hoy) con partidarios y detractores.

A día de hoy cada vez se han hecho menos necesarios estos métodos, ya que los elementos utilizados se almacenan en bases de datos muy avanzadas tecnológicamente y que poseen algoritmos de clasificación y ordenamiento propios. Pero no está mal para cualquier desarrollador conocerlos, porque, de hecho, a la hora de ponerse a programar los necesitaremos en multitud de ocasiones.

Siempre que escribo un post en el que va a haber códigos de ejemplo, nunca sé que lenguaje de programación utilizar; son tantos en la cabeza… Normalmente decido a bulto, para no decantarme por uno solo, así que hoy le ha tocado a Java porque sí, y punto. Se pueden encontrar en Internet multitud de ejemplos en los más variados lenguajes. Es posible que tampoco reseñemos absolutamente todos los algoritmos de ordenación que existen, pero sí vamos a estudiar los más importantes y extendidos.

1. Método de inserción directa (Insertion sort).
Este algoritmo es muy elemental, antiguo y lento, aunque su utilización está justificada en problemas pequeños debido a su bajo consumo de recursos. Este método toma cada elemento del arreglo para ser ordenado y lo compara con los que se encuentran en posiciones anteriores a la de él dentro del arreglo. Si resulta que el elemento con el que se está comparando es mayor que el elemento que ordenar, se recorre hacia la siguiente posición superior. Si por el contrario, resulta que el elemento con el que se está comparando es menor que el elemento que ordenar, se detiene el proceso de comparación, pues se encontró que el elemento ya está ordenado y se coloca en su posición (que es la siguiente a la del último número con el que se comparó).

void Insercion (int[] v) {
   for (int i=1; i<v.length; i++) {
      int aux = v[i];
      int j;
      for (j=i-1; j>=0 && v[j]>aux; j--)
         v[j+1] = v[j];
         v[j+1] = aux;
    }
}

2. Método de selección (Selection sort).
Este método también es muy lento, sin embargo, por su estructura, reduce al mínimo el número de intercambios. Consiste en encontrar el menor de todos los elementos del arreglo e intercambiarlo con el que está en la primera posición. Luego el segundo más pequeño, y así sucesivamente hasta ordenar todo el arreglo.

void Selecccion (int[] a) {
   for (int i = 0; i < a.length - 1; i++) {
     int min = i;
     for (int j = i + 1; j < a.length; j++) {
        if (a[j] < a[min]) {
           min = j;
        }
     }
     if (i != min) {
        int aux= a[i];
        a[i] = a[min];
        a[min] = aux;
     }
   }
}

3. Método de la burbuja (Bubble sort).
Este archiconocido método es muy parecido al de inserción directa pero mucho más rápido. Fue muy popular cuando apareció porque sustituía a los anteriores bajando drásticamente la velocidad de ordenación. Se recorre el arreglo intercambiando los elementos adyacentes que estén desordenados. Se recorre el arreglo tantas veces hasta que ya no haya cambios. Prácticamente lo que hace es tomar el elemento mayor y lo va corriendo de posición en posición hasta ponerlo en su lugar.

void Burbuja (int[] n) {
   int temp;
   int t = n.length;
   for (int i = 1; i < t; i++) {
      for (int k = t-1; k >= i; k--) {
         if(n[k] < n[k-1]){
            temp = n[k];
            n[k] = n[k-1];
            n[k-1]=  temp;
         }
      }
   }
}

4. Método de Shell (Shell sort).
El método de ordenación Shell, así llamado en honor a su inventor Donald Shell, es considerado un algoritmo avanzado cuya velocidad es notablemente mayor con respecto a los anteriores. Este método utiliza una segmentación entre los datos; funciona comparando elementos que están distantes. La distancia entre comparaciones decrece conforme el algoritmo se ejecuta hasta la última fase, en la cual se comparan los elementos adyacentes, por esta razón se le llama también ordenación por disminución de incrementos.

void Shell (int[] a) {
   for ( int increment = a.length / 2;
      increment > 0;
      increment = (increment == 2 ? 1 : (int) Math.round(increment / 2.2))) {
      for (int i = increment; i < a.length; i++) {
         for (int j = i; j >= increment && a[j - increment] > a[j]; j -= increment) {
            int temp = a[j];
            a[j] = a[j - increment];
            a[j - increment] = temp;
         }
      }
   }
}

5. Método de mezcla (Merge sort).
La ordenación por mezcla o combinación de capas se basa en la estrategia de dividir para conquistar (divide y vencerás). Primero divide el arreglo en dos, ordena recursivamente cada una de las partes y luego las mezcla. El procedimiento debe entonces recibir el arreglo y un par de índices que delimitan los bordes de la ordenación.

public class Mezcla {
   private int A[];
   public int[] Ordenar (int[] L) {
      int n = L.length;
      if (n > 1){ int m = (int) (Math.ceil(n/2.0));
         int [] L1 = new int[m];
         int [] L2 = new int[n-m];
         for (int i = 0; i < m; i++) {
           L1[i] = L[i];
         }
         for (int i = m; i < n; i++) {
            L2[i-m] = L[i];
         }
         L = Mezcla(Ordenar(L1), Ordenar(L2));
      }
      return L;
   }

   public int[] Eliminar (int [] l) {
      int [] L = new int[l.length-1];
      for(int i = 1; i < l.length; i++){
         L[i-1] = l[i];
      }
      return L;
   }

   public int[] Mezcla(int[] L1, int[] L2) {
      int[] L = new int[L1.length+L2.length];
      int i = 0;
      while ((L1.length != 0) && (L2.length != 0)) {
         if (L1[0] < L2[0]) {
            L[i++] = L1[0];
            L1 = eliminar(L1);
            if (L1.length == 0){ while (L2.length != 0) {
               L[i++] = L2[0];
               L2 = Eliminar(L2);
            }
         }
      }
      else {
         L[i++] = L2[0];
         L2 = Eliminar(L2);
         if (L2.length == 0) {
            while (L1.length != 0) {
               L[i++] = L1[0];
               L1 = eliminar(L1);
            }
         }
      }
   }
   return L;

   void GenerarNumeros() {
      Random ran = new Random();
      int x;
      for(int i = 0; i < A.length; i++) {
         x = (int)(ran.nextDouble()*10000);
         A[i] = x;
      }
   }

   void imprimir() {
      for(int i = 0; i < A.length; i++) {
         System.out.println(A[i]);
      }
   }

   int[] getA(){
      return A;
   }

   void setA(int []A){
      this.A = A;
   }
}

6. Método de montículos (Heap sort).
Este algoritmo consiste en almacenar todos los elementos del vector que se desea ordenar en un montículo (heap), para luego extraer el nodo que queda como nodo raíz del montículo (cima) en sucesivas iteraciones obteniendo el conjunto ordenado. Basa su funcionamiento en una propiedad de los montículos por la cual la cima contiene siempre el menor elemento (o el mayor, según se haya definido el montículo) de todos los almacenados en él.

import java.util.Arrays;
public class Heap {
   void main(String[] args) {
      int[] arry_int={49,38,65,97,76,13,27,55};
      Heap OrdenaHeap=new OrdenaHeap();
      hsort.OrdenaHeap(arry_int);
   }

   void AjustaHeap(int[] arr, int s,int m) {
      int temp=arr[s];
      for(int j=2*s+1;j<m;j=j*2+1) {
         if(j+1<m && arr[j]>arr[j+1]) ++j;
            if(temp<arr[j])break;
               arr[s]=arr[j];
               s=j;
               arr[s]=temp;
            }
         }

   void OrdenaHeap (int[] arr) {
      for(int i=(arr.length/2-1);i>=0;--i) {
         AjustaHeap(arr,i,arr.length);
      }
      for(int j=arr.length-1;j>0;--j) {
         System.out.println("Elemento superior del montículo arrr[0]="+arr[0]);
         System.out.println("arr["+j+"]="+arr[j]);
         System.out.println("se cambia con"+j+"element");
         int temp=arr[0];
         arr[0]=arr[j];
         arr[j]=temp;
         AjustaHeap(arr,0,j);
         System.out.println(Arrays.toString(arr));
      }
   }
}

7. Método de ordenamiento rápido (Quick sort).
Consiste en elegir un elemento de la lista para ordenar, al que llamaremos pivote. Resituamos los demás elementos de la lista a cada lado del pivote, de manera que a un lado queden todos los menores que él y al otro los mayores. Los elementos iguales al pivote pueden ser colocados tanto a su derecha como a su izquierda, dependiendo de la implementación deseada. En este momento, el pivote ocupa exactamente el lugar que le corresponderá en la lista ordenada. La lista queda separada en dos sublistas, una formada por los elementos a la izquierda del pivote y otra por los elementos a su derecha. Se repite este proceso de forma recursiva para cada sublista mientras éstas contengan más de un elemento. Una vez terminado el procedimiento, todos los elementos estarán ordenados.

void Rapido (int[] vector, int primero, int ultimo) {
   int i=primero, j=ultimo;
   int pivote=(vector[primero]+vector[ultimo])/2;
   int auxiliar;
   do {
      while(vector[i]<pivote) i++;   
      while(vector[j]>pivote) j--;

      if (i<=j) {
         auxiliar=vector[j];
         vector[j]=vector[i];
         vector[i]=auxiliar;
         i++;
         j--;
      }
   }
   while (i<=j);

   if(primero<j) ordenarQuicksort(vector,primero, j);
   if(ultimo>i) ordenarQuicksort(vector,i, ultimo);
}

8. Método de ordenamiento Radix (Radix sort).
Es un algoritmo de ordenamiento que ordena enteros procesando sus dígitos de forma individual. La mayor parte de los ordenadores digitales simbolizan internamente todos sus datos como representaciones electrónicas de números binarios, por lo que procesar los dígitos de las representaciones de enteros por representaciones de grupos de dígitos binarios es lo más conveniente.

public class Radix {
   void Radix (int[] arr) {
      if(arr.length == 0)
      return;
      int[][] np = new int[arr.length][2];
      int[] q = new int[0x100];
      int i,j,k,l,f = 0;
      for(k=0;k<4;k++) {
         for(i=0;i<(np.length-1);i++)
         np[i][1] = i+1;
         np[i][1] = -1;
         for(i=0;i<q.length;i++)
         q[i] = -1;
         for(f=i=0;i<arr.length;i++) {
            j = ((0xFF<<(k<<3))&arr[i])>>(k<<3);
            if(q[j] == -1)
            l = q[j] = f;
         else {
            l = q[j];
            while(np[l][1] != -1)
            l = np[l][1];
            np[l][1] = f;
            l = np[l][1];
         }
         f = np[f][1];
         np[l][0] = arr[i];
         np[l][1] = -1;
      }
      for(l=q[i=j=0];i<0x100;i++)
      for(l=q[i];l!=-1;l=np[l][1])
      arr[j++] = np[l][0];
   }

   void main(String[] args) {
      int i;
      int[] arr = new int[15];
      System.out.print("original: ");
      for(i=0;i<arr.length;i++) {
         arr[i] = (int)(Math.random() * 1024);
         System.out.print(arr[i] + " ");
      }

      Radix (arr);
      System.out.print("\nordenados: ");
      for(i=0;i<arr.length;i++)
      System.out.print(arr[i] + " ");
      System.out.println("\nHecho.");
   }
}
Sigue teknoPLOF! vía…
 
Twitter
RSS
 
Publicidad