Home

Awesome

Question

What is the most efficient way to implement multidimensional arrays in JavaScript?

UPDATE Experiments for numeric.js, cwise and ndarray-ops added

Experiment

To run the experiment in node, just do:

node experiment.js

If you want to try it in your browser, you can install beefy by typing:

npm install -g beefy

Then running

beefy experiment.js --open

Results:

These are the results of running the experiment in the latest version of Chrome V8.

With:

Running experiment with dimensions = 16 x 16 x 16 experiment.js:30
   Proposal #1  raw native array                         Total Init =      0ms  Execution =      8ms 
   Proposal #2  raw typed array                          Total Init =      0ms  Execution =      9ms 
   Proposal #3  object with array accessor               Total Init =      0ms  Execution =     15ms 
   Proposal #4  object with flat accessor                Total Init =      0ms  Execution =     10ms 
   Proposal #5  object with flat accessor, no offset     Total Init =      1ms  Execution =     11ms 
   Proposal #6  array of native arrays                   Total Init =      1ms  Execution =     25ms 
   Proposal #7  array of native arrays (fast init)       Total Init =      1ms  Execution =      5ms 
   Proposal #8  array of typed arrays                    Total Init =      0ms  Execution =      9ms 
   Proposal #9  array of contiguous typed arrays         Total Init =      1ms  Execution =      9ms 
   Proposal #10 numeric.js simple                        Total Init =      0ms  Execution =     47ms 
   Proposal #11 numeric.js pointwise()                   Total Init =      0ms  Execution =     64ms 
   Proposal #12 ndarray-raw                              Total Init =      4ms  Execution =      8ms 
   Proposal #13 ndarray-ops                              Total Init =      0ms  Execution =     52ms 
   Proposal #14 cwise                                    Total Init =      0ms  Execution =      9ms 
Running experiment with dimensions = 64 x 64 x 64 experiment.js:30
   Proposal #1  raw native array                         Total Init =     57ms  Execution =    660ms 
   Proposal #2  raw typed array                          Total Init =      0ms  Execution =    471ms 
   Proposal #3  object with array accessor               Total Init =      1ms  Execution =    732ms 
   Proposal #4  object with flat accessor                Total Init =      1ms  Execution =    470ms 
   Proposal #5  object with flat accessor, no offset     Total Init =      1ms  Execution =    464ms 
   Proposal #6  array of native arrays                   Total Init =      3ms  Execution =   1516ms 
   Proposal #7  array of native arrays (fast init)       Total Init =     22ms  Execution =    244ms 
   Proposal #8  array of typed arrays                    Total Init =      7ms  Execution =    462ms 
   Proposal #9  array of contiguous typed arrays         Total Init =      4ms  Execution =    556ms 
   Proposal #10 numeric.js simple                        Total Init =      9ms  Execution =  11902ms 
   Proposal #11 numeric.js pointwise()                   Total Init =      5ms  Execution =   3399ms 
   Proposal #12 ndarray-raw                              Total Init =      1ms  Execution =    256ms 
   Proposal #13 ndarray-ops                              Total Init =      3ms  Execution =    770ms 
   Proposal #14 cwise                                    Total Init =      0ms  Execution =    201ms 
Running experiment with dimensions = 512 x 512 x 4 experiment.js:30
   Proposal #1  raw native array                         Total Init =    199ms  Execution =   1130ms 
   Proposal #2  raw typed array                          Total Init =      4ms  Execution =   1857ms 
   Proposal #3  object with array accessor               Total Init =      5ms  Execution =   3025ms 
   Proposal #4  object with flat accessor                Total Init =      5ms  Execution =   1895ms 
   Proposal #5  object with flat accessor, no offset     Total Init =      1ms  Execution =   1853ms 
   Proposal #6  array of native arrays                   Total Init =    162ms  Execution =   6221ms 
   Proposal #7  array of native arrays (fast init)       Total Init =    138ms  Execution =   1147ms 
   Proposal #8  array of typed arrays                    Total Init =    543ms  Execution =   1975ms 
   Proposal #9  array of contiguous typed arrays         Total Init =    395ms  Execution =   1921ms 
   Proposal #10 numeric.js simple                        Total Init =     81ms  Execution =  59890ms 
   Proposal #11 numeric.js pointwise()                   Total Init =     81ms  Execution =  17571ms 
   Proposal #12 ndarray-raw                              Total Init =      3ms  Execution =   1172ms 
   Proposal #13 ndarray-ops                              Total Init =      3ms  Execution =   3799ms 
   Proposal #14 cwise                                    Total Init =      3ms  Execution =    940ms 
