Leer un entero de teclado en C

Sin usar scanf, porque no sirve para leer de teclado.

#include<stdlib.h>
#include<stdio.h>

#define MAX_DIGITS 9
#define BASE 10

static int* BUFFER = NULL;

int* readInt()
{
int i = 0,
j = 0,
base = 1,
factor = 1,
*result,
ch = getchar();
if(BUFFER == NULL){
BUFFER = malloc(MAX_DIGITS * sizeof(int));
}
if(ch == 45){
factor = -1;
ch = getchar();
}
while(i < MAX_DIGITS && ch != 10 && ch != -1 && 48 <= ch && ch <= 57){
BUFFER[i++] = ch;
ch = getchar();
}

if(i == 0 || (ch != 10 && ch != -1)){
while(ch != 10 && ch != -1){
/* consumo lo que haya en el buffer para vaciarlo.*/
ch = getchar();
}
return NULL;
}
/* transformo el string en un entero según la base.*/
result = (int*) malloc(sizeof(int));
*result = 0;
/* De atrás para adelante, multiplicando por la base y sumando.*/
for(j = i – 1; j >= 0; j = j-1){
*result += ( BUFFER[j] – 48 ) * base;
base *= BASE;
}
/* aplico el signo*/
*result *= factor;
return result;
}

Anuncios

Java stack trace como String

A veces se desea obtener un String que tenga el texto que se imprime en el System.err cuando hay una excepción para guardarlo en una base de datos o mostrarlo en una interfaz gráfica.
Se hace así:

private static String getStackTraceAsString(Throwable tw) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(baos);
tw.printStackTrace(printStream);
printStream.flush();
String ss = baos.toString();
printStream.close();
return ss;
}

Cálculo correcto del hashCode en Java

Cuando definimos un objeto y redefinimos el método #equals debemos redefinir el método #hashCode

Definir mal el equals es fatal, pero quiero hablar del método #hashCode. Este método devuelve un número con una propiedad fundamental, si dos objetos son iguales (según #equals) el valor retornado por sus respectivos hashCode debe ser igual. Básicamente esta expresión debe ser siempre verdadera:
(!o1.equals(o2)) || (o1.hashCode() == o2.hashCode())
Esto implica que si dos objetos no son iguales (según #equals) pueden tener o no el mismo valor de hashCode.

Implementar mal el hashCode puede pasar inadvertido pero pasa a ser fatal si se usan esos objetos como claves en un HashMap o si se almacenan en un HashSet.

El problema está en que cuando metemos uno de estos objetos en una de esas colecciones se los almacena en diferentes sectores (llamados buckets) según su valor de hashCode. Luego cuando los queremos recuperar pasando como referencia otra instancia que es igual como su valor de hashCode no coincide lo busca en otro sector y no lo encuentra.

Implementar el hashCode de cualquier manera que cumpla la condición mencionada antes tampoco es suficiente, porque si todos los objetos tienen el mismo valor de hashCode van a ir a parar al mismo sector y el HashSet o el HashMap tendrá la misma estructura y tiempos de respuesta de una lista.

Una forma de quedarnos tranquilos de que el valor de hashCode cumple las propiedades y no transforma los HashMaps en listas es haciendo así el cálculo:

public static int genericHash(int... fieldHashes) {
int result = 17;
for (int hash : fieldHashes) {
result = 37 * result + hash;
}
return result;
}

Y un ejemplo de su uso en un objeto:

public class Persona {
private String tipoDocumento;
private int numeroDocumento;
private int hashCode = 0;

@Override
public int hashCode() {
if (this.hashCode == 0) {
this.hashCode = genericHash(this.tipoDocumento.hashCode(),
this.numeroDocumento);
}
return this.hashCode;
}

@Override
public boolean equals(Object obj) {
return obj instanceof Persona
&& ((Persona) obj).tipoDocumento.equals(this.tipoDocumento)
&& ((Persona) obj).numeroDocumento == this.numeroDocumento;
}
}

Layouts con CSS

Hay 3 cosas que toda página HTML debe tener:

  1. Adaptarse a diferentes tamaños de letra
  2. Adaptarse al tamaño de ventana y resolución que el usuario use
  3. Estar hecha con DIVs y CSS

Para ello hay muchas técnicas y no todas logran buenos resultados. He aquí un ejemplo de layout con CSS que conserva las 3 propiedades.

Consiste de una barra de título o encabezado, una barra de links a la derecha, una barra de links a la derecha (que pueden ser otra cosa como banners o texto). Las barras de links se adaptan al tamaño de la fuente que se quiera.

En el centro el conenido principal que fluqye hasta ocupar todo el espacio que quede libre.

Al final un pie.

Ejemplo de Layout CSS

El HTML

<body>
<div id=”arriba”>
<h1><img src=”http://www.w3.org/Icons/w3c_main”/&gt; Título Principal</h1></div>
<div id=”links”>
<pre>
#links{
float: left;
width: 10em;
margin-right:1em;
background-color:
lightblue;
}
</pre>
<ul>
<li><a href=”link1.html”>Link 1</a></li>
<li><a href=”link1.html”>Vínculo 2</a></li>
<li><a href=”link1.html”>Hipervínculo 3</a></li>
<li><a href=”link1.html”>Hyperlink 4</a></li>
<li><a href=”link1.html”>Enlace 5</a></li>
<li><a href=”link1.html”>Hiperenlace 6</a></li>
</ul>
</div>

