Core AS3: Modulus

I’ve decided to start a little series of articles on the blog called Core AS3 that will deal with small, simple snippets of code (<5 lines) that are very useful but not particularly self-evident. I often encounter questions at workshops and conferences about small coding constructs that I take for granted, and it occurred to me it might be helpful to document and share them with the community.

The first article in this series is about modulus. Modulus, which is represented by the percent sign % simply returns the remainder of a division operation. For example, 21 modulus 5 is 1. This is handy for a lot of different things, but I’m going to focus on four of them: alternation, frequency, wrapping, and two dimensional data sets.

All code will be simplified to focus on the concept at hand. Most of it should also be applicable to any similar language (ActionScript 2, ActionScript 3, JavaScript, etc)

Using Modulus for Alternation
This is perhaps the simplest use case. Say you want to alternate row colors in a list – you can simply make the color of each row a function of the modulus value of the rowcount:

if (rowIndex % 2 == 0) {
rowColor = 0xFFFFFF;
} else {
rowColor = 0xCCCCCC;
}

Using Modulus to Vary Frequency
Similar to the above, you can use modulus to vary the frequency of execution of a block of code within a repeating block. For example:

// tick runs every frame:
function tick() {
trace("I run every frame");
if (++frameCount % 10 == 0) {
trace("I run every 10 frames");
}
}

Using Modulus to Wrap Values
You can also modulus to wrap a value within a specified range. For example, if you want to a sprite to move right, but wrap back to the left side of the screen when it hits the right side, you could use this:

sprite.x = (sprite.x + 5) % stage.stageWidth;

It’s easy to modify this to work with negative x motion as well, you simply have to ensure the value is always positive:

sprite.x = (sprite.x + velX + stage. stageWidth) % stage. stageWidth;

Using Modulus to Flatten Two Dimensional Data Sets
Creating two dimensional arrays by nesting arrays is very inefficient. It’s much better to flatten the 2D data into a single array. You can do this easily using modulus and simple multiplication:

// iterate the array:
function scanArray() {
for (var i=0; i<flatArray.length; i++) {
var x = i%columns;
var y = Math.floor(i/columns);
trace("value at x="+x+",y="+y+" is '"+flatArray[i]+"'");
}
}
// access individual values:
function getValueAt(x,y) {
return flatArray[x+y*columns];
}

Based on some feedback in the comments below, I did some additional testing, and found that this technique, while novel, is actually slower than using nested arrays in the latest player 9. Based on this, my recommendations would be to use flattened arrays for performance critical routines in AS1/2, but stick with the more readable and performant nested approach for everything else.

Have other handy uses for modulus? Post them in the comments below.

Grant Skinner

The "g" in gskinner. Also the "skinner".

@gskinner

