Results 1 to 8 of 8

Thread: Get total size of multidimensional array

  1. #1

    Get total size of multidimensional array

    Hi.
    I encountered a problem, where i need to get size of 3D array, because i will use size of this to "SetLength" of other dynamic array (1D).

    What i have is this:
    Code:
    myarray[0..255, 0..255, 0..7] of tmyRecord;
    dynarray: array of tmyObject;
    3D array is used to render 3D map. Because i render only specific range (not whole map at once), the X, Y ranges may vary. They could be for ex: X: 17 - 24, Y: 0 - 7.
    Z is always max 7.

    Because of that i must sum them up: X * Y * Z. I get some value.
    And then i set the length of dynamic array to this sum.

    I mean

    Code:
    sum:= X * Y * Z; 
    SetLength(dynarray, sum);
    But is it safe and correct way to do?

    What i need is the SUM of NR_OF_OBJECTS within specified X,Y,Z range.


    Should i be aware of something? Crashes, leaks?

    Im just not sure if im doing it correctly.


    Thanks for any help.
    Last edited by hwnd; 18-10-2012 at 11:00 PM.

  2. #2
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,246
    Blog Entries
    2
    Hi hwnd,

    On the setLength front, you should (unless I'm mistaken) always remember to setLength to 0 when you're finished with the array.

    Another option you have though is to use a single array in the first place and use a function to generate an index when you access it using x,y,z. If you use your example dimensions, the function could look like this:-

    Code:
    function getIndex(x,y,z:integer):integer;
    begin
      result:=(z*256*256)+(y*256)+x;
    end;
    A faster, possibly more efficient variation on this could be:-

    Code:
    function getIndexFast(x,y,z:integer):integer;
    begin
      result:=(z shl 16)+(y shl 8)+x;
    end;
    Then you use a single dimensional array that is 256x256x8 elements in size.

    The exact formula you use could vary to improve performance. For example, lets say you use the items inside three loops like this:-

    Code:
    for x:=0 to 255 do
    begin
      for y:=0 to 255 do
      begin
        for z:=0 to 7 do
        begin
          // Use item here
        end;
      end;
    end;
    Then, to improve performance you could do this:-

    Code:
    function getBaseIndex(x,y:integer):integer;
    begin
         result:=(x shl 11)+(y shl 3);
    end;
    
    ...
    
    
    var
      baseIndex : integer;
    
    ...
    
    for x:=0 to 255 do
    begin
      for y:=0 to 255 do
      begin
        baseIndex:=getBaseIndex(x,y);
        for z:=0 to 7 do
        begin
          // Use item here
    
          inc(baseIndex);
        end;
      end;
    end;
    Of course, if you just need to read through them in a particular order, then you can tailor the 'getIndex' function to cater for that and then simply read through from 0 to 524287. This approach of converting from separate indices to one big number can also be applied to using fully dynamic arrays based on pointers. A while ago I wrote an article that featured a class that represented a map layer. The follow up thread http://www.pascalgamedevelopment.com...hread.php?3640 provides some example code of how to do this if you're interested.

    Hope this helps.
    :: AthenaOfDelphi :: My Blog :: My Software ::

  3. #3
    Thank you for all this help.
    I will try out what you wrote and will report the results of how it went.

  4. #4
    SetLength() with more than one length argument works too.

  5. #5
    Quote Originally Posted by AthenaOfDelphi View Post
    On the setLength front, you should (unless I'm mistaken) always remember to setLength to 0 when you're finished with the array.
    Dynamic arrays are reference counted, so you don't need to explicitly call SetLength to zero. They will be released automatically when the variable goes out of the scope.

    Quote Originally Posted by AthenaOfDelphi View Post
    Another option you have though is to use a single array in the first place and use a function to generate an index when you access it using x,y,z. If you use your example dimensions, the function could look like this:-

    Code:
    function getIndex(x,y,z:integer):integer;
    begin
      result:=(z*256*256)+(y*256)+x;
    end;
    A faster, possibly more efficient variation on this could be:-

    Code:
    function getIndexFast(x,y,z:integer):integer;
    begin
      result:=(z shl 16)+(y shl 8)+x;
    end;
    As long as optimizations are enabled, both versions will have equivalent performance as the compiler replaces 256 multipliers with bit shifts. You can confirm this by turning optimization on and then watching generated assembly code. The only difference in this case will be the second approach being more difficult to understand, so I'd recommend sticking to the first approach.

  6. #6
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,246
    Blog Entries
    2
    Quote Originally Posted by Lifepower View Post
    Dynamic arrays are reference counted, so you don't need to explicitly call SetLength to zero. They will be released automatically when the variable goes out of the scope.

    As long as optimizations are enabled, both versions will have equivalent performance as the compiler replaces 256 multipliers with bit shifts. You can confirm this by turning optimization on and then watching generated assembly code. The only difference in this case will be the second approach being more difficult to understand, so I'd recommend sticking to the first approach.
    Thanks for clearing that up Lifepower I always err on the side of caution with things like variable clean up and also whether or not the compiler will optimise such things. I always make the assumption it won't and try and figure out the most efficient way of doing it myself.
    :: AthenaOfDelphi :: My Blog :: My Software ::

  7. #7
    Quote Originally Posted by Super Vegeta View Post
    SetLength() with more than one length argument works too.
    But can you get it in other direction, get the length of the multidimensional array? For a while now i have stopped using Count property, and only rely on length() and high(). I know there's no problem with that if using 1-dimensional array with X,Y (,Z) multiplication.

    One thing that happens with multiplication, is that when array is resized, it is harder to track what data is from before and what you should copy over from temporary array, if data must persist. (From the top of my head i can't think of single case where i would need it but still...) When i have dynamic 1-dimensional array, say length(50) and i setlength(100), then all the data in index slots 0..49 are there from before, and 50..99 are undefined (or null?).

  8. #8
    assuming you set the size of your array like this:
    Code:
    SetLength(MyArr, X, Y, Z); //where X, Y, Z are the dimensions of the array
    you can get each dimension like this:
    Code:
    X := Length(MyArr);
    Y := Length(MyArr[0]);
    Z := Length(MyArr[0][0]);

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •