Time efficiency

The difference seems to be how they are stored; packed arrays can only contain objects of the same type, so mma does not need to keep track of the type of each element. This can also speed up operations with them. Define

Unpacking

To be warned of arrays being unpacked, you can do SetSystemOptions[PackedArrayOptions->UnpackMessage->True] or, in versions after 7, On["Packing"] (thanks to OleksandrR for pointing this out). The you see that eg Select unpacks: try Select[fpacked, 3] and a message is produced. Also assigning a value of different type to a packed array unpacks it: try fpacked[[2]] = 4 to see this.

This unpacking explains mysterious slowdowns in mma code most of the time for me.

Addressing

It appears that it is twice as slow to address a single element in a packed vs an unpacked array:

So, you could set $Post = Developer`PackedArrayForm and then packed arrays would be displayed in a special way. I am not sure if this has any other sideeffects (this has been suggested in this great answer by ruebenko).

As of version 7, one may use On["Packing"] as an alternative to SetSystemOptions[PackedArrayOptions->UnpackMessage->True]. Also, AppendTo will not be appreciably faster for packed arrays in most cases because the great bulk of its runtime consists of copying the array. At least this is done without unpacking unless absolutely necessary (therefore probably using optimized memcpy).
–
Oleksandr R.Mar 26 '12 at 0:11

I think On["Packing"] may be one of the most useful things I've come across on this site. Thanks!
–
PillsyJun 19 '13 at 19:30

The difference

Packed arrays give you pretty much an access to a direct C memory layout, where the arrays are stored. Unpacked arrays reference arrays of pointers to their elements. This explains most of the other differences, in particular:

Space efficiency: if you look at how much space is required for packed arrays, you see that it is exactly the amount you'd need in C

Limitation to be rectangular: this allows to allocate arrays as contiguous blocks of memory, and perhaps use fast operations for array copying etc (such as memset, memcpy, or whatever custom analogs of them may exist in M implementation).

Runtime efficiency

Packed arrays by themselves would not bring to the table much except space efficiency. However, in addition to the new data structure, most fundamental functions have been internally overloaded to automatically use their specialized and much more efficient versions when arguments are packed arrays. Among these functions: Join, Tally, DeleteDuplicates, UnitStep, Clip, Unitize, Pick, Part,Transpose, Partition, etc.

This is a kind of a partial replacement of compilation in an interpreted environment. Some important things related to this:

Most numeric functions are Listable. This Listability is often not distinguished from the high-level one, where you can assign the Listable attribute to any function you write. While conceptually they serve the same purpose, being Listable means a different thing for numeric built-in functions in terms of implementation: it tells them that, given a packed array, they should use a specialized low-level version. This is the reason for huge speed-ups, because you effectively compile this part of the code.

Most built-in functions which take and process packed arrays, also output packed ararys, which provides means for composition.

Compile operates on packed arrays and produces packed arrays. Most common iteration functions such as Map, Table etc often auto-compile the functions they iterate, thus also produce packed arrays. This adds a lot, since the user is able to extend the set of fast (packed-array based) functions by using Compile. Since M8, the user is also able to produce Listable compiled functions, in the same sense as numeric Listable functions.

Sparse arrays use packed arrays internally to store their data

The main idea of all this is to operate on large chunks of data at once, and avoid the main evaluator by pushing most of the work to the kernel. As I said, this IMO can be viewed as a sort of a partial compilation technique. I just want to stress once again that for this to work, the most important part is a tight integration of packed arrays into the core language, which affects many functions. All these functions have specialized low-level versions which are used when packed arrays are supplied to them. Because of the rectangular layout of the arrays, they map directly on native C arrays, so these specialized implementations can be very fast.

Addressing

In addition to the observations of @acl, I just want to stress that addressing measured in isolation seems not really that important (the twofold difference is most likely due to the extra pointer dereferencing, although I may be wrong). The point IMO is that packed arrays are effective when used with an entirely different programming style, where explicit individual indexing is avoided as much as possible (except possibly inside Compile), and instead the code is rewritten in such a way that this indexing is done internally by built-in functions, at a much lower level.

Limitations

As mentioned already, arrays must be rectangular and of the same native type (Integer, Real, or Complex)

Not all functions benefit from packed arrays. One notable example which does not, is Sort (and also Union, Complement, Intersection, Ordering) with a default comparison function.

When to use

Actually, whenever you can. I can't recall any case off the top of my head where the use of packed arrays would hurt (if they can be used). Just one hypothetical scenario comes to mind: you store a large amount of data in a packed array, but then somewhere in your code it gets unpacked and eats up all your memory. However, while it is stated in the documentation that computations on packed arrays would always produce the same results as on identical unpacked ones, there are probably corner cases like this one, where this is not so. It seems however that such cases are, so to speak, of measure zero.

One useful trick which isn't emphasized enough is that often you can store your data very space-efficiently even when the main array can not be packed, but its elements can. Given such a list as unpacked, you can MapDeveloper`ToPackedArray on it, which may lead to very siginificant savings, both in terms of run-time and memory efficiency. One example of such use is here.

In general, when you see the recommendation to "vectorize the problem" or "use vectorized operations" for speed, this is exactly about using packed arrays. Various solutions for this question (except mine) are good examples of such vectorized use. There are plenty of other similar ones here on SE, on SO and MathGroup. One example which I find interesting and somewhat standing out is this one, where I used packed arrays to pack a small matrix of positions, and this still lead to a dramatic speed-up because that matrix was used to extract huge numbers of elements from a list at once, and Extract is also optimized on packed arrays - so, in some cases packing of even small arrays can be beneficial.

This illustrates once again my main message: the big deal is not just packed arrays as a stand-alone data structure, but a different programming style possible when all relevant ingredients are packed. It is this style which leads to huge performance boosts, not just packing by itself.

good point about them being useful for a different style, and useful discussion :) +1
–
aclMar 25 '12 at 23:37

@acl Thanks. Your answer is pretty good too, I voted for it. And I also noticed a rather untypical for your answering style length and organization of it. This seems painfully familiar, and apparently contagious :)
–
Leonid ShifrinMar 25 '12 at 23:42

thanks. About the style, I thought I'd up my game :) I find this organization useful in other people's answers so I try to do the same
–
aclMar 25 '12 at 23:45

please note how flexibly I am entering into extended discussions in comments, mere hours after proclaiming their absence being the sole differentiator from other online resources!
–
aclMar 25 '12 at 23:46

@acl Oh yes, I do note. Actually, people do want to get engaged in discussions, and comments on SE is a backdoor for that. I can imagine that SE "doesn't like this" (and there is some explicit evidence, such as automatic invitations to switch to chat), but it has to live with that. Will leave now, to avoid such an invitation and get some sleep - it is 4 a.m. here.
–
Leonid ShifrinMar 25 '12 at 23:51

Mathematica is a registered trademark of Wolfram Research, Inc. While the mark is used herein with the limited permission of Wolfram Research, Stack Exchange and this site disclaim all affiliation therewith.