Running experiment with dimensions = 512 x 4 x 512 experiment.js:30
   Proposal #1  raw native array                         Total Init =    228ms  Execution =   1841ms 
   Proposal #2  raw typed array                          Total Init =      1ms  Execution =   1856ms 
   Proposal #3  object with array accessor               Total Init =      1ms  Execution =   2886ms 
   Proposal #4  object with flat accessor                Total Init =      1ms  Execution =   1871ms 
   Proposal #5  object with flat accessor, no offset     Total Init =      1ms  Execution =   1869ms 
   Proposal #6  array of native arrays                   Total Init =     34ms  Execution =   6015ms 
   Proposal #7  array of native arrays (fast init)       Total Init =     25ms  Execution =    741ms 
   Proposal #8  array of typed arrays                    Total Init =      6ms  Execution =   1875ms 
   Proposal #9  array of contiguous typed arrays         Total Init =      4ms  Execution =   1891ms 
   Proposal #10 numeric.js simple                        Total Init =     31ms  Execution =  45547ms 
   Proposal #11 numeric.js pointwise()                   Total Init =     15ms  Execution =  13322ms 
   Proposal #12 ndarray-raw                              Total Init =      3ms  Execution =   1003ms 
   Proposal #13 ndarray-ops                              Total Init =      5ms  Execution =   2766ms 
   Proposal #14 cwise                                    Total Init =      3ms  Execution =    767ms 
Running experiment with dimensions = 4 x 512 x 512 experiment.js:30
   Proposal #1  raw native array                         Total Init =    208ms  Execution =   2232ms 
   Proposal #2  raw typed array                          Total Init =      1ms  Execution =   1885ms 
   Proposal #3  object with array accessor               Total Init =      1ms  Execution =   2907ms 
   Proposal #4  object with flat accessor                Total Init =      1ms  Execution =   1884ms 
   Proposal #5  object with flat accessor, no offset     Total Init =      1ms  Execution =   1870ms 
   Proposal #6  array of native arrays                   Total Init =     37ms  Execution =   5959ms 
   Proposal #7  array of native arrays (fast init)       Total Init =     26ms  Execution =    762ms 
   Proposal #8  array of typed arrays                    Total Init =      6ms  Execution =   1883ms 
   Proposal #9  array of contiguous typed arrays         Total Init =      4ms  Execution =   1912ms 
   Proposal #10 numeric.js simple                        Total Init =     23ms  Execution =  39231ms 
   Proposal #11 numeric.js pointwise()                   Total Init =     16ms  Execution =  13258ms 
   Proposal #12 ndarray-raw                              Total Init =      3ms  Execution =   1002ms 
   Proposal #13 ndarray-ops                              Total Init =      5ms  Execution =   2773ms 
   Proposal #14 cwise                                    Total Init =      3ms  Execution =    770ms 
Running experiment with dimensions = 2 x 2 x 2048 experiment.js:30
   Proposal #1  raw native array                         Total Init =      0ms  Execution =     16ms 
   Proposal #2  raw typed array                          Total Init =      0ms  Execution =     16ms 
   Proposal #3  object with array accessor               Total Init =      0ms  Execution =     26ms 
   Proposal #4  object with flat accessor                Total Init =      0ms  Execution =     17ms 
   Proposal #5  object with flat accessor, no offset     Total Init =      0ms  Execution =     17ms 
   Proposal #6  array of native arrays                   Total Init =      0ms  Execution =     49ms 
   Proposal #7  array of native arrays (fast init)       Total Init =      0ms  Execution =      7ms 
   Proposal #8  array of typed arrays                    Total Init =      0ms  Execution =     16ms 
   Proposal #9  array of contiguous typed arrays         Total Init =      0ms  Execution =     16ms 
   Proposal #10 numeric.js simple                        Total Init =      0ms  Execution =    230ms 
   Proposal #11 numeric.js pointwise()                   Total Init =      1ms  Execution =    139ms 
   Proposal #12 ndarray-raw                              Total Init =      0ms  Execution =      8ms 
   Proposal #13 ndarray-ops                              Total Init =      0ms  Execution =     49ms 
   Proposal #14 cwise                                    Total Init =      0ms  Execution =      9ms 
Running experiment with dimensions = 2048 x 2 x 2 experiment.js:30
   Proposal #1  raw native array                         Total Init =      1ms  Execution =     15ms 
   Proposal #2  raw typed array                          Total Init =      0ms  Execution =     15ms 
   Proposal #3  object with array accessor               Total Init =      0ms  Execution =     34ms 
   Proposal #4  object with flat accessor                Total Init =      0ms  Execution =     25ms 
   Proposal #5  object with flat accessor, no offset     Total Init =      0ms  Execution =     23ms 
   Proposal #6  array of native arrays                   Total Init =      1ms  Execution =     51ms 
   Proposal #7  array of native arrays (fast init)       Total Init =      2ms  Execution =     17ms 
   Proposal #8  array of typed arrays                    Total Init =      7ms  Execution =     20ms 
   Proposal #9  array of contiguous typed arrays         Total Init =      6ms  Execution =     19ms 
   Proposal #10 numeric.js simple                        Total Init =     21ms  Execution =    458ms 
   Proposal #11 numeric.js pointwise()                   Total Init =      2ms  Execution =    303ms 
   Proposal #12 ndarray-raw                              Total Init =      0ms  Execution =     17ms 
   Proposal #13 ndarray-ops                              Total Init =      0ms  Execution =     83ms 
   Proposal #14 cwise                                    Total Init =      0ms  Execution =     18ms 

UPDATE

Interesting things to note:

Generic Observations

Reasonable Approaches to Arrays

Excluding obviously stupid things,

Based on performance considerations, I am currently leaning toward option 4, but dissenting opinions are welcome.

UPDATE Observations about Libraries