435,639 Members | 2,262 Online + Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,639 IT Pros & Developers. It's quick & easy.

Math.ceil/floor Vs parseInt Vs plus/minus

 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:
Number of iterations
-- Rob Jul 23 '05 #1
6 Replies

 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 type-converts non-string 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 non-integer 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)? 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. i = this.form.num.value; s = new Date(); while ( i-- ) { ( x>0 )? parseInt(x)+1 : parseInt(x)-1; 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 non-zero - !d - is false, adding zero after type-conversion to a number, and when - d - is zero - !d is true, adding 1 following type-conversion. 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. Jul 23 '05 #2

 P: n/a RobG wrote: 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 ) )); } 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. Jul 23 '05 #4

 P: n/a Richard Cornford wrote: RobG wrote: Here's my final version. moveBy is generated by somefunction of the distance between two elements:if ( moveBy ) { setPos( obj, ((moveBy > 0)? ( moveBy+=1 | 0 ) : ( moveBy-=1 | 0 ))); } 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 bit-wise truncates - sweet! -- Rob Jul 23 '05 #5

 P: n/a JRS: In article , dated Fri, 8 Jul 2005 01:13:11, seen in news:comp.lang.javascript, RobG posted :Richard Cornford wrote: RobG wrote: Here's my final version. moveBy is generated by somefunction of the distance between two elements:if ( moveBy ) { setPos( obj, ((moveBy > 0)? ( moveBy+=1 | 0 ) : ( moveBy-=1 | 0 ))); } 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 bit-wise 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 move-calculation. 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 © JL/RC: FAQ of news:comp.lang.javascript jscr maths, dates, sources. TP/BP/Delphi/jscr/&c, FAQ items, links. Jul 23 '05 #6

 P: n/a Dr John Stockton wrote: JRS: In article , dated Fri, 8 Jul 2005 01:13:11, seen in news:comp.lang.javascript, RobG posted :Richard Cornford wrote:RobG wrote:Here's my final version. moveBy is generated by somefunction of the distance between two elements:if ( moveBy ) { setPos( obj, ((moveBy > 0)? ( moveBy+=1 | 0 ) : ( moveBy-=1 | 0 ))); }In looking at this I observe that the value that is determined by theoutcome of the conditional expression is the +/-1, so maybe;-setPos( obj, ((moveBy += ((moveBy > 0)?1:-1)) | 0) )And the outer bit-wise 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 frees-up 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 move-calculation. 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 Jul 23 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion. 