42 Comments

  1. Nice! I can’t wait for all the others. I think this will be a fun series.

  2. Very cool. I’ve used it for alternation and frequency but never thought to use it for the other two examples you provided. Thanks and look forward to the series.

  3. The two-dimensional data set implementation also functions as grid-layout code. Code is untested, but you get the idea.

    function drawGrid() {

    for (var i=0; i < items; i++) {

    var sprite = new MySprite();

    sprite.x = (i%columns) * spriteWidth;

    sprite.y = Math.floor(i/columns) * spriteHeight;

    }

    }

  4. Thanks for sharing.

    Great way to open your series of code snippets.

  5. make a mc to walk :

    var t=0

    this.onEnterFrame=function () {

    t++

    ball._x+=t%12

    }

  6. That looks great. These are great snippets and explanations. Modulus makes more sense to me now, I can’t wait to use it! Also looking forward to the rest of the series, thanks!

  7. Modulus is one of the only cool tricks I remember from my stint in computer science… Extremely useful, though. I hadn’t though of the stage application.

  8. Maybe irrelevant, but you should never use

    if (rowIndex % 2 == 0)

    as

    if (rowIndex & 1 == 0)

    is way faster.

  9. Gskinner’s New Article Series

    Grant Skinner, gskinner.com, is a well known flash/actionscript guru whose notables include gProject (acquired by Adobe), and gallery incomplet. His blog is a great resource for anyone interesting in flash development.

    Fortunately for all of us, he…

  10. Thanks Grant! This is going to be a great series I’m sure!

  11. Gonzalo León May 23, 2008 at 12:37pm

    Danny Miller: boy! that’s the first practical example i’ve ever seen of bitwise operations! cool!

  12. Danny,

    right, that is faster for straight alternation. It’s worth noting though that it is easier to extend the modulus solution to multiple colors:

    rowColor = rowColorsArray[rowIndex % numColors];

    Gonzalo,

    definitely more useful bitwise stuff coming in a future installment (probably the next one).

  13. Hey Grant! I was just thinking that using stage.width instead of stage.stageWidth can confuse people with testing. Took me 15 minutes to figure out back in the days when as3 was young.

    Looking forward to more posts!

  14. laz9,

    I agree completely. Updated the article to reflect.

  15. why would you possible want to flatten an array? why is it always the flash community with such dumb ideas?

    why can’t you just use a product like everybody else?

    and if you do some lowlevel hacking..please read first some literature on compiler.

    man…

  16. robs,

    I have to admit, I have no real idea what you’re talking about, but I’m always happy to learn. If you have a more efficient way of representing a 2D table of data in ActionScript, I’m sure we’d all love to hear it.

    I’d hardly consider the use of the modulus operator to be “lowlevel [sic] hacking”, but your opinion may vary. Regardless, I think I have a reasonable understanding of the Flash compiler, but again, I’d be happy to have you enlighten me.

  17. I had never considered using the mod for screenwrapping, that is great ! thanks

  18. Grant,

    appreciated your ideas. I liked the way using modulus and process 2D-arrays; I used to create Object to represent two dimensional arrays, but your way is great.

    I’d like to comment about robs’ post. Hey robs, go back to your compiler course, and never come back. Because you studied compilers, it makes you a programmer? You are an idiot.

  19. I don’t think I understand the flat-array thing. Maybe if you showed how to populate the array (or flatten one that was first made as a nested array) then I might understand.

    It’s funny because a student solved a nested array problem this way a long time ago and I thought he was totally whacked–though, since it worked, I couldn’t really say there was anything wrong.

    By the way, if you’re talking efficiency, it’d pay to point out the “rule of threes”… namely that you should store that array’s length in a local variable instead of calculate it on every loop. I know it’s a nitpick but I’ll bet that will improve performance more than avoiding a nested array. Or, is the reason for avoiding the nested array RAM usage?

    Anyway, I like the idea of such focused topics!

  20. Very useful stuff. Thank you! Please highlight snippets that run pretty fast. I see the Flash world split into designer and developers. Now with as3, there is a lot of pressure, because they have to start from scratch, plus there is huge difference between what a flash designer also becomes a developer can achieve code wise, compared to as3 developers that migrated from java or had previous programming experience. I started to learn programming with flash, so I still lack a lot of the programming concepts developers have ( compared to designers) so I stick to the manual and write code as close to ‘the book’ as possible to avoid errors. ( Some of those error codes and explanations don’t help designers very much ). Sticking to the manual isn’t always the fastest way. Please let us know when we can use some of these snippets in favor of more beginner-level code to gain some speed in flash projects.

  21. Juan Pablo Califano May 24, 2008 at 5:41pm

    Grant,

    Maybe this is a bit off-topic since your article is about modulus, but another way to deal with flat arrays is using nested loops.

    I think it adds just a little bit nore overhead than your flat-loop implementation. One more variable for the inner counter and some extra increments and less than comparisons. In a 10 x 10 data set, your approach makes 100 increments and 100 comparisions, while the nested alternative performs, if my math’s not wrong, 110 increments and 110 comparisons (10 for each outer loop, plus 10 for each inner loop, which is run 10 times, so it’s 10 + 10 * 10 = 110).

    In code:

    var flatArray:Array = [“r_0_c_0″,”r_0_c_1″,”r_0_c_2″,”r_1_c_0″,”r_1_c_1″,”r_1_c_2”];

    var columns:int = 3;

    var rows:int = 2;

    function scanArrayNestedLoops():void {

    var len:int = flatArray.length;

    var idx:int = 0;

    for(var r:int = 0; r < rows; r++) {

    for(var c:int = 0; c < columns; c++) {

    idx = r * columns + c;

    trace(“value at row=”+r+”,col=”+c+” is ‘”+flatArray[idx]+”‘”);

    }

    }

    }

    scanArrayNestedLoops();

    The advantage is that you replace the modulus operation with a multiplication and an add, which are supposed to be faster than modulus.

    Having said that, to really know whether it’s faster or not, it should be benchmarked. And by the way, even if a modulus operation is slower, my guess is that it couldn’t possibly be a real bottle-neck, but then again, I’m guessing.

    @robs,

    Using a flat array instead of nested arrays is indeed more efficient in terms of processor performance (and probably takes up less memory, but that could not be necessarily the case), for the simple reason that nested arrays are arrays of arrays in Actionscript. Each array is an object, and creating and managing them has a cost. Naturaly, creating and managing eleven array objects (assuming a 10 x 10 grid) takes more resources than creating and managing just one.

    Cheers

    Juan Pablo Califano

  22. Is it confirmed that nested arrays are slower than “flat” arrays?

    I have whitnessed otherwise with AS3, espescially these latests builds.

    I would say for ease of coding over the insignifigant optimisation you should use nested arrays.

  23. Robin,

    I just tested it, and you are correct. With the latest builds of player 9, nested arrays are actually faster than using the techniques described above This is surprising, because object instantiation and property access are usually quite taxing.

    In my tests, populating a 1000 by 1000 element array was about 10% faster with nested arrays (this includes instantiating the nested arrays) versus using a flattened array. More importantly, access of the values was very significantly faster for the nested arrays, by almost 20 times.

    Using flattened arrays was much faster than nested arrays in AS2, and I believe they remained noticeably faster in early builds of player 9. The player team has obviously worked some magic and made this massively more efficient. Excellent!

    My recommendation, based on these findings: Use flattened arrays for performance critical routines in AS2, but stick with the more readable and performant nested approach for everything else.

    Thanks for bringing that to my attention. Maybe robs was actually right (though his comment remains utterly unhelpful).

  24. Juan Pablo Califano May 24, 2008 at 11:26pm

    “In my tests, populating a 1000 by 1000 element array was about 10% faster with nested arrays (this includes instantiating the nested arrays) versus using a flattened array.”

    Quite surprising, indeed.

    “Each array is an object, and creating and managing them has a cost. Naturaly, creating and managing eleven array objects (assuming a 10 x 10 grid) takes more resources than creating and managing just one.”

    Oops, mental note: next time don’t be so lazy and actually do some benchmarking first, instead of assuming something as being “naturally” true, just because it “makes sense”. Especially, when it comes to code performance.

    Cheers

    Juan Pablo Califano

  25. Juan Pablo Califano May 25, 2008 at 10:09pm

    Well, I have just made some tests, and it seems like using nested arrays works better for AS 2.0, too. Especially, for building the arrays. (I’m testing with the standalone flash player 9.0.45, don’t know what the figures would be on FP8).

    =========================

    AS 2.0, 500 x 500 items

    =========================

    buildNested:548

    buildFlat:2097

    scanNestedArrays:381

    scanFlatArrayNestedLoop:484

    scanFlatArraySingleLoop:904

    =========================

    AS 3.0, 1000 x 1000 items

    =========================

    buildNested:373

    buildFlat:477

    scanNestedArrays:181

    scanFlatArrayNestedLoop:188

    scanFlatArraySingleLoop:1319

    The tested code (it’s exactly the same for both versions, exception in AS 2.0 int’s are replaced by Number’s):

    public function buildFlat():int {

    var init:int = getTimer();

    var len:int = rows * cols;

    var i:int = 0;

    flat = new Array(len);

    for(i = 0; i(LESS_THAN) len;i++) {

    flat[i] = 1;

    }

    return getTimer() – init;

    }

    public function buildNested():int {

    var init:int = getTimer();

    var r:int = 0;

    var c:int = 0;

    nested = new Array(rows);

    for(r = 0; r (LESS_THAN) rows;r++) {

    nested[r] = new Array(cols);

    for(c = 0; c (LESS_THAN) cols; c++) {

    nested[r][c] = 1;

    }

    }

    return getTimer() – init;

    }

    public function scanNestedArrays():int {

    var init:int = getTimer();

    var r:int = 0;

    var c:int = 0;

    var tmp:int = 0;

    for(r = 0; r (LESS_THAN) rows;r++) {

    for(c = 0; c (LESS_THAN) cols; c++) {

    tmp = nested[r][c];

    }

    }

    return getTimer() – init;

    }

    public function scanFlatArraySingleLoop():int {

    var init:int = getTimer();

    var len:int = rows * cols;

    var i:int = 0;

    var tmp:int = 0;

    var r:int = 0;

    var c:int = 0;

    for (i=0; i (LESS_THAN) len; i++) {

    c = i % cols;

    r = Math.floor(i/cols);

    tmp = flat[i];

    }

    return getTimer() – init;

    }

    public function scanFlatArrayNestedLoop():int {

    var init:int = getTimer();

    var len:int = rows * cols;

    var idx:int = 0;

    var tmp:int = 0;

    var r:int = 0;

    var c:int = 0;

    for(r = 0; r (LESS_THAN) rows; r++) {

    for(c = 0; c (LESS_THAN) cols; c++) {

    idx = r * cols + c;

    tmp = flat[idx];

    }

    }

    return getTimer() – init;

    }

    Cheers

    Juan Pablo Califano

  26. Thanks for the tips on using modulus. I never would have imagined using it for screen wrapping.

  27. Awesome, I love snippets like these, keep em coming!

  28. looping a number range forward or backward

    var c:Number = 0;

    var range:Number = 10;

    increment.onRelease = function(){

    var n:Number = Math.abs(++c%range);

    trace(n)

    }

    decrement.onRelease = function(){

    var n:Number = Math.abs(–c%range);

    trace(n)

    }

  29. Similar to the idea of screen wrapping I used modulo to flip through a series of images that produced a 3D rotation effect from still images. The images were listed in an array. As the user drags the mouse leftright the images swap out. Modulo comes in handy by making it simple to wrap from the end of the array to the beginning, and visa-versa.

    http://polygeek.com/368_portfolio_taking-my-cars-for-a-spin-with-actionscript-30

  30. This is great, I’m looking forward to more of this series!

  31. For alternation I use:

    rowColor = (fooIndex = (fooIndex == false) )?0xFFFFFF:0xCCCCCC;

  32. With CS4 will possible to use a Vector data type Array.

    Now an array can be variable:

    var a:Array = [‘hi’,45, moviePoniter, {obj:5}];

    In the next flash release, the vectors == array mono-data-type!

    So, Grant flat array speed idea could back be correct!

  33. Look forward to reading the rest of the series. I also did a little write up on the differences between computational and mathematical mod, and the benefits of using a slightly different definition of mod in Flash, where -1 % 4 = 3 ( Flash will give you -1 ), say if you were decrementing an index for an array and wanted to go to the last element.

    See more here:

    http://www.timrobles.com/blog/2008/04/03/math-mod-util-class/

  34. Great idea for this series. This is stuff I could have used in the past and can use in the future.

  35. It is great, I’m looking forward to more of this series. thanks for really good item

  36. Hi. I never knew of such a thing as modulus. Thanks, I have learned something new to-day!

  37. This discussion of the use of modulus was so good (and language-independent) that I’ll bet you could help with a problem I’m having as a C# developer. My real-world need is probably too industry-specific to be clearly communicated, but I have conceived a familiar analogy that matches it:

    Imagine that you are writing a program to play Bingo. The 75 numbered balls are arranged in 5 groups of 15, one group corresponding to each letter of the word “BINGO”.

    Balls 1-15 belong to group 0 (the letter B).

    Balls 16-30 belong to group 1 (the letter I).

    Balls 31-45 belong to group 2 (the letter N).

    Balls 46-60 belong to group 3 (the letter G).

    Balls 61-75 belong to group 4 (the letter O).

    Given any number in the range from 1 to 75, we’ll say “61”, to which group of 15 does it belong (0, 1, 2, 3 or 4)?

    Thanks for a great discussion.

  38. J – it actually wouldn’t require modulus. You just need to divide the number by the group size and floor the result.

    var groupNum = Math.floor(num/groupSize);

    Your example is starting at 1 instead of 0 though, so you have to correct by subtracting 1 from the number.

    ex.

    groupNum = Math.floor( (61-1) / 15 );

    groupNum = 4;

  39. I know it’s an old thread, but I’m hoping you could shed some light: I’ve created a grid using modulo just like Lanny posted above:

    function drawGrid() {

    for (var i=0; i

  40. fuck arrays i use xmls and objects all the time…

    no need for arrays. you could tell me the difference between those beacause i dont know but i wouldnt care anyway.

    you wanna fuck with tables and rows go fuck wit mysql.

  41. I love this post ! Modulus is great.

    I was really interested in the script where you can create a grid , and then mixing the alternating colors to make a checker board kinda look…

    heres my code that I ended up with that handles the fact that you do not get proper checker if the columns are even in count… I’ve love to know a more efficient way to write it. Anyone?

    if( i % cols == 0){

    rowIndx++;

    }

    if(cols % 2 == 0){

    if(rowIndx % 2 == 0 ){

    color = i % 2 ? 0x111111 : 0xeeeeee;

    }else{

    color = i % 2 ? 0xeeeeee : 0x111111;

    }

    }else{

    color = i % 2 ? 0x111111 : 0xeeeeee;

    }

  42. I’m currently using the modulus operator to help with my multiple object tracking project… I keep track of how many pixel colour changes there are in a horizontal row of pixels, then if the number is even (x % 2 == 0) it’s the entry point of a blob, else (x % 2 != 0) it’s odd, therefore an exit point. Doing so, I can keep track of multiple blobs, therefore track multiple objects 😀

    If only my fellow students knew the wonders of maths and physics when it comes to coding 😛

Comments are closed.