<div id=”links2″>
<pre>
#links2{
float: right;
width: 10em;
color: white;
background-color:
red;
}
</pre>
<ul>
<li><a href=”link1.html”>Link 1</a></li>
<li><a href=”link1.html”>Vínculo 2</a></li>
<li><a href=”link1.html”>Hipervínculo 3</a></li>
<li><a href=”link1.html”>Hyperlink 4</a></li>
<li><a href=”link1.html”>Enlace 5</a></li>
<li><a href=”link1.html”>Hiperenlace 6</a></li>
</ul>
</div>

<div id=”content”>
<pre>
#content{
padding-left: 1em;
background-color: snow;
margin-left: 10.2em;
margin-right: 10.2em;
padding-left: 1em;
padding-right: 1em;
}
</pre>
</div>

<div id=”pie”>
<p>
#pie{background-color: yellow;border-style:dotted;border-color: lightgray;border-width:2px;}
</p>
</div>

</body>

El CSS

body{
font-size: 100%;
background-color: snow;
}

#links2{
float: right;
width: 10em;
background-color: orange;
}

#links{
float: left;
width: 10em;
margin-right:1em;
background-color: lightblue;
}
#content{
padding-left: 1em;
background-color: snow;
margin-left: 10.2em;
margin-right: 10.2em;
padding-left: 1em;
padding-right: 1em;
}
img{margin-right:1em;}

#pie{
background-color: yellow;
border-style:dotted;
border-color: lightgray;
border-width:2px;
}

Java puede ser mucho más rápido que C

Tengo un programa para calcular hashes hecho en C llamado HashCalc que usa la biblioteca QuickHash que está escrita en C.

Para calcular algunos hashes de un archivo de 126.664.704 bytes tardó 4 minutos.

Un programa similar jHashCalc escrito 100% en Java y ejecutado usando la JVM HotSpot 6.0 tardó 2 minutos 20 segundos, casi la mitad.

Sólo calculé los algoritmos de hash que ambos soportan. Además le di la ventaja al programa en C de no usar el parámetro -server en la invocación a Java, simplemente hice doble click en el archivo jar.

Para colmo la biblioteca de hashes que está usando el programa hecho en Java es más lenta para MD5, SHA1, SHA-256 y SHA-512 que la biblioteca estándar Java como puede verse en los gráficos que publiqué en una entrada anterior.

jHashCalc HashCalc

Actualización: Hashero calcula los hashes el paralelo y es mucho más rápido.

Algoritmos de Hash: Java vs. GNU

La implementación de Java de SUN provee implementaciones para varios algoritmos de hash como MD5, SHA1, SH?A-256 y SHA-512.

La biblioteca GNU crypto también los provee. Me puse a probar cuál implementación es más rápida.

Datos de la prueba:

  • OS: Windows XP Profesional SP2
  • Java: Java HotSpot(TM) Server VM (build 1.6.0-b105, mixed mode)
  • Parámetros: -Xms128m -Xmx128m
  • Memoria: 512 MB
  • Tamaño del archivo: 126.664.704 bytes

Probé con varios tamaños de bloque para leer. Los tiempos están en milisegundos. Siempre la última fila es la más rápida y en ese caso siempre Java es más rápido. El % de incremento es de GNU contra Java.

Algoritmo (Tamaño Bloque de lectura) Java GNU Incr. %
MD5 (1M) 1985 2281 14,91%
MD5 (4k) 2188 1922 -12,16%
MD5 (128K) 1906 1984 4,09%
MD5 (256K) 1875 1953 4,16%
MD5 (64K) 1875 1875 0,00%
MD5 (512K) 1844 1938 5,10%
MD5 (8k) 1328 1406 5,87%
MD5 (32K) 1250 1266 1,28%
MD5 (16K) 1250 1438 15,04%
Algoritmo (Tamaño Bloque de lectura) Java GNU Incr. %
SHA1 (1M) 3578 3531 -1,31%
SHA1 (4k) 3328 3719 11,75%
SHA1 (128K) 3297 3578 8,52%
SHA1 (512K) 3296 3547 7,62%
SHA1 (256K) 3282 3593 9,48%
SHA1 (64K) 3219 3500 8,73%
SHA1 (8k) 2891 3250 12,42%
SHA1 (32K) 2703 3015 11,54%
SHA1 (16K) 2656 2937 10,58%
Algoritmo (Tamaño Bloque de lectura) Java GNU Incr. %
SHA-256 (256K) 4688 4687 -0,02%
SHA-256 (128K) 4688 4671 -0,36%
SHA-256 (512K) 4672 4656 -0,34%
SHA-256 (4k) 4641 4656 0,32%
SHA-256 (64K) 4625 4625 0,00%
SHA-256 (1M) 4672 4609 -1,35%
SHA-256 (8k) 4390 4485 2,16%
SHA-256 (32K) 4063 4062 -0,02%
SHA-256 (16K) 4000 4016 0,40%
Algoritmo (Tamaño Bloque de lectura) Java GNU Incr. %
SHA-512 (8k) 17343 19750 13,88%
SHA-512 (4k) 18031 17250 -4,33%
SHA-512 (256K) 15578 16047 3,01%
SHA-512 (128K) 15563 16031 3,01%
SHA-512 (512K) 15422 17828 15,60%
SHA-512 (1M) 15407 15984 3,75%
SHA-512 (64K) 15375 15985 3,97%
SHA-512 (16K) 14906 16047 7,65%
SHA-512 (32K) 14844 15672 5,58%

Voy a probar lo mismo el otras plataformas a ver qué resultados obtengo.

Aquí puse unos gráficos para mostrar esos mismos números.