Thursday, September 28, 2006

Running with a Number ...

I think this post is only for basic JS developers and shows how a simple function or a simple operation should be wrote in different ways.
In this specific case, I would talk about logic used for a single function while I was optimizing bytefx.

The problem
I've two numbers, x and y, I need to change x, adding or removing a "speed" value, while x is not equal to y.

This simple problem has a lot of solutions. This is probably the simplest one:

function xRun2y(x, y, speed) {
// check wich number is greater than other one
if(x < y) {

// ok, x is less than y ... then add speed
x += speed;

// x can't be greater than y ...
// x can be only less than y ... or equal
if(x > y)
x = y; // stop run
}

// other case, x is greater than y
else if(x > y) {

// well, in this case we remove speed from x
x -= speed;

// but x can't be lower than y ... then ...
if(x < y)
x = y;
}

// we don't need to care about x == y
// just return x
return x;
};

As you can see by yourself, this simple function could create a range of numbers from Nstart to Nend.
This is an example:

// from 10 to 0
var start = 10, end = 0, speed = 1,
arr = [];
while(start !== end) {
start = xRun2y(start, end, speed);
arr.push(start);
};
alert(arr); // 9,8,7,6,5,4,3,2,1,0

// from 0 to 10
var start = 0, end = 10, speed = 1,
arr = [];
while(start !== end) {
start = xRun2y(start, end, speed);
arr.push(start);
};
alert(arr); // 1,2,3,4,5,6,7,8,9,10

These operations should be usefull to move an element, to change some value from a startPoint to endPoint ... but, as i've said, there are different ways to do that.

This way is, for me, a better way to write the same function.

function xRun2y(x, y, speed) {

// check wich number is greater than other one
if(x < y)

// with a ternary operator we can do everything inline
x = x + speed > y ? y : x + speed;

// other case, x is greater than y
else if(x > y)

// well, in this case we remove speed from x
x = x - speed < y ? y : x - speed;

return x;
};

Simple ? Clear ? ... I like this way as I like ternary operator, it's a must to write compact but efficient code.
However, look at this last function ... don't You see something strange ?
If and else if do exactly same operations ... only plus sign and greater than are diferent.
How we could create these similar operations in a single line ?
Using eval, sure !

function xRun2y(x, y, speed) {
var temp = x < y ? ["+", ">"] : ["-", "<"];
return eval("x".concat(temp[0], "speed", temp[1], "y?y:x", temp[0], "speed")); };

Yess !!! ... seems perfect ? ... or seems the evil ? Let me explain that :)

function xRun2y(x, y, speed) {

// we need to create dedicated ternary operation
var temp = x < y ?

// if x is lower than y we need to add speed
// and verify that x + speed is not greater than y
["+", ">"] :

// in other case we need to remove speed from x
// and check if x is not lower than y
["-", "<"];

// if x is lower than y this string is:
// x + speed > y ? y : x + speed
// else if x is greater than y ...
// x - speed < y ? y : x - speed
return eval("x " + temp[0] + " speed " + temp[1] + " y ? y : x " + temp[0] + " speed"); };

... simple ? cool ? ... no, it's not cool !
Eval in this case isn't absolutely dangerous or a problem while ternary operator is.
The answer is simple, we have reduced code size with a simple and fast function but we do everytime two operations.
These are x + speed or x - speed in both cases duplicated.
It's true, a simple addiction shouldn't be a problem for code execution, but if there's a way to use a better function, why we shouldn't use that ?

function xRun2y(x, y, speed) {

if(x < y)
// we need minimum value because
// if x + speed is greater than y
// we want y
x = Math.min(x + speed, y);

else if(x > y)
// we need maximum value because
// if x - speed is lower than y
// we want y
x = Math.max(x - speed, y);

return x;
};

Final solution
We don't care about case x == y but an operation like this one Math.min(1,1) returns 1 and not an error than why we couldn't use ternary operator ?

function xRun2y(x, y, speed) {
return x < y ? Math.min(x + speed, y) : Math.max(x - speed, y);
};

Do you think this is the best way to run from a Number to another ? I think so :)

No comments:

Post a Comment