contando hacia atras

Vaya, este artículo debería haberlo publicado hace unos días, cuando muchos de vosotros sí que os estábais preparando para la cuenta atrás… de final de año, claro. Espero que me perdonéis, pero estoy un poco griposillo así que no me ha dado instancia a dedicar tiempo a escribir.


Aun así: ¡aprovecho para felicitaros a todos desde aquí y desear que los 0x757B12C00 milisegundos de este 2007 os sean propicios! }:)




El caso es que, continuando con el emocionante tema de los tipos de datos, he pensado en dejaros un pequeño puzzler para empezar el año. Os recuerdo que la idea de los puzzlers es responder a las preguntas sobre el código sin ejecutarlo primero (y si sois capaces ademas de saber qué hace, saber el por qué… ¡son gallifantes extra!)


Al igual que en el problema anterior, podéis publicar la solución en vuestro blog y enlazarla desde un comentario aquí o bien enviarlas directamente como comentario del artículo. En cualquier caso, intentaremos comentar la solución entre todos }:)


Pero basta ya de preámbulos: la idea es que tenemos estos tres pedacitos de código:








pedacito #1
int counter = (int)1e8;
while(counter > 0) {
counter–;
}
Console.WriteLine(“counter: “ + counter);








pedacito #2
float counter = (float)1e8;
while(counter > 0) {
counter–;
}
Console.WriteLine(“counter: “ + counter);








pedacito #3
double counter = (double)1e8;
while(counter > 0) {
counter–;
}
Console.WriteLine(“counter: “ + counter);


¿Sabríais decir cuál será la salida de cada uno de ellos? Y ya puestos: ¿sabríais decir cuál tardará MENOS y cual MÁS en ejecutarse?


NOTA: tal y como estan expresados, estos pedacitos deberían ejecutarse sin problemas en C#, Java, C y C++ (simplemente cambiando la última línea por la llamada a System.out.println, printf o cout << apropiada). ¡Siento no haber podido hacer versiones en otros lenguajes!

12 comentarios en “contando hacia atras”

  1. Que mala fe Ricardo… no podías pillar el 1e7 ??? 🙂 🙂 bueno voy a dejar una pista antes de que nadie se mosquee.
    0 10011001 1 .01111101011110000100000
    0 26 1.4901161

    Unai

  2. Hola Ricardo, antes que nada felicitarte en este nuevo año y desearte lo mejor (sigue adelante).

    Bueno en cuanto al codigo que expones, el que se ejecuta mas rapido es el “pedacito #1”, es decir, que trata tipos de datos enteros “int”. El que mas tarda en ejecutarse seria el tipo de dato “double”.

    Ahh!! me falta el resultado que seria: Es el mismo, es decir el contador se queda igual. Ya que al hacer esto:

    while (counter > 0)
    {
    counter –;
    }
    El resultado seria este: Counter: 0 ya que no esta inicializado.

    Saludos desde Rep. Dom. [;)]

  3. hola,

    varios comentarios:

    1.- joe, qué mal ando! pensando que era “le8” cuando es “1e8” XD

    2.- supongo que se ejecuta más rápidamente el pedacito que maneja datos “int”, aunque si no recuerdo mal, los x86 tienen una unidad especifica para el procesamiento matematico, denominado FUP.

    3.- pequeño comentario aunque supongo que lo sabéis. según Stroustrup, cuando se produce el decremento/incremento de un dato y no se realiza nada más en esa expresión (es decir, como está “counter–“) debe ponerse el operador ‘pre’ (–counter). 😉

    agur!

    PD: y a seguir así con este blog! 😉

  4. Francisco, fíjate en la pista que he dado 🙂 y en que todos los numeros no tienen una representacion exacta en una determinada base, por ejemplo 1/3 no tiene representacion exacta en base 10 pero si en base 3 … y puede producir efectos colaterales como el que esta intentando mostrar Ricardo en este juego.
    saludos
    Unai

  5. Buenas crases!

    Si es que Unai es un tio listo… no le ha hecho falta mucho para ver por donde van los tiros }:)

    Francisco, Alberto… no os quedeis con la duda! Una vez habeis hecho una “hipotesis”… probad a ejecutar, quiza poniendo unos timers… a ver que sale }:)

    (aun es muy pronto para que diga cual es mas rapido y cual mas lento pero… aviso que el mas lento es muchiiiiiiiisimo mas lento que los otros… sabeis por que?)

  6. por cierto, dos cosas que se me olvidaban:

    1) Juan Francisco, no entiendo lo que quieres decir en tu explicacion con “El resultado seria este: Counter: 0 ya que no esta inicializado.” No lo inicializamos en la linea justo antes del while?

    2) Keiko, en tu nota 3) sobre el operador de decremento… tienes toda la razon! En las convenciones que cita Bjarne si es asi, pero es que como de siempre acostumbro a poner el post (p.ej. en bucles) y nunca he usado (en el trabajo) unas “convenciones de codigo” que lo requieran pues… Espero que en este caso no lleve a confusion, de todas formas }:)

    Pero por curiosidad, vosotros que usais? sois de “pre” o de “post”? };D

  7. Buff, por fin lo he sacado. No quiero postear los detalles para que haya gente que siga pensando. Unai, no había entendido tu pista hasta que me he mirado el estandar IEEE 754, pero es muy buena pista. El más rápido el pedazo 1 por ser int (sus operaciones son más rápidas) el segundo en velocidad el pedazo 3, y el pedazo 2 ….

    Saludos

    David

  8. hola,

    Me podéis llamar ‘albertito’ porque seré el más joven de todos, aunque quizás el más grande cuerpo. 😛

    Ricardo, no creo que haga falta que diga si soy de “pre” o de “post”, no? XD
    De todos modos, no te preocupes que no lleva a confusión. Sólo por meter un poco de puntilla al código. 😛

    Ya he probado los códigos con resultados sorprendentes. No me esperaba lo que sucede en el caso 2. Yo he probado el código con Java.

    He realizado las pruebas con FreePascal, compilando con compatibilidad para Delphi (-MDelphi) y los resultados son parecidos, con la diferencia de que tarde más un tipo Extended que un tipo real.

    agur!

    PD: Por si a alguien le motiva probarlo, pongo el código en Pascal:

    program Ejemplo;

    uses
    Dos;

    var
    counter: extended;
    timestamp, timestamp2: real;
    h, m, s, c : Word;

    Begin
    counter := 0;
    timestamp := 0;
    timestamp2 := 0;
    h := 0;
    m := 0;
    s := 0;
    c := 0;

    GetTime(h, m, s, c);
    timestamp := c/100+s+m*60+h*60*60;

    counter := 1e8;
    while counter > 0 do
    counter := counter – 1;

    GetTime(h, m, s, c);
    timestamp2 := c/100+s+m*60+h*60*60;

    writeln(‘counter: ‘, counter);
    writeln(‘difference: ‘, (timestamp2 – timestamp));
    End.

    {
    Si se utiliza el tipo ‘integer’ o el tipo ‘LongInt’ para el dato counter, debeis de llamar al método Trunc en la asignación del valor, es decir, quedaría así:

    counter := Trunc(1e8);
    }

  9. Hola Ricardo.

    Bueno no me fije bien el codigo [:D], pero si esta inicializado, lo probe con Visual C# 2005, y aun estoy sacando mis conclusiones [;)].

    Saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *