Trabajo, trabajo. Mucho tiempo alejado de estos foros. Pero ya vienen más experimentos de física, vehículos derrapando, y cosas por el estilo. Si no surge ningún contratiempo esta semana o la próxima voy a estar posteando el primero (si, genero expectativa porque puedo mwhahaha).
En este caso, una clase que escribí para un posible juego de carreras (obviamente tiene otros usos) luego de ver un libro de física.
Lo que vi fue un gráfico que representaba el torque (ver artículo en la Wikipedia) de un motor en función de las rpm. Algo muy similar a lo que se ve en ésta imagen (una coincidencia, que la primer imagen de Google sea de un Porsche, ya que en el libro el ejemplo era de un vehículo de la misma marca).
Pero el tema automovilístico no nos interesa por el momento (quizá en un futuro?). Lo que importa es ver como la curva de torque está formada por distintos datos experimentales que la convierten en una serie de funciones lineales, que tienen por ecuación y = ax + b. Nuestra clase va a representar una tabla de valores que nos va a permitir calcular el valor (aproximado) de, por ejemplo, el torque a determinadas rpm. Para ello, suponemos que dos puntos contiguos que hemos añadido a la lista (con la función addData), hay una línea recta, y así podremos inferir los valores intermedios. Esto lo podemos ver en éste gráfico, donde a partir de una serie de puntos generamos los segmentos que los unen, y sacamos a partir de ellas los valores de la función:
Click para generar un nuevo gráfico
Código :
package { public class MultiPointLinearFunction { /* PRIVATE VARIABLES */ private var tempArray:Array; private var indexArray:Array; private var valuesArray:Array; private var lenght:int; /* CONSTRUCTOR */ public function MultiPointLinearFunction () { tempArray = new Array (); lenght = 0; } /* METHODS */ // Use this function to add new "experimental data" public function addValue (x:Number, y:Number):void { tempArray.push ([x, y]); lenght++; } // This function generates new arrays for faster calculations the process isn't very fast so it has to be used wiselly // Also it is neccessary to execute the function at least once before getting y coordinates public function generateTable ():void { tempArray.sort (multiSort); indexArray = new Array (); valuesArray = new Array (); for (var i:int = 0; i < lenght; i++) { indexArray.push (tempArray[i][0]); valuesArray.push (tempArray[i][1]); } } public function getY (x:Number):Number { var maxIndex:int; var minIndex:int; var rx:Number; // The closest x coordinate greater (rightX simplified as rx) than the provided x value var lx:Number; // The closest x coordinate lesser (leftX simplified as lx) than the provided x value var ry:Number; // The y value corresponding to the aforementioned rx var ly:Number; // The y value corresponding to the aforementioned lx for (var i:int = 0; i < lenght; i++) { if (indexArray[i] > x) { if (i == 0) { maxIndex = 1; minIndex = 0; rx = indexArray[maxIndex]; lx = indexArray[minIndex]; ry = valuesArray[maxIndex]; ly = valuesArray[minIndex]; return ((ry - ly) / (rx - lx)) * (x - lx) + ly; } else { maxIndex = i; minIndex = i - 1; rx = indexArray[maxIndex]; lx = indexArray[minIndex]; ry = valuesArray[maxIndex]; ly = valuesArray[minIndex]; return ((ry - ly) / (rx - lx)) * (x - lx) + ly; } } } maxIndex = lenght - 1; minIndex = lenght - 2; rx = indexArray[maxIndex]; lx = indexArray[minIndex]; ry = valuesArray[maxIndex]; ly = valuesArray[minIndex]; return ((ry - ly) / (rx - lx)) * (x - lx) + ly; } public function toString ():String { var str:String = "[object, MultiPointLinearFunction]\ninitialized = " + (indexArray != null).toString () + "\ntotalValues = " + lenght.toString (); return str; } /* IMPLEMENTATION */ // Sorts the Array according to the first element of the nested Arrays private function multiSort (a:Array, b:Array):int { var xa:Number = a[0]; var xb:Number = b[0]; if (xa > xb) { return 1; } else if (xa < xb) { return -1; } else { return 0; } } } }
La función no es muy complicada, lo que hace es detectar entre qué "valores experimentales" se halla el x dado y calcular su valor de acuerdo a la función lineal que describen.
El único problema (tengo pensado postear la versión v.2 en los próximos días, así que manténganse atentos a los comentarios) es que usamos fuerza bruta
Lo ideal sería que en lugar de revisar los índices del Array uno por uno, tomaramos el del medio ( array[int (array.lenght / 2)] ) para ver en qué mitad debería estar nuestro valor. Seguir partiendo el Array en 2 para encontrar entre qué 2 números se halla nuestro valor.
Puede sonar excesivamente complicado, pero ahorra muchísimo tiempo al CPU.
Por ejemplo, con 1024 valores, el peor caso usando fuerza bruta nos obliga a revisar 1023 elementos inútilmente, usar el método de dividir por 2 requiere sólo 10 (porque 2^10 = 1024 si esto no resulta obvio, no se preocupen, o voy a explicar cuando termine el código )
Otra mejora que tengo planeada es precalcular b y m para cada par de valores (si no saben de qué hablo, no importa, también lo voy a explicar en el futuro), aprovechando que ya uso una etapa donde precalculo un par de cosas para acceder más rápido, a la información (
Pero creo que por el momento, con el ejemplo anterior alcanza y si lo necesitan urgente, no creo que les cueste agregar las 2 cosas que comenté antes.
¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por HernanRivas el 30 de Enero de 2008
Una pequeña explicación antes:
La búsqueda binaria consiste en tomar una lista de n valores ordenados y encontrar el índice de uno de ellos. Esto se podría hacer por fuerza bruta (como en mi primer ejemplo), pero la búsqueda binaria es más rápida. Básicamente partimos el Array en 2 y nos fijamos en qué mitad está nuestro valor (por eso es esencial que esté ordenado). Continuamos con esta técnica hasta encontrar el valor que buscamos.
Los valores m y b de una función lineal son su pendiente y su ordenada al origen, respectivamente. Para simplificar, m es la velocidad a la que cambia el valor de y respecto a x y b es el valor que tiene la función en x = 0.
Código :
Por Zah el 30 de Enero de 2008
Glad to see you again!
Por Freddie el 30 de Enero de 2008
Por penHolder el 30 de Enero de 2008
Por gustavogarzon el 31 de Enero de 2008
Por HernanRivas el 01 de Febrero de 2008
Click para generar un nuevo gráfico
Es interesante cómo calcula también los valores fuera de los límites.
Pero armando el ejemplo, encontré un error. Hay que reemplazar esta línea:
Código :
Por esta otra:
Código :
Por Zah el 02 de Febrero de 2008
Por karen garcia el 04 de Marzo de 2008
Por estella el 22 de Mayo de 2008
Por noe!! el 06 de Diciembre de 2009
Por noe!! el 06 de Diciembre de 2009