⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arrays-storage.texi

📁 A C++ class library for scientific computing
💻 TEXI
字号:
@node Array storage@section Array storage orders@cindex Array storage formats@cindex storage of arraysBlitz++ is very flexible about the way arrays are stored in memory.Starting indices can be 0, 1, or arbitrary numbers; arrays can be stored inrow major, column major or an order based on any permutation of thedimensions; each dimension can be stored in either ascending or descendingorder.  An N dimensional array can be stored in @math{N! 2^N} possible ways.Before getting into the messy details, a review of array storage formats isuseful.  If you're already familiar with strides and bases, you mightwant to skip on to the next section.@subsection Fortran and C-style arraysSuppose we want to store this two-dimensional array in memory:@example[ 1 2 3 ][ 4 5 6 ][ 7 8 9 ]@end example@unnumberedsubsubsec Row major vs. column majorTo lay the array out in memory, it's necessary to map the indices (i,j) intoa one-dimensional block.  Here are two ways the array might appear inmemory:@example[ 1 2 3 4 5 6 7 8 9 ][ 1 4 7 2 5 8 3 6 9 ]@end exampleThe first order corresponds to a C or C++ style array, and is called@emph{row-major ordering}: the data is stored first by row, and then bycolumn.  The second order corresponds to a Fortran style array, and iscalled @emph{column-major ordering}: the data is stored first by column, andthen by row.The simplest way of mapping the indices (i,j) into one-dimensional memory isto take a linear combination.@footnote{Taking a linear combination issufficient for dense, asymmetric arrays, such as are provided by the Blitz++@code{Array} class.}  Here's the appropriate linear combination for rowmajor ordering:@examplememory offset = 3*i + 1*j@end exampleAnd for column major ordering:@examplememory offset = 1*i + 3*j@end exampleThe coefficients of the (i,j) indices are called @emph{strides}.  For a rowmajor storage of this array, the @emph{row stride} is 3 -- you have to skipthree memory locations to move down a row.  The @emph{column stride} is 1 --you move one memory location to move to the next column.  This is also knownas @emph{unit stride}.  For column major ordering, the row and columnstrides are 1 and 3, respectively.@unnumberedsubsubsec BasesTo throw another complication into this scheme, C-style arrays have indiceswhich start at zero, and Fortran-style arrays have indices which start atone.  The first valid index value is called the @emph{base}.  To account fora non-zero base, it's necessary to include an offset term in addition to thelinear combination.  Here's the mapping for a C-style array with i=0..3 andj=0..3:@examplememory offset =  0 + 3*i + 1*j@end exampleNo offset is necessary since the indices start at zero for C-style arrays.For a Fortran-style array with i=1..4 and j=1..4, the mapping would be:@examplememory offset = -4 + 3*i + 1*j@end exampleBy default, Blitz++ creates arrays in the C-style storage format (base zero,row major ordering).  To create a Fortran-style array, you can use thissyntax:@exampleArray<int,2> A(3, 3, FortranArray<2>());@end exampleThe third parameter, @code{FortranArray<2>()}, tells the @code{Array}constructor to use a storage format appropriate for two-dimensional Fortranarrays (base one, column major ordering).A similar object, @code{ColumnMajor<N>}, tells the @code{Array} constructorto use column major ordering, with base zero:@exampleArray<int,2> B(3, 3, ColumnMajor<2>());@end exampleThis creates a 3x3 array with indices i=0..2 and j=0..2.In addition to supporting the 0 and 1 conventions for C and Fortran-stylearrays, Blitz++ allows you to choose arbitrary bases, possibly different foreach dimension.  For example, this declaration creates an array whoseindices have ranges i=5..8 and j=2..5:@exampleArray<int,2> A(Range(5,8), Range(2,5));@end example@subsection Creating custom storage orders@cindex storage order, creating your own@cindex Array storage order, creating your ownAll @code{Array} constructors take an optional parameter of type@code{GeneralArrayStorage<N_rank>}.  This parameter encapsulates a completedescription of the storage format.  If you want a storage format other thanC or Fortran-style, you have two choices:@itemize @bullet@item      You can create an object of type@code{GeneralArrayStorage<N_rank>}, customize the storage format, and usethe object as a argument for the @code{Array} constructor.@item      You can create your own storage format object which inherits from@code{GeneralArrayStorage<N_rank>}.  This is useful if you will be using thestorage format many times.  This approach (inheriting from@code{GeneralArrayStorage<N_rank>}) was used to create the@code{FortranArray<N_rank>} objects.  If you want to take this approach, youcan use the declaration of @code{FortranArray<N_rank>} in@code{<blitz/array.h>} as a guide.@end itemizeThe next sections describe how to modify a@code{GeneralArrayStorage<N_rank>} object to suit your needs.@unnumberedsubsubsec In higher dimensionsIn more than two dimensions, the choice of storage order becomes morecomplicated.  Suppose we had a 3x3x3 array.  To map the indices (i,j,k) intomemory, we might choose one of these mappings:@examplememory offset = 9*i + 3*j + 1*kmemory offset = 1*i + 3*j + 9*k@end exampleThe first corresponds to a C-style array, and the second to a Fortran-stylearray.  But there are other choices; we can permute the strides (1,3,9) anywhich way:@examplememory offset = 1*i + 9*j + 3*kmemory offset = 3*i + 1*j + 9*kmemory offset = 3*i + 9*j + 1*kmemory offset = 9*i + 1*j + 3*k@end exampleFor an N dimensional array, there are N! such permutations.  Blitz++ allowsyou to select any permutation of the dimensions as a storage order.  Firstyou need to create an object of type @code{GeneralArrayStorage<N_rank>}:@exampleGeneralArrayStorage<3> storage;@end example@code{GeneralArrayStorage<N_rank>} contains a vector called @code{ordering}which controls the order in which dimensions are stored in memory.  The@code{ordering} vector will contain a permutation of the numbers 0, 1, ...,N_rank-1.  Since some people are used to the first dimension being 1 ratherthan 0, a set of symbols (firstDim, secondDim, ..., eleventhDim) areprovided which make the code more legible.  The @code{ordering} vector lists the dimensions in increasing order ofstride.  You can access this vector using the member function@code{ordering()}.  A C-style array, the default, would have:@examplestorage.ordering() = thirdDim, secondDim, firstDim;@end examplemeaning that the third index (k) is associated with the smallest stride, andthe first index (i) is associated with the largest stride.  A Fortran-stylearray would have:@examplestorage.ordering() = firstDim, secondDim, thirdDim;@end example@unnumberedsubsubsec Reversed dimensionsTo add yet another wrinkle, there are some applications where the rows orcolumns need to be stored in reverse order.@footnote{For example, certainbitmap formats store image rows from bottom to top rather than top tobottom.}Blitz++ allows you to store each dimension in either ascending or descendingorder.  By default, arrays are always stored in ascending order.  The@code{GeneralArrayStorage<N_rank>} object contains a vector called@code{ascendingFlag} which indicates whether each dimension is storedascending (@code{true}) or descending (@code{false}).  To alter the contentsof this vector, use the @code{ascendingFlag()} method:@example// Store the third dimension in descending orderstorage.ascendingFlag() = true, true, false;// Store all the dimensions in descending orderstorage.ascendingFlag() = false, false, false;@end example@unnumberedsubsubsec Setting the base vector@code{GeneralArrayStorage<N_rank>} also has a @code{base} vector whichcontains the base index value for each dimension.  By default, the basevector is set to zero.  @code{FortranArray<N_rank>} sets the base vector toone.  To set your own set of bases, you have two choices:@itemize @bullet@item       You can modify the @code{base} vector inside the@code{GeneralArrayStorage<N_rank>} object.  The method @code{base()} returnsa mutable reference to the @code{base} vector which you can use to set thebases.@item       You can provide a set of @code{Range} arguments to the@code{Array} constructor.@end itemizeHere are some examples of the first approach:@example// Set all bases equal to 5storage.base() = 5;    // Set the bases to [ 1 0 1 ]storage.base() = 1, 0, 1;@end exampleAnd of the second approach:@example// Have bases of 5, but otherwise C-style storageArray<int,3> A(Range(5,7), Range(5,7), Range(5,7));// Have bases of [ 1 0 1 ] and use a custom storageArray<int,3> B(Range(1,4), Range(0,3), Range(1,4), storage);@end example@unnumberedsubsubsec Working simultaneously with different storage ordersOnce you have created an array object, you will probably never have to worryabout its storage order.  Blitz++ should handle arrays of different storageorders transparently.  It's possible to mix arrays of different storageorders in one expression, and still get the correct result.Note however, that mixing different storage orders in an expression mayincur a performance penalty, since Blitz++ will have to pay more attentionto differences in indexing than it normally would.You may not mix arrays with different domains in the same expression.  Forexample, adding a base zero to a base one array is a no-no.  The reason forthis restriction is that certain expressions become ambiguous, for example:@exampleArray<int,1> A(Range(0,5)), B(Range(1,6));A=0;B=0;using namespace blitz::tensor;int result = sum(A+B+i);@end exampleShould the index @code{i} take its domain from array @code{A} or array@code{B}?  To avoid such ambiguities, users are forbidden from mixing arrayswith different domains in an expression. @unnumberedsubsubsec Debug dumps of storage order information    In debug mode (@code{-DBZ_DEBUG}), class @code{Array} provides a memberfunction @code{dumpStructureInformation()} which displays information aboutthe array storage:@exampleArray<float,4> A(3,7,8,2,FortranArray<4>());A.dumpStructureInformation(cerr);@end exampleThe optional argument is an @code{ostream} to dump information to.  Itdefaults to @code{cout}.  Here's the output:@smallexample@include examples/dump.out@end smallexample@unnumberedsubsubsec A note about storage orders and initializationWhen initializing arrays with comma delimited lists, note that the array isfilled in storage order: from the first memory location to the last memorylocation.  This won't cause any problems if you stick with C-style arrays,but it can be confusing for Fortran-style arrays:@exampleArray<int,2> A(3, 3, FortranArray<2>());A = 1, 2, 3,    4, 5, 6,    7, 8, 9;cout << A << endl;@end exampleThe output from this code excerpt will be:@exampleA = 3 x 3         1         4         7          2         5         8         3         6         9@end exampleThis is because Fortran-style arrays are stored in columnmajor order.@subsection Storage orders example@smallexample@include examples/storage.texi@end smallexampleAnd the output:@smallexample@include examples/storage.out@end smallexample

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -