jueves, 28 de abril de 2011

Proyecto: Informatizar un problema matemático de primaria, Divisores (6 de 10)


Estamos en la fase de implementación y, mientras me voy haciendo con Eclipse, vamos a ir comentando un punto delicado : Limitaciones y límites a considerar.
Y es que , hasta aquí, todo era más o menos teórico pero, ahora, llega el momento de crear “la criatura” y, como colación de la pregunta del otro día, pues toca hablar de ciertas cosas.

¿Qué máximo valor podremos descomponer con la certeza de que obtendremos siempre divisores primos?
Sí, si alguien lo pensó, decirle que el número máximo será siempre el cuadrado del máximo primo que tengamos , así si os dije que teníamos los primos hasta el 108 evidentemente podemos admitir para hacer la descomposición factorial hasta, prácticamente, el 1016


Puntos del dibujo 1,2 y 3 !Primer vistazo!

Vamos a ponernos en un caso:
Supongamos que el valor máximo de nuestro fichero era el primo justo anterior a 109 y que, por tanto, admitíamos su cuadrado y, nos dan 2*1016 como valor x inicial para resolver....

El punto 1 lo pasa exitósamente. (Por ahora es natural y mayor que dos)

El punto 2 vemos que 2*1016=217*516 luego, se nos genera un array de longitud 17+16=33. Lo que tampoco supone un problema.

Y ahora llegamos al punto 3, donde había que generar números desde el 0 hasta, en este ejemplo, el 233 -1 y , por cada número, convertirlo a cadena de bits y hacer el condicional y ,si el valor resultante obtenido para ese número no estaba en el Vector solución, incluirlo.

Bueno, vemos que estamos tocando números “mucho grandes” y toca hacer una aclaración... y es que java, en un principio y si no se dice otra cosa, interpretará los números con el tipo básico Integer (int ) que, comprende 31 bits para valores y uno para signo. 
Asi que: !Ojito que corremos riesgo de desbordamiento!



Y hablando de desbordamiento vamos a hilar fino, fino, fino, a continuación:

Alguno me diréis , pero oye que habíamos quedado que el fichero de primos iba a contener los primos hasta 108 más o menos......
No eso no es cierto , en un principio diseñe el programa para que al introducir un numero no decimal y mayor que cero el programa lo asociara a una variable int y por tanto si probais a meterle un número superior a 231 el programa debería de fallar pero, hasta ese número el programa no debe de fallar.
Google : "Optimización"

Claro , y aquí es dónde alguna mente sagaz ubicará la pregunta de: 
-"Pero oye, si yo, por ejemplo, al programa para ver los primos, le introduzco el número 200000000 el programa “casca” y me sale un

Exception in thread “main” java.lang.OutOfMemoryError: Java heap space

,¿Se rompe?"-

Bueno, eso no es que precisamente el programa falle.
Estáis ante un caso de optimización que se da mucho en minería de datos.
Y es que, cuando ejecutais el programa bien en windows con el bat o bien en linux, si no hacéis nada el programa se ejecuta con los parámetros de memoria configurados por defecto en la máquina virtual que lo interpreta.
Y , claro, la pila se llena tanto que desborda la memoria asignada por defecto para la ejecución de dicho programa (de intercambio).
Esta circunstancia es propia , por la teoría de computación, de enunciados cuya resolución genera  "muchos subcálculos a tratar" es dificil explicarlo de un modo "no-técnico" pero, espero,  que el ejemplo os ilustre: 
A más factores primos divisores, muchísmos más subconjuntos a estudiar . De hecho , el número de subconjuntos crece de forma exponencial. 
Otro ejemplo que podréis encontrar, de esto que os comento , es el conocido problema de Viajante  y si queréis más, buscad "Problemas de planificación " o Schelude. 

¿Soluciones? 
 
Pues, como he dicho, es un problema de optimización de recursos.
Debemos saber que, la máquina virtual de java que interpretará el programa está justo encima del sistema operativo. Esto supone que, de la memoria que tenga para gestionar en mi equipo, deberé reservar un minimo para el sistema operativo y el resto puedo reparametrizarla en la maquina o bien en mi programa.
Así pues, vemos que, depediendo de: la memoria que tengamos , del sistema operativo sobre el que se pose la JavaVirtualMachine (JVM, interpretadora, o como la queráis llamar) de los servicios (en windows) o demons (en Linux, asi como el suso de entorno grafico en este último en el mismo), que tengamos habilitados podremos ampliar o no la memoria confiriendole asi mayor capacidad de trabajo (eso si a cambio disminuiremos la velocidad pero, podemos, como estoy diciendo ampliar el rango). Eso si debéis recordar que la paginación y la memoria virtual que requiere un sistema operativo tambien requiere memoria asi que a ver si por ganar en la JVM perdeis en SO y por tanto no habéis hecho nada.


En internet he encontrado la siguiente tabla de Megas mínimos a reservar para los siguientes sistemas operativos que sólo vayan a usar nuestro proceso, ya en futuras entradas la ampliaré , ahora sólo estamos hablando de como construir nuestra “maldita “ aplicación.

Windows XP: dejar 392MB para el SO
Linux: si no ejecutas las X, puedes llegar a dejarle sólo con 64MB para el SO.

Y estos para quien aun los use:
Windows NT: dejar 128MB para el SO
Windows 2000:dejar 256MB para el SO



Vale, vale, seguro que lo habéis pillado y esa "reparametrización" ¿Cómo lo hago?
Puede hacerse o bien en la maquina o bien en la ejecución yo os rcomiendo la segunda pues asi es solo para dicha ejecucion puntual:

Recordad o editad el bat que os deje para los que os daba problemas en windows, contenía la linea:
  • java -jar elnombredelprograma.jar

Se trata de modificar esta línea en el bat en windows o al comandarla en linux tal que, por ejemplo, podria dejar de mi Giga dedicados a la ejecucion 512 Mb:

  • java -Xms512Mb -Xms512Mb -jar elnombredelprograma.jar
Con esto ya he alcanzado el 150000000 sin problemas.

Y se queda la cosa en ir probando.



Bueno y con esto, por hoy.... ya sabéis ….
Por “su puesto” : !Sed buenos!

No hay comentarios: