el numeros de la bestias y descuentos

21 junio 2008

Que bonita esa cancion de los Maiden... 666, el numero de la bestia. Sin embargo, programanticamente hablando, el 666 es un numero de lo mas normalito (si lo ponemos como 0x29A, 0o1232 o 0b1010011010 no impone el mismo respeto, verdad?)

Pero en programacion si que hay numeros "especiales" que son a la vez enormemente interesantes para los curiosos y terribles para los descuidados. En este articulo vamos a ver un par de puzzlers que espero que nos hagan pensar un par de veces la proxima vez que tengamos que evaluar estos "casos extremos" y de paso nos ayuden a repasar un poquito mas de aritmetica programante.

El primero, hablando de casos extremos, es para examinar unos conceptos basicos sobre matematica. Si tenemos este trocito de codigo que declara distintos valores y operaciones:

float zero = 0.0f;
float one = 1.0f;
float negativeone = -1.0f;

float division1 = zero / one;
float division2 = zero / negativeone;

float infinity1 = one / zero;
float infinity2 = negativeone / zero;

float division0 = zero / zero;

Console.WriteLine(division1 == division2);
Console.WriteLine(infinity1 == infinity2);

Console.WriteLine(infinity1 == infinity1);
Console.WriteLine(infinity2 == infinity2);
Console.WriteLine(division0 == division0);

¿Sabríais decir cuál será la salida que obtendremos al ejecutar?

Y el segundo es un caso de "depuracion pensando" que tiene que ver con numeros especiales tambien. Supongamos que tenemos una serie de productos a los que queremos aplicar un descuento (porque para eso estamos de rebajas de Enero). Tenemos algunos cuyo precio se ha reducido a la mitad, y otros que rebajamos un 10%. Como no nos gusta andar con la calculadora todo el rato nos hemos hecho un programita que aplica los descuentos por nosotros. El trocito de codigo que hace lo que queremos es algo como:

int[] precios = {20, 30, 20};
float[] descuentos = {0.5f, 0.5f, 0.1f};

for(int i = 0; i < style="font-weight: normal; color: blue;" color="#0000e0" face="Courier New" size="11"> int
precioRebajado = (int) (precios[ i ] * (1 - descuentos[ i ]));
int porcentaje = (int) (100 * descuentos[ i ]);
Console.WriteLine("antes: {0} euros... ahora solo {1}!!! (-{2}%)",
precios[ i ], precioRebajado, porcentaje);
}

Sin embargo, al ejecutar nos hemos dado cuenta que la salida no es justo la que esperabamos. ¿Sabríais decir cuál es el error o errores que hemos cometido? ¿Como podemos hacer que nuestro programa funcione correctamente?

NOTAS/Actualizacion: Un par de apuntes sobre el problema de parte de un par de lectores avanzados (ver comentarios) }:)

  • Tal y como menciona Augusto, estos problemas pueden arreglarse usando la clase System.Decimal (o java.math.BigDecimal o el equivalente en cada plataforma). El tipo Decimal es bastante interesante, asi que dejamos aqui la referencia por si alguien es curioso y quiere adivinar por que sirve para este tipo de problemas (y cuales son sus ventajas e inconvenientes)
  • Curiosea que te curiosea, Tio_Luiso nos indica que en el primer trocito de codigo, C# parece que no representa el resultado de 0/-1 como "menos cero" (de acuerdo al estandar IEEE 754). En cuanto pueda informarme sobre esto pongo una actualizacion! }:)
Muchisimas gracias a los dos por tomaros el tiempo de compartir esta informacion! }:D