AS3 Interesting Numeric Storage Behavior
When storing numbers in AS3 VM Andre Michelle and his collegue Bram de Jong at splicemusic found an interesting behavior of the internal uint storage. When the numbers are stored they change from int to Number depending on range. Why does this matter? Because ints are faster than Numbers and during larger simulations with lots of math it could slow things down quite a bit at these types change.
The disadvantage of this is that Numbers are slower in computation as well as reading, writing in an Array.
The internal findings when storing a uint
From 0 to 27 it is int
From 28 to 31 it is Number
From 32 to 59 it is int (again)
From 60 to 63 it is Number (again) …
Found when reading another excellent polygonal labs post on benchmarks and performance (this one is great as well concerning faster operations using bitwise shifts or alternate ways to eek out more performance) where he wisely advises to use signed int for loops or iterations rather than uint where needed because the iterations with numbers will be slower.
Andre Michelle posted an Adobe response on the issue and it is a known and by design characteristic due to the metadata that is stored with the datatype in the AS3 virtual machine.
The AS3 VM uses 32-bit Atom formats to store various types. 3-bits of the Atom describe the type data, leaving 29-bits for actual data. In some cases, like null/undefined/void/etc, we use 3-bits plus a few more bits to define the type.
For signed integers, we have 28-bits to work with plus a sign bit. For unsigned integers we have 29-bits (or maybe 28 with the upper bit always zero?). Once your number gets larger than 28/29 bits, we dynamically switch it to a Number Atom type, which contains a 3-bit type value with a 29-bit ptr. All ptrs are 8-BYTE aligned so we get away with using 29-bits there.
All three formats are basically interchangeable. When storing a number in an Atom, we see if it’s an integer and fits within the 28/29 bits. If so, we store it as a int/uint value – otherwise we store it as a Number value.
It essentially is an optimization for uint to make it faster at times but its good to know for large iterative loops or large storage where uints might be needed. This goes back to sometimes where optimizations are a mixed bag. The switching/converting types adds delay to the iteration.
var num: uint;
for (var i: int = 0; i < 64; i++)
{
num = 1 << i;
trace( i, getQualifiedClassName( num ) ); }
0 int 1 int 2 int 3 int 4 int 5 int 6 int 7 int 8 int 9 int 10 int 11 int 12 int 13 int 14 int 15 int 16 int 17 int 18 int 19 int 20 int 21 int 22 int 23 int 24 int 25 int 26 int 27 int 28 Number 29 Number 30 Number 31 Number 32 int 33 int 34 int 35 int 36 int 37 int 38 int 39 int 40 int 41 int 42 int 43 int 44 int 45 int 46 int 47 int 48 int 49 int 50 int 51 int 52 int 53 int 54 int 55 int 56 int 57 int 58 int 59 int 60 Number 61 Number 62 Number 63 Number
![*drawlogic – interactive and game development technologies for the web – flash, flex, unity3d, silverlight, javascript [ draw.logic ]](http://farm4.static.flickr.com/3270/3068080918_eeebfbdb01_o.png)
Numbers are so strange in AS3 …
I don’t know the first thing about AS3, but I suspect that «1 << i» is the same as «1 << (i & 0×1f)». That is, only the bottom 5 bits of i are used to perform the shift, so the actual shift is always from 0 to 31 regardles of how large i gets.
You don’t print out the value of num, but I suspect you’ll find that «1 << 1» is the same as «1 << 33». If so, it inherits this behaviour from the SHL instruction on Intel architectures.
Drj11,
Yes it has to do with the underlying framework that runs probably in C or C++ that runs the virtual machine. This only happens when doing performance tweaks like bitwise shifts because it accesses the type faster due to direct memory but because there is no wrapper (I am speculating) then it passes the types back without any filtering.
This does not happen on a normal loop with a typed iterator only performance areas where bitwise shifts are faster (which are in many places stop by polygonal labs to see that the cleanest code or simplest code is not always the fastest). Optimization can sometimes be a gotcha. Now on iterations using bitwise on a high performance app there will be slowdowns appearing in the range where Numbers appear rather than int. Again, not a big deal if you aren’t really looking to extend every bit of performance you can out of the flash vm, for most purposes its overkill. When doing games and other really high concurrent systems like that it becomes an issue. (i.e. iterating over objects in a multiplayer map rapidly)
It’s interesting, Sho claims that his tests led him to believe that Numbers may actually be faster than ints in Flash:
http://kuwamoto.org/2006/06/15/avoid-ints-in-actionscript/
Grant Skinner’s tests showed that ints had only a small improvement over Number, but uint was much worse then either:
http://www.gskinner.com/blog/archives/2006/06/types_in_as3_in.html
It seems like the only consistent claim is that numerical data types in Flash are inconsistent
Hey Nate,
Yeh the uint constantly does conversions from int to Number so that is slower by far, conversions are expensive. The important thing is I guess is to go with one type and stick with it. Conversions are the bottleneck in uint when bitwise operations happen.
i’m agree Andre Michelle didn’t know about he talking about. but I thing this test is a little distorted. May be if you put entire data in trace, including num value. I did the test tracing the entire data and the result was this:
var num: uint;
for (var i: int = 0; i < 64; i++)
{
num = 1 << i;
trace( i, getQualifiedClassName( num ) , num);
}
0 int 1
1 int 2
2 int 4
3 int 8
4 int 16
5 int 32
6 int 64
7 int 128
8 int 256
9 int 512
10 int 1024
11 int 2048
12 int 4096
13 int 8192
14 int 16384
15 int 32768
16 int 65536
17 int 131072
18 int 262144
19 int 524288
20 int 1048576
21 int 2097152
22 int 4194304
23 int 8388608
24 int 16777216
25 int 33554432
26 int 67108864
27 int 134217728
28 Number 268435456
29 Number 536870912
30 Number 1073741824
31 Number 2147483648
32 int 1
33 int 2
34 int 4
35 int 8
36 int 16
37 int 32
38 int 64
39 int 128
40 int 256
41 int 512
42 int 1024
43 int 2048
44 int 4096
45 int 8192
46 int 16384
47 int 32768
48 int 65536
49 int 131072
50 int 262144
51 int 524288
52 int 1048576
53 int 2097152
54 int 4194304
55 int 8388608
56 int 16777216
57 int 33554432
58 int 67108864
59 int 134217728
60 Number 268435456
61 Number 536870912
62 Number 1073741824
63 Number 2147483648
The Adobe Guys must to filter this issue, but in some way a programmer should understand this bad function in interpreted languages.
BINGO! heres the theorm behind this pattern. see if you can spot why the answer you have is the cause of this. 0+1+1+2+4+8+16+32+64+128…etc
[...] Ryan Christensen: AS3 Interesting Numeric Storage Behavior Andre Michelle: Weird behavior of numbers in as3 Michael Baczynski: Bitwise gems – fast integer math Michael Baczynski: Int, uint and number data type conversion Sho Kuwamoto: Avoid ints in ActionScript Grant Skinner: Types in AS3: ints not so fast, uints slow! This entry was posted on Saturday, May 3rd, 2008 at 16:19 and is filed under Nincs kategorizálva. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. « ApplicationDomain – parent and child [...]
I have to side with Quantium – the post as written is extremely misleading. Specifically, this:
“The internal findings when storing a uint
From 0 to 27 it is int
From 28 to 31 it is Number
From 32 to 59 it is int (again)
From 60 to 63 it is Number (again) …”
Should be
“The internal findings when storing a uint
From 1 << 0 to 1 << 27 it is int
From 1 << 28 to 1 << 31 it is Number
From 1 << 32 to 1 << 59 it is int (again)
From 1 << 60 to 1 << 63 it is Number (again) …”
Otherwise it is easy to think that uints should only be used when the expected value is from 0 to 27!