El problema de la liebre

Tendria yo como unos 10 años cuando leí el siguiente acertijo en un libro llamado “A jugar con los números”:

Una liebre pesa 10 libras más la mitad de su peso. ¿Cuál es el peso de la liebre?

Inmediatamente llegué a una respuesta: 15. Busqué la solución al final del libro y decía simplemente:

20 libras (y no 15 como era de esperar).

Ni una palabra más ni una palabra menos.

Pregunté a algunos adultos muy pacientes y algunos también decían que 15. Si alguien me dijo que 20 fue por  usar alguna herramienta matemática (seguramente álgebra, pero yo ni si quiera sabía lo que era).

Cuando aprendí álgebra la ecuación resultó obvia:

p = 10 + p/2

Y manipular la ecuación para dejar sola la p es fácil: primero se multiplica todo por 2:

2p = 2*10 + 2p/2

2p = 20 + p

Y se le resta p a todo:

2pp = 20 + pp

p = 20

Bien, ya tengo la respuesta. Confirma que mi intuición estaba mal. Pero no me quedo agusto si hay una discrepancia entre la realidad y mi interpretación de la realidad. Ahora, ¿cómo corregir mi intuición? ¿Dónde estaba el error? ¿Podía haberlo comprendido yo, de niño, sin conocimiento de álgebra?

Sigue leyendo

Nuevo proyecto: Caddeus, un Makefile para TDD en C

Caddeus es un Makefile para GNU Make que sirve como plantilla para comenzar el desarrollo de cualquier proyecto en C. Caddeus está liberado bajo una licencia BSD simplificada. Caddeus está hospedado en Github en la siguiente dirección

https://github.com/alvarezp/caddeus

Esta plantilla soporta automáticamente:

Un modelo de desarrollo dirigido por pruebas (TDD): No es un framework sino la construcción de un módulo y su falla temprana sin reconstruir otros módulos ni reejecutar cada pruebas innecesariamente. La regla es muy simple: si tienes un modulo.c, crea otro llamado modulo.t.c y Make automáticamente compilará y ejecutará modulo.t.c automáticamente después y registrará si la prueba pasó. Cualquier modificación al módulo provocará una ejecución nueva de las pruebas de dicho módulo.

Un archivo llamado aplicacion.tt es considerado un script a ser ejecutado tras la compilación de la aplicación final, útil para prueba de integración.

Por defecto, las CFLAGS son muy estrictas, forzando la estandarización y la portabilidad (o la documentación de la falta de portabilidad) desde un principio: -std=c99 -W -Wall -Werror -Wextra -pendatic-errors. Si tu programa falla con estas banderas, intenta #define _GNU_SOURCE al principio de tu módulo y proponte como reto poder eliminar esa definición. Como resultado, tendrás un código de mayor calidad y mejor portabilidad.

Análisis estático automático, cortesía de CppCheck y Clang. Si están presentes en el sistema, todos tus módulos serán automáticamente revisados por CppCheck y Clang, dándote seguridad de un código fuente de mayor calidad.

Análisis automático de ejecución, cortesía de Valgrind. Si está instalado en el sistema, las pruebas unitarias se ejecutarán a través de Valgrind con revisión completa por fugas de memoria.

Todo lo anterior se desactiva automáticamente ante la presencia de un archivo “RELEASE”, lo que permite liberar código sin forzar a que el resto del mundo ejecute las mismas pruebas.

Se pueden establecer timeouts de manera opcional para dejar corriendo el juego de pruebas y si se cae en un ciclo infinito, el consumo del CPU se detenga después de un tiempo establecido.

Se generan automáticamente dependencias de los archivos .c a sus encabezados .h, de modo que al cambiar cualquiera de los encabezados, también se regeneran los módulos que correspondan.

Motivos para deshabilitar JavaScript (video en español)

Motivos para deshabilitar JavaScript. Está disponible en HD. Si le dan click al botón de YouTube, cambien la calidad por 720p para que se alcance a ver un poquito mejor la pantalla.

Presentado el 26 de noviembre de 2013 durante la reunión mensual del grupo Tijuana.js.

El audio está un poco fuerte, pero sirvió para poder oir algunas preguntas y comentarios que salieron. Entonces, de nada y sorry. ;-)

Asignacion de variables en Bash

En Bash, ¿qué diferencia hay entre las siguientes tres instrucciones?

  • VARIABLE=valor instrucción
  • VARIABLE=valor; instrucción
  • export VARIABLE=valor; instrucción

¿Por qué no todas las combinaciones funcionan cuando se invoca Make y por qué no todas las combinaciones funcionan con echo?

Asignar una variable puede afectar a una de dos: al ambiente o a las variables del shell. Pero ¿cuál afecta a cuál? Para acabar de complicar la situación, en algunos casos es un cambio persistente y en otros es un cambio temporal.

Para salir de la duda de una vez por todas y entender con exactitud lo que ocurre, he preparado una dupla de pruebas para cada una de las 3 sintaxis, resultando en 6 combinaciones:

  1. VAR=val env | grep VAR; env | grep VAR
  2. VAR=val; env | grep VAR; env | grep VAR
  3. export VAR=val; env | grep VAR; env | grep VAR
  4. VAR=val echo $VAR; echo $VAR
  5. VAR=val; echo $VAR; echo $VAR
  6. export VAR=val; echo $VAR; echo $VAR

Estas pruebas deberían ser suficientes para salir de la duda. Para asegurar la fiabilidad a las pruebas, cada una la envolví de esta forma, que permitirá, incluso, ver los saltos de línea:

(unset VAR; PRUEBA) | tr '\n' :; echo

Resultados:

VAR=val instr VAR=val; instr export VAR=val; instr
echo $VAR; echo $VAR :: val:val: val:val:
env | grep VAR; env | grep VAR VAR=val: (línea vacía) VAR=val:VAR=val:

Se concluye lo siguiente:

VAR=val instr VAR=val; instr export VAR=val; instr
Alcance Sólo para la instrucción especificada A partir de este momento A partr de este momento
Ambiente al que afecta Subproceso Shell actual Shell actual y subproceso

Tiene sentido:

En la sintaxis VAR=val instr, la asignación es un prefijo para instr y sólo para instr. Lo interesante es que sólo afecta al ambiente exportado a la instrucción. Es decir, VAR=val echo $VAR no funciona porque la variable la expande Bash mismo antes de asignar el valor val a VAR. En efecto: VAR=val1; VAR=val2 echo $VAR regresa val1.

En la sintaxis VAR=val; instr, el punto y coma efectivamente separa una instrucción de la otra. Es el equivalente de asignar el valor val a VAR antes que cualquier otra instrucción como una acción independiente; es una acción independiente. Esto le da la persistencia del valor tanto en esta sinaxis como en la tercera. Además, Bash, por defecto, no exporta sus variables al entorno. Esto hace que sólo se afecte la instrucción echo… O bueno… en realidad no, no es echo quien se está viendo afectado. Ojo: Echo no recibe la variable en su entorno: es Bash quien está expandiendo la variable a su valor al llamar echo, quien recibe el valor ya expandido como argumento.

La tercera sintaxis, export VAR=val; instr es igual a la segunda: dos instrucciones independientes, con la adición de que la instrucción export, naturalmente interna a Bash, indica que VAR se debe exportar al ambiente de los siguientes subprocesos. Es decir, tanto se asigna como se importa en la misma instrucción. Es por esto que afecta tanto a echo $VAR como a env, Make y lo que se ponga a su paso.

Siendo dos aspectos afectados y dos puntos a combinar podría pensarse que falta una cuarta sintaxis: export VAR=val instr, sin el punto y coma. Sin embargo, esta sintaxis es una simple invocación a export, indicando que queremos exportar las variables VAR e instr.

Referencia rápida de expresiones regulares

Como complemento a mi presentación de hoy en la reunión de noviembre del Gultij, publico esta tabla de expresiones regulares.

Observaciones:

  • Esta tabla no contempla la compatibilidad con POSIX. Por ejemplo, \b es un Perlismo que da la casualidad de que otros lo soportan también. Wikipedia trae información más detallada.
  • Perl toma algunas consideraciones con los fines de línea (\n). La manera más simple y segura de hacer matching en Perl de forma consistente con los demás motores es hacerle chomp a la línea. Como dicen en los comerciales: se aplican restricciones.

Si le detectan errores, por favor háganmelos saber.

Perl GNU Grep GNU Grep Ext Gawk GNU Sed GNU Sed Ext
Caracteres
Comodín . (punto) . (punto) . (punto) . (punto) . (punto) . (punto)
Juego [a-z] [a-z] [a-z] [a-z] [a-z] [a-z]
Excepto juego [^a-z] [^a-z] [^a-z] [^a-z] [^a-z] [^a-z]
Clase alpha [:alpha:] [:alpha:] [:alpha:] [:alpha:] [:alpha:] [:alpha:]
Clase dígitos [:digit:], \d [:digit:] [:digit:] [:digit:] [:digit:] [:digit:]
Clase controlchars [:cntrl:] [:cntrl:] [:cntrl:] [:cntrl:] [:cntrl:] [:cntrl:]
Clase alnum [:alnum:] [:alnum:] [:alnum:] [:alnum:] [:alnum:] [:alnum:]
Clase visibles [:graph:] [:graph:] [:graph:] [:graph:] [:graph:] [:graph:]
Clase minúsculas [:lower:] [:lower:] [:lower:] [:lower:] [:lower:] [:lower:]
Clase mayúsculas [:upper:] [:upper:] [:upper:] [:upper:] [:upper:] [:upper:]
Clase imprimibles [:print:] [:print:] [:print:] [:print:] [:print:] [:print:]
Clase puntuación [:punct:] [:punct:] [:punct:] [:punct:] [:punct:] [:punct:]
Clase espacios [:blank:], \h [:blank:] [:blank:] [:blank:] [:blank:] [:blank:]
Clase espacios y \n [:space:], \s [:space:], \s [:space:], \s [:space:], \s [:space:], \s [:space:], \s
Clase hexes [:xdigit:] [:xdigit:] [:xdigit:] [:xdigit:] [:xdigit:] [:xdigit:]
Límite de palabra \b \b \b (no hay) \b \b
[_[:alnum:]] \w \w \w \w \w \w
[^_[:alnum:]] (separadores) \W \W \W \W \W \W
Anclas
Inicio ^cadena ^cadena ^cadena ^cadena ^cadena ^cadena
Fin cadena$ cadena$ cadena$ cadena$ cadena$ cadena$
Calificadores
Agrupamiento (j) \(j\) (j) (j) \(j\) (j)
Referencia \1 \1 \1 (no hay) \1 \1
Cuantificadores
Cero o más * * * * * *
Cero o uno ? \? ? ? \? ?
Al menos 1 + \+ + + \+ \1
Rango {m,n} \{m,n\} {m,n} {m,n} \{m,n\} {m,n}
Operadores
Concatenación ab ab ab ab ab ab
Alternancia | \| | | \| |