My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

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 :)

17 comments:

Anonymous said...

hi Andrea,
i like the way you code,this function is absolutely useful!

p.s. I think this line
var temp = x <>"] : ["-", "<"];
should be
var temp = x < y ? ["+", ">"] : ["-", "<"];["+", ">"]

Andrea Giammarchi said...

oops ... modified, thank you :)

kentaromiura said...

you just follow one of the first rules for javascript optimization:

"Use built-in functions whenever possible (like the Math object), because these are generally faster than custom replacements. For critical inner loops, measure your changes because performance can vary among different browsers."

source of citation

Andrea Giammarchi said...

come on kenta :)

... I think this post is only for basic JS developers ...

... he he ... this post is "just for fun" but not every "young" js developer think over a single function more than 5 minutes ... then as you said, if you can, if you have more time, try to optimize your code, starting from these simple problems :)

Yaroslaff "Inviz" Fedin said...

Hey, Andrea.

I think you'll find it funny, 3 bytes less :D It's not any better - there are more operations to execute, but just a bit shorter:

function xRun2y2(x, y, speed) {
return Math[x < y ? "min" : "max"](x + --speed + (x < y), y);
};

Do you think it could be shortened more? :D

Andrea Giammarchi said...

there are more operations to execute ... and there is an impossible sintax to debug ... no yaroslaff ... absolutely this is not what I mean when I talk about optimizzations ...

kentaromiura said...

...come on kenta :)...

you misurestanding my previous comment, what I try to say is :
"Nice job, Nick! ;)"

Yaroslaff "Inviz" Fedin said...

Dude, Of course I didnt mean this as a serious variant. word "funny" means it :-)

I just felt like a challenge to find if there is could be a shorter syntax, no practical usage.

Andrea Giammarchi said...

Sorry Yaroslaff, I've deleted your reply that was a cool solution:

return Math[x < y ? "min" : "max"](x + --speed, y);

Andrea Giammarchi said...

your reply that was a cool solution:
forget this reply because I didn't test wrong Yaroslaff "Inviz" Fedin solution ...

1 - it's wrong because doesn't work with float speed values

2 - it's wrong because my example creates an infinite loop with Inviz method ...

Then my last function is the final solution, bye.

lupign said...

Hello,
I'm probably less than a basic JS developers, but I have a lot appreciated this post!

abozhilov said...

Yet another buggy code :~)
This is classical Arithmetic progression. But you. You changes :))))
What's happen if your magic var speed, defined with 0 :)))
You are guru :)))
http://style-bg.org/testuser/Translation.html

Andrea Giammarchi said...

Thanks to read my blog until september 2006 to find something wrong, I hope you learned something in 3 years of posts.

Regards

abozhilov said...

Andrea, look. I don't like hate... You are good javascript programmer, but you have very very high spirits. This is not good for you, and your code. I thing, one man ever learn from another. And i hope, and i very kind if learn something else from you.
My concept is: Ever ever before write something code, man who write this code, must be thinking.

Sometime when my english is better, i told you. I will happy if conversation with you.

With respect and please delete that from http://twitter.com. I don't need from unduly popularity ;)

Andrea Giammarchi said...

Ever ever before write something code, man who write this code, must be thinking.

Agree, and that is the reason you started in a bad way, without thinking, and you'll go on forever, until the day you'll think before you'll write a comment which aim is to blame somebody else code.

Regards

abozhilov said...

Hm you are amazing.... Why, when i'm not thinking bugs in your code, not in my :~) Please stop this. Ugly dispute. I don't want talk with one fool man, who think is best ever JavaScript developer...
After previous post and this. We discovered, your code haves very big bugs. That bugs is harmful for user browser... That's enough.

You, don't guarantee anything? And i guarantee never use your code. Because i know, this code don't guarantee anything. Don't guarantee my job! Don't guarantee my calm sleep!

Andrea Giammarchi said...

You can stop surf this blog right now, nobody stop you man.

Keep behaving like this and good like with your skills, right?

You are still commenting 3 years old post. Good luck with your life code a part, seriously! Go on, until I'll stop to publish your comments so you'll have something to truly blame about.

Regards

P.S. do you really think I gonn aremove that stuff from twitter? That's you man, right now, that's you! Good stuff!!!