miércoles, 15 de mayo de 2013

Nice Numbers

Una de las cosas que recientemente he tenido que aprender como la palma de mi mano es este algoritmo. Como parte mis obligaciones actuales, tengo la enmienda de realizar una serie de graficadores que si bien son todo mar de procedimientos complejos, en este apartado tratare de explicar un poco sobre como iniciar el dibujado de cualquier grafica, calculando la escala óptima y no morir en el intento. 

Lo primero a tomar en cuenta son los conceptos básicos que debemos saber.

Max: Representa el numero máximo que puede tener nuestra grafica
Min: Numero mínimo de nuestra grafica
Tick: En español es, marca (por decirlo de alguna forma), las rayitas que tenemos atravesando el eje para mostrar cierto número de unidades en nuestra grafica
#Max. Ticks: Un numero máximo de marcas que Nosotros deseamos existan en el eje, este valor es importante y debemos prestar atención mas adelante.
Eje: Eje Y o X, representa los lados grafica para representar el área de graficacion
Rango: Es la distancia entre 2 valores.


Fig. 1. 

Imaginemos que queremos graficar estos valores [2, 350, 122, 78, 150, 383, 100]; como decimos por aquí, a ojo de buen cubero;  la escala que se debe tomar es del 0 al 400 y hacer incrementos de 100 en 100, esto para el cerebro humano es muy fácil de calcular, pero hablando matemáticamente, requiere de un algoritmo más complejo. 


Fig. 2

En la figura 2, en la primer imagen representa, como ingenuamente la computadora graficaría los valores que le hemos pasado, dando como resultado un error catastrófico, al determinar que no existe el mismo tamaño entre una marca y otra, o bueno!!, visualmente si existe, pero no es lo mismo la distancia entre 2 a 78 que de 78 a 100 o sí?


Lo que queremos calcular es una escala como se muestra en la segunda parte de la imagen, para esto ocuparemos el algoritmo "Nice Numbers". Seamos realistas, este tipo de cosas nadie las memoriza o trae en la cabeza como el algoritmo de la burbuja, o bueno casi nadie que no tenga que ver o esté involucrado con un proyecto de este tipo. 
Antes de pasar al algoritmo identifiquemos algunos datos, del arreglo que queremos graficar.


Min. 2
Max: 383
#Max. Ticks. Este depende del tamaño del área de dibujo, tamaño de letra, tamaño de las etiquetas, etc. etc. ya que ponemos un número mayor al máximo de marcas que puedo dibujar sobre el área de dibujo, estas se podrían encimar y no ser del todo útiles en nuestra grafica.

Ahora sí, pasemos a lo bueno, este es el algoritmo completo:

_____________________________________________________
const ntick =10;                                    //En mi area de dibujo caben maximo 10 marcas.
procedure niceScale(min, max: real);
           nfrac: int;
           d: real;                                      //Tamaño de la marca
           graphmin, graphmax: real;      //Max y Min. despues del algoritmo
           range, x: real;
           begin
                    range =nicenum(max – min, false);
                   d =nicenum(range/(ntick – 1), true);
                   graphmin =floor(min/d)*d;
                   graphmax =ceiling(max/d)*d;
                   nfrac =max( – floor(logl0(d)), 0);     //Numero de digitos fraccionales a mostrar
                   for x =graphmin to graphmax + .5*d step d do
                                 poner la marca en x una etiqueta numeral, mostrando nfrac digitos
                   endloop;
endproc niceScale;

/**
nicenum: funcion para encontrar una numero(“nice number”) aproximadamente igual a x.
Round the number if round = true, take ceiling if round = false.
function nicenum(x: real; round: boolean): real;
           exp: int;                                        //Exponente X
           f: real;                                          //Parte de fraccional de X
           nf: real;                                        //nice number, numero fraccional
           begin
                   exp =floor(logl0(x));
                   f =x/expt(10., exp);             //Siempre entre 1 y 10
                   if round then
                             if f < 1.5 then nf =1.;
                            else if f < 3. then nf =2.;
                            else if f < 7. then nf =5.;
                            else nf =10.;
                   else
                            if f <= 1. then nf =1.;
                           else if <= 2. then nf =2.;
                           else if <= 5. then nf =5.;
                          else nf = 10.;
           return nf*expt(10., exp);
endfunc nicenum;
_____________________________________________________

Por último les dejo una tabla, que se aplique en Excel con diferentes rangos y sus variaciones para ver el comportamiento del algoritmo.



Después de todo me doy cuenta que esas clases de matemáticas, donde veíamos logaritmos, limites y aproximaciones, no solo eran para martirizarnos durante anios, si no que en realidad si tiene un uso.



Concordantly, while your first question may be the most pertinent, 
you may or may not realize it is also the most irrelevant.
The Matrix Architect

No hay comentarios.:

Publicar un comentario