code of the Ninja();

// in search of swift, efficient, and invisible code

2012-11-24

Prepare To Be Floored (Correction)

This is a correction of a mistake in my last post.

The last section said this:

This is all very well and good for rounding, but what about flooring or ceiling a number? This trick always rounds up with a fractional part of 0.5 or above, and rounds down below that. In Game Maker, you can use the floor() function to always round down, and the ceil() function to always round up.

You're in luck, because you can do code like this:

These will still be very nearly twice as fast as their function equivalents!

The trouble is that only works if your number actually has a fractional part. If you try to floor or ceil an integer that way, you'll get the integer -1 and the integer +1, respectively.

I can still pull my fat out of the fire, though. Instead of using 0.5 as the value to be subtracted (for flooring) or added (for ceiling), you can use a constant that's just ever so slightly less than 0.5, such as:

Just set this up as a constant (call it something like MATH_CEIL) and then make a second constant that's the negative of it (e.g. MATH_FLOOR = -MATH_CEIL). Then you can do:

And everything I said still holds. You'll still get the job done twice as fast as using the function equivalents. (The use of constants doesn't slow it down at all.)

I suppose you might still technically run into a problem if you're using numbers that require a precision greater than power(2,-43), but for most purposes that'll never happen. Again, this is merely a trick to be used in code that requires optimisation at all costs, not everywhere in your program.

2 comments:

  1. Well isn't that just the weirdest thing. I double checked to be sure, and used your value of 32, and sure enough you are correct.

    However, I was positive I got the effect before, so I tested with 1 -- and bizarrely it happens when you use 1 but apparently no other numbers.

    So 32+0.5>>0 is 32, but 1+0.5>>0 is 2.

    Why, Mark Overmars, why?

    ReplyDelete
    Replies
    1. It turns out that this doesn't just happen when bit-shifting by 0, but also when using the built-in round() function.

      This is actually intended behaviour, because Game Maker's rounding algorithm is based on one used in statistics, which rounds numbers whose fractional part is exactly 0.5 up or down depending on whether the number before the decimal point is odd or even.

      This is great for avoiding bias in data sets, but bad in a lot of games programming situations; for example, rounding a value that increases by 0.5 every step will result in a sequence where even numbers are three times more numerous than odd ones!

      This has apparently been changed in Game Maker Studio 2, but for those retro enthusiasts still hobby programming in Game Maker 8, I'd suggest using floor(n + 0.5) instead of round(n) to get the result you're probably expecting.

      Delete