Universidad de Costa Rica
|
|
Para esta tarea programada usted debe enviarme estos archivos:
Es extraño cómo funcionan los valores infinitos porque el sentido común a veces no concuerda con la realidad. Por ejemplo, es posible demostrar que se puede contar los números racionales positivos al usar un recorrido como el que se muestra en este diagrama:
http://en.wikipedia.org/wiki/File:Diagonal_argument.svg
http://en.wikipedia.org/wiki/Rational_number
Al examinar este diagrama se puede concluir que la cantidad de
números racionales es similar a la de números enteros,
porque es posible contar cada uno de los números racionales
positivos: a primera vista, esto es paradójico. Sin embargo, en
la memoria de un computador no es posible almacenar todos estos valores
porque cada número se presenta como una secuencia finita de bits,
que en el caso del lenguaje Java es de 32 bits para el tipo
(int)
y de 64 bits para el tipo (long)
:
→
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
El recorrido mostrado antes es engorroso de programar, porque
primero sube y luego baja. Es más simple programar el recorrido
por lo mismos números, pero comenzando por el primer
renglón y bajando por la diagonal que cae de derecha a izquierda:
[ 1/1 .. 1/2 2/1 .. 1/3 2/2 3/1 .. 1/4 2/3 3/2 4/1 .. 1/5 2/4 3/3
4/2 5/1 ... ]
. Este orden es el que usted usará para
recorrer los números racionales positivos que se pueden
representar en variable Java de tipo (byte)
, que usan 8
bits y permiten almacenar los números enteros en el rango
[-128 .. 127]
.
El mayor número entero que se puede almacenar en una variable entera de 32 bits es 2,147,483,647 que es el valor 2^31-1 (el exponente es no es 32 porque hay que usar uno de los bits para el signo del número). Esto quiere decir que si se suman 2 valores positivos y el resultado es un número negativo es porque la suma requiere más de 32 bits, como ocurre con estos ejemplos:
public void test_dosAla() { // dosAla(n) == 2^n assertTrue( dosAla(0) == 1 && dosAla(3) == 8 ); // Ok assertTrue( dosAla(30) == 1073741824 ); assertTrue( dosAla(31) == 2*1073741824 ); // Ok assertTrue( dosAla(31) == -2147483648 ); // ?????? [[1]] assertTrue( 2*dosAla(30) == -2147483648 ); // !!!!!! assertFalse( dosAla(30)+dosAla(30) > dosAla(30) ); // ?????? [[2]] }
Al sumar el valor 1,073,741,824 consigo mismo, el resultado 2,147,483,648 sobrepasa en 1 el máximo valor que puede almacenarse en una variable entera: 2,147,483,647. Por eso, en lugar de obtener un resultado positivo, esta multiplicación queda como un número negativo.
Una forma de detectar si el resultado de una suma de 2 valores
positivos ya no cabe en la variable entera es verificar si el resultado
obtenido es un número negativo, como ocurre en el renglón
marcado [[1]]
. Otra es verificar si el resultado de la suma
es menor que los valores originales, como ocurre en el renglón
marcada [[2]]
.
En esta tarea programada usted debe hacer un programa que busque la primera pareja de números que tiene la propiedad de que, al sumarla, produce un resultado incorrecto porque se rebasa el límite de 32 bits para números enteros. Su programa debe probar todas las parejas de números que corresponden a un racional en el orden antes descrito para contar racionales (si lo desea, puede usar el orden de la figura que es un poco más complicado de programar).
Su programa rebase.java
debe usar los métodos de
la clase biblio
para grabar en pantalla las primeras
parejas de números cuyo suma, resta o multiplicación se
sale de 8 bits, pues ese es el tamaño de una variable Java de
tipo (byte)
. Use al técnica descrita en el Lab12.java
para obtener la
cantidad de valores que si programa debe reportar. Además,
reporte primero las sumas, luego las restas y por últimos las
multiplicaciones en renglones aparte que no sobrepasen 80 caracteres.
Debido a que su programa usa el orden que permite contar números
racionales, debe procesar las parejas de valores en ese mismo orden.
/** Contiene rutinas para verificar si las operaciones aritméticas producen o no rebase numérico. */ class biblio { /** Retorna true si la suma a+b si cabe en una variable entera. */ public static boolean addIsSafe(byte a, byte b) { byte res=a; res += b; if (a != res-b) { return false; } return true; } // http://google.com/search?as_qdr=all&num=100&as_q=java+detect+integer+overflow /** Retorna true si la resta a-b si cabe en una variable entera. */ public static boolean subIsSafe(byte a, byte b) { byte res=a; res -= b; if (a != res + b) { return false; } return true; } /** Retorna true si la multiplicación a*b si cabe en una variable entera. */ public static boolean multIsSafe( byte a , byte b ) { byte res=a; res *= b; if (a!=0) if (res/a != b) { return false; } return true; } /** Retorna true si la división a/b si cabe en una variable entera. */ public static boolean divIsSafe( byte a , byte b ) { return true; } }
(byte)
.
¿Qué hacemos? PUNTOS EXTRA: Lo interesante de la tarea es que, para implementarla, no hay que usar multiplicaciones pues al recorrer las parejas de números usando el diagrama de diagonalización que está arriba, se puede generar el resultado de la multiplicación con base en los valores ya calculados.
|
Adolfo Di Mare <adolfo@di-mare.com>.
|