P: n/a

I am writing a script to move an absolutely positioned element on a
page by a factor using style.top & style.left.
The amount to move by is always some fraction, so I was tossing up
between Math.ceil/floor and parseInt +/ 1 to ensure the amount to
move was at least 1 and in the right direction. I made a small test to
see which one is faster and also included simply adding/subtracting 1.
parseInt generally took 50% to 100% longer than Math.ceil/floor, but
adding/subtracting 1 is 30 to 100 times faster (depending on the
browser) than Math.ceil/floor. Naturally I'd like to use that since
it's so much quicker.
So my question is:
Is it safe to set the 'top' or 'left' of an element to some
fractional measurement of pixels?
e.g. is it safe to do:
x = 1.9863098
el.style.left = x + 'px'
or should I be making x an integer first (using parseInt or
Math.ceil/floor)? Here's my test script:
<form action="">
<input type="text" value="1000" name="num">Number of iterations<br>
<textarea name="outCell" rows="10" cols="30">
Click Run it to run it.
</textarea>
<input type="button" value="Run it" onclick="
// x will sometimes be +ve, sometimes ve
var x = (Math.random()0.5)*10;
var i, f, s, t0, t1;
i = this.form.num.value;
s = new Date();
while ( i ) {
( x>0 )? parseInt(x)+1 : parseInt(x)1;
x += x;
}
f = new Date();
t0 = fs;
i = this.form.num.value;
s = new Date();
while ( i ) {
( x>0 )? Math.ceil(x) : Math.floor(x);
x += x;
}
f = new Date();
t1 = fs
i = this.form.num.value;
s = new Date();
while ( i ) {
( x>0 )? x+1 : x1;
x += x;
}
f = new Date();
this.form.outCell.value =
'parseInt: ' + t0 + '\n'
+ 'ceil/floor: ' + t1 + '\n'
+ 'plus/minus: ' + (fs)
;
">
</form>

Rob  
Share this Question
P: n/a

RobG wrote: I am writing a script to move an absolutely positioned element on a page by a factor using style.top & style.left.
The amount to move by is always some fraction, so I was tossing up between Math.ceil/floor and parseInt +/ 1 to ensure the amount to move was at least 1 and in the right direction. I made a small test to see which one is faster and also included simply adding/subtracting 1.
parseInt generally took 50% to 100% longer than Math.ceil/floor,
It would as parseInt typeconverts nonstring arguments into strings
prior to parsing them.
but adding/subtracting 1 is 30 to 100 times faster (depending on the browser)
Irrelevant if you have to do that anyway.
than Math.ceil/floor. Naturally I'd like to use that since it's so much quicker.
Subtraction is no substitute for rounding.
So my question is:
Is it safe to set the 'top' or 'left' of an element to some fractional measurement of pixels?
e.g. is it safe to do:
x = 1.9863098 el.style.left = x + 'px'
No. Many browsers will happily make pixel approximations of noninteger
values (they need to in order to cope with em, %, etc. units), but some
go belly up. It is much safer only to ask for pixel positions in
integers.
or should I be making x an integer first (using parseInt or Math.ceil/floor)?
<snip>
No. If you want to turn a number with a fractional part into an integer
suitable for use in positioning in the quickest way possible use:
x  0
 or:
x >> 0
 as the bitwise operations truncate their operands to 32 bit signed
integer values (except for  >>> , which uses ToUint32 internally
instead of ToInt32). 32 bit signed integers are sufficiently big to cove
all realistic pixel positioning and dimension requirements.
Generally, if you want fast math for pixel positioning work try to use
bitwise operators, particularly at the end of sequences of calculations.
For example, halving a dimension can be done as  ( x >> 1 )  and be
guaranteed to return an integer result (so will not then need to be
floored), so:
((totalWidth  elementWidth) >> 1)
 gives you a guaranteed integer result that is no bigger than half of
the width not taken up by elementWidth, ideal for centring an element in
a space, and without the need for further rounding.
<snip> i = this.form.num.value; s = new Date(); while ( i ) { ( x>0 )? parseInt(x)+1 : parseInt(x)1;
<snip>
It is difficult for me to tell what you are after from this. My
inclination would be to handle distance and direction independently.
Acquiring a +1/1 value for direction and a separate positive value for
distance. That allows the distance to be rounded in a known directions
(ie, truncated with bitwise operators, floored or ceiled) and then
direction applied by multiplication with +1/1 (preserving the integer
nature of the result).
Many expressions can be used to give +1/1 results based on
Math.random(), E.G.:
Math.random()<0.5 ? +1 : 1 // fastest on average, by a
// small margin
(((Math.random()<0.5)&& +1)1)
((Math.random()+0.5)<<1)1
((Math.random()<0.5)<<1)1
So given a positive distance  d  that starts truncated/floored to an
integer, but must be made at least 1, and a direction  v , that will
be either 1 or +1, you might have:
(d + !d) * v
 where if  d  is nonzero  !d  is false, adding zero after
typeconversion to a number, and when  d  is zero  !d is true, adding
1 following typeconversion. Then the dimensions  d ,
truncated/floored and adjusted by one,if needed, only in one direction,
is multiplied by +1 or 1 to give an integer distance in one of two
opposite directions.
Richard.  
P: n/a

Richard Cornford wrote: RobG wrote:
[...] Irrelevant if you have to do that anyway.
The strategy is to emulate ceil/floor, i.e. ensure that +ve numbers are
always 'rounded' up and ve always 'rounded' down. This can be done by
adding 1 to +ve and subtracting 1 from ve and truncating. The trick is
to do the logic for determining +ve/ve, add/subtract and truncate with
the quickest algorithm.
I want numbers like 0.1 to become 1 (add 1 and truncate or use ceil) and
0.1 to become 1 (subtract 1 and truncate or use floor).
It seems simply adding/subtracting and letting the browser truncate when
setting style.left/top is not reliable  small 'jitters' occur randomly
near the end of the movement, different browsers have different
behaviours. I was pretty sure I'd be told to pass integers. than Math.ceil/floor. Naturally I'd like to use that since it's so much quicker.
Subtraction is no substitute for rounding.
In the context described above, it kinda works, but not reliably, so I
guess you're right.
[...] No. Many browsers will happily make pixel approximations of noninteger values (they need to in order to cope with em, %, etc. units), but some go belly up. It is much safer only to ask for pixel positions in integers.
Agreed, and the results are inconsistent across browsers so it's a poor
strategy  unless unpredictable jitters with imprecise movement are
intended. :) or should I be making x an integer first (using parseInt or Math.ceil/floor)?
<snip>
No. If you want to turn a number with a fractional part into an integer suitable for use in positioning in the quickest way possible use:
x  0
 or:
x >> 0
 as the bitwise operations truncate their operands to 32 bit signed integer values (except for  >>> , which uses ToUint32 internally instead of ToInt32). 32 bit signed integers are sufficiently big to cove all realistic pixel positioning and dimension requirements.
Here's my final version. moveBy is generated by some function of the
distance between two elements:
if ( moveBy ) {
setPos( obj, ((moveBy > 0)? ( moveBy+=1  0 ) : ( moveBy=1  0 ) ));
}
It's neatly symmetrical, fast and +ve/ve movement and truncating are
dealt with in one go.
Which is at least as fast as simply adding/subtracting one and is faster
by a factor of about 15 than the equivalent:
setPos( obj, ((moveBy > 0)? Math.ceil(moveBy) : Math.floor(moveBy))); Generally, if you want fast math for pixel positioning work try to use bitwise operators, particularly at the end of sequences of calculations. For example, halving a dimension can be done as  ( x >> 1 )  and be guaranteed to return an integer result (so will not then need to be floored), so:
((totalWidth  elementWidth) >> 1)
 gives you a guaranteed integer result that is no bigger than half of the width not taken up by elementWidth, ideal for centring an element in a space, and without the need for further rounding.
