Por: HernanRivas + 28.01.2008
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;
}
}
}
}
Código :
package
{
public class MultiPointLinearFunction
{
/*
PRIVATE VARIABLES
*/
private var tempArray:Array;
//
private var indexArray:Array;
private var valuesArray:Array;
private var indexes:int;
private var currentFunction:Function;
// Precalculate this values for faster operations
private var globalM:Number;
private var globalB:Number;
private var minX:Number;
private var maxX:Number;
/*
CONSTRUCTOR
*/
public function MultiPointLinearFunction ()
{
tempArray = new Array ();
indexes = 0;
}
/*
METHODS
*/
// Use this function to add new "experimental data"
public function addValue (x:Number, y:Number):void
{
tempArray.push ([x, y]);
indexes++;
currentFunction = bruteForce;
}
// 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 ();
var x1:Number, y1:Number, x2:Number, y2:Number, m:Number, b:Number;
minX = tempArray[0][0];
maxX = tempArray[indexes - 2][0];
for (var i:int = 0; i < indexes - 1; i++)
{
x1 = tempArray[i][0];
y1 = tempArray[i][1];
x2 = tempArray[i + 1][0];
y2 = tempArray[i + 1][1];
m = (y2 - y1) / (x2 - x1);
b = y1 - x1 * m;
indexArray.push (x1);
valuesArray.push (m, b);
}
if (indexes == 0)
{
globalM = globalB = 0;
}
else
{
globalM = valuesArray[0];
globalB = valuesArray[1];
}
// Choose the ideal algorithm
if (indexes <= 2)
{
currentFunction = fastCalculation;
}
else if (indexes <= 8)
{
currentFunction = bruteForce;
}
else
{
currentFunction = binarySearch;
// currentFunction = bruteForce;
}
}
public function getY (x:Number):Number
{
return currentFunction (x);
}
public function toString ():String
{
var str:String = "[object, MultiPointLinearFunction]\ninitialized = " + (indexArray != null).toString () + "\ntotalValues = " + indexes.toString ();
return str;
}
/*
IMPLEMENTATION
*/
private function fastCalculation (x:Number):Number // Used only with up to two elements (saves time by avoiding array access)
{
return globalM * x + globalB;
}
private function binarySearch (x:Number):Number // The fastest version. Yet, there is some place for optimization, poor performance for small Arrays
{
var m:Number, b:Number;
if (x <= minX)
{
m = valuesArray[0];
b = valuesArray[1];
}
else if (x >= maxX)
{
m = valuesArray[(indexes - 1) * 2 - 2];
b = valuesArray[(indexes - 1) * 2 - 1];
}
else
{
var sampleLenght:Number = indexes;
var sampleLenghtInt:int;
var sum:Number = 0;
var midValue:Number = 0;
while (sampleLenght > 2)
{
sampleLenght *= .5;
sampleLenghtInt = int (sampleLenght); // Caching the interger allows faster Array lookups and bitwise operations
midValue = indexArray[int(sampleLenghtInt + sum)];
if (midValue > x)
{
// if (sum > 0) sum -= sampleLenghtInt;
}
else if (midValue < x)
{
sum += sampleLenght;
}
else
{
// The midValue equals our query!
trace ("lucky");
sum = Math.round (sum);
m = valuesArray[sum * 2];
b = valuesArray[sum * 2 + 1];
return m * x + b;
}
}
sum = int (sum);
trace ("sum (i) = " + sum.toString ())
m = valuesArray[sum * 2];
b = valuesArray[sum * 2 + 1];
}
return m * x + b;
}
private function bruteForce (x:Number):Number // The brute force method, reccommended for any lenght between 2 and 8
{
var m:Number, b:Number;
if (x <= minX)
{
m = valuesArray[0];
b = valuesArray[1];
}
else if (x >= maxX)
{
m = valuesArray[(indexes - 1) * 2 - 2];
b = valuesArray[(indexes - 1) * 2 - 1];
}
else
{
for (var i:int = 0; i < indexes - 1; i++)
{
if (indexArray[i + 1] > x)
{
m = valuesArray[i * 2];
b = valuesArray[i * 2 + 1];
trace ("i = " + i)
i = indexes; // End the loop
}
}
}
return m * x + b;
}
// 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;
}
}
}
}
Código :
midValue = indexArray[sampleLenghtInt + sum];
Código :
midValue = indexArray[int (sampleLenghtInt + sum)];