code of the Ninja();

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

Showing posts with label operators. Show all posts
Showing posts with label operators. Show all posts

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.

2012-11-05

Prepare To Be Floored

This post is nothing too special or groundbreaking, but it might be of interest to anyone who is as huge of a nerd as I am.

I noticed long ago that Game Maker automatically rounds numbers and variables when they are used as array indices. So, for example array[3.6] is precisely equivalent to array[4].

I also noticed that the same thing happens when performing binary operations:

is precisely equivalent to . The same principle holds for ^ and |.

is precisely equivalent to . The same principle holds for .

Knowing this is certainly useful; it can rid your code of unnecessary calls to the round() function.

But I got an evil thought - what would happen if I tried bit shifting a number by zero, e.g. or ? Mathematically, a bit shift of zero should leave the number unaffected, but would Game Maker go ahead and round it anyway?

The answer is yes! is equal to 32. Therefore this code:

Has the identical effect as this code:

An interesting quirk; a titbit of trivia. So what?

Well, I suspected that it might be a faster operation than the calling of the round() function, and so I tested this hypothesis. The result?

Bit shifting by zero is twice as fast as using round(). Now, that function is hardly going to break the bank, but if you have code that relies on it heavily this is definitely something to consider with regard to optimisation.

For the same effect you could also with ~1, as in this code:

It also rounds the number much faster than round(), comparable to the speed of the bit shifting method. I just don't like the readability as much; the bit shift method > 0--> looks like it's knocking off digits past zero, which is a reasonable mnemonic for rounding.

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!

(EDIT: The above about flooring and ceiling isn't perfect; be sure to read my correction!)

Okay, so maybe in practice this will make your code more confusing and less readable, but like I said: "huge nerd". =P

2012-03-17

Rogue Operators in GML

I've recently discovered a clutch of "rogue" operators in GML: operators that are fully functional but totally undocumented in the help file. While I wouldn't recommend using any of them (they might make your code less portable), they might be interesting to be aware of.

:=

When first n00bishly using GML, I did what I'm sure a lot of others did: I used the = operator for comparisons, e.g. if (a = b), as well as assignment, e.g. a = b. Turns out this is really bad practice if you ever plan on learning other languages (like, say, javascript), because they treat the two very differently. Assignments in javascript actually return the right-hand value, not true/false; so if you were to say if (a = 0) the conditions would never be true, just as if you'd said if (0). The solution, of course, is to use the comparison operator == for condition testing, e.g. if (a == b), and use = only for assignments.

So where does := come into all this? If GML matched other languages, it should be purely an assignment operator, e.g. a := b and not if (a := b). But since GML is special, it's merely a synonym for =. Yep, you can say if (background_color := c_blue) and it'll do the exact same thing as if (background_color = c_blue) or if (background_color == c_blue) in GML.

Dumb. Like I said, these aren't recommended.

<>

This is just a straight synonym for !=. It returns true if the left-hand and right-hand expressions are not equal.

!<, !>

You would think these were cute alternatives for the and operators: whereas you might say to test if a is less than or equal to b, you could also say to test if a is not greater than b for the identical result. However, you would think wrong, even though there are some places around the net that suggest it's true. In GM 8.0, at least, these do not work; they throw a syntax error if used in code. (Though, oddly, they'll just be ignored if used as part of watchers in debug mode: will just return a no matter the right-hand variable is.)

|=, &=, ^=

Okay, so these are documented in the help, but not in the operators section, and there's also a confusing typo where they're listed (suggesting that one of them is ). But they are very useful if you know them; they're the bitwise brethren to the +=, -=, *=, and /= operators. For example, a |= b is equivalent to a = a|b.