Yes, but I need to account for direction (+ve ve) and would like to
have that done within a single step as above. <snip>
i = this.form.num.value; s = new Date(); while ( i ) { ( x>0 )? parseInt(x)+1 : parseInt(x)1; <snip>
It is difficult for me to tell what you are after from this. My
It's just a test of part of my logic, on its own it's pretty
meaningless. ;p
[...] Many expressions can be used to give +1/1 results based on Math.random(), E.G.:
Math.random()<0.5 ? +1 : 1 // fastest on average, by a // small margin
(((Math.random()<0.5)&& +1)1)
((Math.random()+0.5)<<1)1
((Math.random()<0.5)<<1)1
So given a positive distance  d  that starts truncated/floored to an integer, but must be made at least 1, and a direction  v , that will be either 1 or +1, you might have:
(d + !d) * v
 where if  d  is nonzero  !d  is false, adding zero after typeconversion to a number, and when  d  is zero  !d is true, adding 1 following typeconversion. Then the dimensions  d , truncated/floored and adjusted by one,if needed, only in one direction, is multiplied by +1 or 1 to give an integer distance in one of two opposite directions.
Actually I'm trying to avoid random movement (!) but thanks for the tip,
I'm sure it will come in handy.

Rob  
P: n/a

RobG wrote:
<snip> Here's my final version. moveBy is generated by some function of the distance between two elements:
if ( moveBy ) { setPos( obj, ((moveBy > 0)? ( moveBy+=1  0 ) : ( moveBy=1  0 ) )); }
<snip>
In looking at this I observe that the value that is determined by the
outcome of the conditional expression is the +/1, so maybe;
setPos( obj, ((moveBy += ((moveBy > 0)?1:1))  0) )
Richard.  
P: n/a

Richard Cornford wrote: RobG wrote: <snip>
Here's my final version. moveBy is generated by some function of the distance between two elements:
if ( moveBy ) { setPos( obj, ((moveBy > 0)? ( moveBy+=1  0 ) : ( moveBy=1  0 ) )); }
<snip>
In looking at this I observe that the value that is determined by the outcome of the conditional expression is the +/1, so maybe;
setPos( obj, ((moveBy += ((moveBy > 0)?1:1))  0) )
And the outer bitwise truncates  sweet!

Rob  
P: n/a

JRS: In article <Hq******************@news.optus.net.au>, dated Fri, 8
Jul 2005 01:13:11, seen in news:comp.lang.javascript, RobG
<rg***@iinet.net.auau> posted : Richard Cornford wrote: RobG wrote: <snip>
Here's my final version. moveBy is generated by some function of the distance between two elements:
if ( moveBy ) { setPos( obj, ((moveBy > 0)? ( moveBy+=1  0 ) : ( moveBy=1  0 ) )); }
<snip>
In looking at this I observe that the value that is determined by the outcome of the conditional expression is the +/1, so maybe;
setPos( obj, ((moveBy += ((moveBy > 0)?1:1))  0) )
And the outer bitwise truncates  sweet!
If you are repeatedly moving in the same direction by
function(distance), then the direction should be determined, for speed,
outside the move loop. Possibly, write a function to move +, another to
move , and at the start of each sequence assign one or other to do the
job; but function calls may be slower.
If you are using new Date() to time your moves, you probably need not
care much about the speed of the move calculation code, depending on OS;
unless the OS maintains and serves the date as a day or seconds count,
there's more work in new Date() than there can be in movecalculation.
And, between ticks, one can calculate a lot.
Timing with setTimeout or setInterval would not have those overheads,
but different ones.

© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4 ©
<URL:http://www.jibbering.com/faq/> JL/RC: FAQ of news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/jsindex.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.  
P: n/a

Dr John Stockton wrote: JRS: In article <Hq******************@news.optus.net.au>, dated Fri, 8 Jul 2005 01:13:11, seen in news:comp.lang.javascript, RobG <rg***@iinet.net.auau> posted :
Richard Cornford wrote:
RobG wrote: <snip>
Here's my final version. moveBy is generated by some function of the distance between two elements:
if ( moveBy ) { setPos( obj, ((moveBy > 0)? ( moveBy+=1  0 ) : ( moveBy=1  0 ) )); }
<snip>
In looking at this I observe that the value that is determined by the outcome of the conditional expression is the +/1, so maybe;
setPos( obj, ((moveBy += ((moveBy > 0)?1:1))  0) )
And the outer bitwise truncates  sweet!
If you are repeatedly moving in the same direction by function(distance), then the direction should be determined, for speed, outside the move loop. Possibly, write a function to move +, another to move , and at the start of each sequence assign one or other to do the job; but function calls may be slower.
Thanks, I'll consider that.
The destination can move before it is reached, therefore position and
distance are calculated each time after a move. I am working on
creating objects that learn to move of their own accord  accelerate,
move with a set speed, then decelerate. But they also need to be
updated with where the destination has moved to as they go.
My biggest speed issue is eliminating the use of Math functions. They
are handy to use to get the logic right, but then optimisation is
required  using a function that is 30 times faster freesup quite a
bit of CPU! If you are using new Date() to time your moves, you probably need not care much about the speed of the move calculation code, depending on OS; unless the OS maintains and serves the date as a day or seconds count, there's more work in new Date() than there can be in movecalculation. And, between ticks, one can calculate a lot.
I was using a date object to time sections of code  usually 10,000 or
so loops with multiple runs are required to get meaningful results.
I've also found that when testing a series loops in a single function,
going first is a distinct disadvantage. Timing with setTimeout or setInterval would not have those overheads, but different ones.

Rob   This discussion thread is closed Replies have been disabled for this discussion.   Question stats  viewed: 8144
 replies: 6
 date asked: Jul 23 '05
