<HTML><HEAD></HEAD>
<BODY dir=ltr>
<DIV dir=ltr>
<DIV style="FONT-FAMILY: 'Calibri'; COLOR: #000000; FONT-SIZE: 12pt">
<DIV>
<DIV>This is probably the most important test/demonstration program I ever wrote
<BR>and published/released onto the internet (up to this date (7 juli
2011)).</DIV>
<DIV> </DIV>
<DIV>I hope compiler writers/programming language designers will study it
<BR>carefully and integrate it into their language.<BR>(It's a bit long/lengthy
read by well worth it ! Also casual programmers can <BR>benefit from it as well
!)</DIV>
<DIV> </DIV>
<DIV>See comments for more details about the usefullness and the value of it for
<BR>present day and the future.</DIV>
<DIV> </DIV>
<DIV>Also see test program way down below for usage example and verification
<BR>program.</DIV>
<DIV> </DIV>
<DIV>Especially the formula's are very important.</DIV>
<DIV> </DIV>
<DIV>For more information how this program came to be see the other thread
called <BR>"dynamic pointer indexing"</DIV>
<DIV> </DIV>
<DIV>Which takes this step a bit further to provide direct memory access
<BR>(concept/thread which is still under development).</DIV>
<DIV> </DIV>
<DIV>This posting takes a step back to evaluate and verify the formula's to be
<BR>used in "dynamic pointer indexing".</DIV>
<DIV> </DIV>
<DIV>For now this example/concept can be thought of as "dynamic indexing".</DIV>
<DIV> </DIV>
<DIV>Which can also be thought of as "multi-dimensional indexing".</DIV>
<DIV> </DIV>
<DIV>A future which is currently missing in C/C++/CUDA C/C++ and in a way also
<BR>Delphi since Delphi requires a pointer array per additional dimension.</DIV>
<DIV> </DIV>
<DIV>The technique illustrated below needs none of that Delphi overhead and
<BR>introduces it's own much smaller overhead, memory-wise, it does introduce a
<BR>somewhat more computation-overhead.</DIV>
<DIV> </DIV>
<DIV>There is also a hidden potential problem if parenthesis would be
used.</DIV>
<DIV> </DIV>
<DIV>A small explanation for the people that did not follow the other thread
<BR>mentioned:</DIV>
<DIV> </DIV>
<DIV>The multiply operator is used as a passing mechanism to calculate a linear
<BR>index for the multi dimension indexes.</DIV>
<DIV> </DIV>
<DIV>// *** Begin of Program ***</DIV>
<DIV> </DIV>
<DIV>program TestProgram;</DIV>
<DIV> </DIV>
<DIV>{$APPTYPE CONSOLE}</DIV>
<DIV> </DIV>
<DIV>{</DIV>
<DIV> </DIV>
<DIV>Test dynamic multi dimensional index calculations</DIV>
<DIV> </DIV>
<DIV>version 0.01 created on 1 juli 2011 by Skybuck Flying</DIV>
<DIV> </DIV>
<DIV>To illustrate the theory behind dynamic multi dimension index calculations
I <BR>shall now<BR>create a little test/demonstration program to show you how to
write this <BR>code and what<BR>formula's to use.</DIV>
<DIV> </DIV>
<DIV>The example deviates from the written theory so far in regard to the order,
<BR>the order<BR>in the theory was assumed to be z, y, x however delphi's order
appears to be <BR>x, y, z.</DIV>
<DIV> </DIV>
<DIV>Therefore the formula's will be adepted to Delphi's order.</DIV>
<DIV> </DIV>
<DIV>For completeness sakes I shall mention the formula's in this comments one
<BR>more time.</DIV>
<DIV> </DIV>
<DIV>How these formula's where derived I will not explain here because it was a
<BR>bit vague and messy but all in all not to bad.<BR>But you don't need to know
that... all that matters are the formula's you <BR>can probably derive/come to
the conclusion<BR>how these were formed yourself and if not consider these a
gift to you from <BR>me ! ;) :)</DIV>
<DIV> </DIV>
<DIV>Formula for index calculation in abstract form:</DIV>
<DIV> </DIV>
<DIV>result.index =<BR>(lower dimension parameter.index * lower dimension
parameter.stride) +<BR>(higher dimension parameter.index * lower dimension
parameter.volume);</DIV>
<DIV> </DIV>
<DIV>the resulting stride should be 1 until further notice<BR>result.stride =
1;</DIV>
<DIV> </DIV>
<DIV>Valueable notes for you to understand:</DIV>
<DIV> </DIV>
<DIV>Strides always have a minimum of 1.<BR>Volumes always have a minimum of
1.<BR>DimensionCounts always have a minimum of 1.</DIV>
<DIV> </DIV>
<DIV>These ones assure that none of the multiplications are zero-ed out, that
<BR>would lead to wrong results.<BR>This is why these general formula's work. No
matter if the stride is 1 and <BR>the volume is 1 it will still work.<BR>So some
unnecessary multiplications with 1 might be done but so be it for
<BR>generalities sake.</DIV>
<DIV> </DIV>
<DIV>The last formula you will need is the volume calculation in abstract form
<BR>which is actually quite simply:</DIV>
<DIV> </DIV>
<DIV>result.volume = (lower dimension parameter.volume * higher dimension
<BR>parameter.volume);</DIV>
<DIV> </DIV>
<DIV>It should be apperent to you now why this will work, but I shall explain it
<BR>anyway.</DIV>
<DIV> </DIV>
<DIV>Since the order is from left to right which means low to high this will
<BR>work.</DIV>
<DIV> </DIV>
<DIV>The lowest dimension is multiplied with the higher dimension giving a new
<BR>volume, in the first two dimension case<BR>this would be the area (a volume
with a depth of 1) the next dimension it is <BR>multiplied with would give a new
volume.<BR>(a real 3d volume with a depth of depth). The next dimension it is
<BR>multiplied against gives a 4D volume. I use<BR>the term "volume" for a lack
of a better term for a 4D quanitity. So think <BR>of a volume is that which
describes<BR>the entire (coordinate) space (or index space if you will).</DIV>
<DIV> </DIV>
<DIV>I shall also give these two formula's in a somewhat more concrete and short
<BR>hand form for direct/easy/correct implementation purposes:</DIV>
<DIV> </DIV>
<DIV>result.stride := 1;<BR>result.index := (ParaA.Index * ParaA.Stride) +
(ParaB.Index * ParaA.Volume);<BR>result.volume := (ParaA.Volume *
ParaB.Volume);</DIV>
<DIV> </DIV>
<DIV>Now it's time for a test/demonstration program to proof to you that this is
<BR>not bullshit, to prove to you that is is valuable<BR>and that this works and
to show the power/flexibility of it so you will <BR>hopefully see how usefull
this would become<BR>if this became a primary language feature with further
support behind it ! <BR>;) =D</DIV>
<DIV> </DIV>
<DIV>However the current code which shall be provided can already be of high
<BR>value for current day usasage ! ;) =D</DIV>
<DIV> </DIV>
<DIV>To show the usefullness of it a type will be introduced which shall
<BR>encompass this theory and these formula's.</DIV>
<DIV> </DIV>
<DIV>This type shall be called "TDynamicIndex" it's purposes is many-fold:</DIV>
<DIV> </DIV>
<DIV>To construct "dynamic" multi dimensional array indexing
automatically.</DIV>
<DIV> </DIV>
<DIV>So that the user programmer can easily adjust it's code to support all
kinds <BR>of 1D, 2D, 3D and xD dimensions.</DIV>
<DIV> </DIV>
<DIV>Possibly layed out over a single dimension.</DIV>
<DIV> </DIV>
<DIV>So this type calculates a linear index (which is the final/result index)
<BR>which can then be used to access for example<BR>the memory system (which is
a 1D entity).</DIV>
<DIV> </DIV>
<DIV>Also to simply the design, the indexed property will be replaced with a
<BR>procedure, this illustrates<BR>that the method is applieable to other
languages which do not have <BR>properties like c/c++, so this also
illustrates<BR>that the method works not because of properties but thanks to
operator <BR>overloading.</DIV>
<DIV> </DIV>
<DIV>However I have no way of setting the index value with indexed properties (a
<BR>procedure call would look ugly so I am going<BR>to leave it in ! ;):)) but
rename it also a little bit to show what it does.</DIV>
<DIV> </DIV>
<DIV>This test/demonstration program will also function as a verifier to verify
<BR>that the calculations are indeed correct.</DIV>
<DIV> </DIV>
<DIV><BR>Conclusion:</DIV>
<DIV> </DIV>
<DIV>It works flawlessly so far.</DIV>
<DIV> </DIV>
<DIV>This is probably one of the, if not the, most important test program and
<BR>theory I have ever published.</DIV>
<DIV> </DIV>
<DIV>I hope compiler writers will study it carefully and will hopefully be able
<BR>to integrate this "technology" into<BR>their programming languages so that
we programmers can finally use "dynamic <BR>pointers" and "dynamic indexes"..
so<BR>that we programmers can finally program easily in multiple dimensions
which <BR>translate to a linear/1d dimension for memory access.</DIV>
<DIV> </DIV>
<DIV>So that we can finally have multi dimensional array indexing with paying
<BR>penalties like additional pointers or difficult data<BR>structure
construction involving multiple array creations and such.</DIV>
<DIV> </DIV>
<DIV>This demonstration and code will become more valuable as CUDA/OpenCL
becomes <BR>more valuable and widely used.</DIV>
<DIV> </DIV>
<DIV>CUDA C/C++ is a perfect example of the<BR>"multi dimensional indexing
hell/linear index calculation hell, problem <BR>distribution hell" that CUDA
C/C++ programmers are now facing.</DIV>
<DIV> </DIV>
<DIV>This code demonstration demonstrates how to solve it in a flexible
way.</DIV>
<DIV> </DIV>
<DIV>The usage example is hard coded to use the dimensions of x: 320 y: 200 z:
60 <BR>which represents the classic ms-dos vga<BR>screen and a refresh rate of
60, (which was actually 70 at the time but ok), <BR>so some programmers might be
used to these dimensions<BR>and might recgonize some of it.</DIV>
<DIV> </DIV>
<DIV>Hopefully needless to say, this example is not limited to these dimensions,
<BR>and any dimension can be used.</DIV>
<DIV> </DIV>
<DIV>A word of caution: integer has been used for volume. It's pretty easy to
see <BR>how the volume calculation might overflow<BR>for large dimensions so
keep an eye out of that. For now I shall let it be <BR>an integer for speed's
sake.</DIV>
<DIV> </DIV>
<DIV>If an overflow occurs for your usage consider using an int64 for larger
<BR>dimension support.</DIV>
<DIV> </DIV>
<DIV>This demonstration code has limited itself to indexes to keep things
simple.</DIV>
<DIV> </DIV>
<DIV>Strides have also been set to 1.</DIV>
<DIV> </DIV>
<DIV>This represent a byte.</DIV>
<DIV> </DIV>
<DIV>Changing the stride to 4 would represent an integer.</DIV>
<DIV> </DIV>
<DIV>Only the first stride for the X dimension would need to be set to 4.</DIV>
<DIV> </DIV>
<DIV>The other strides should be left alone and be set to 1.</DIV>
<DIV> </DIV>
<DIV>Changing the stride would invalidate the verification program
ofcourse.</DIV>
<DIV> </DIV>
<DIV>Changing the code to automatically adept to changes should be obvious, but
<BR>for clearities sake<BR>will not be done in version 0.01.</DIV>
<DIV> </DIV>
<DIV>Perhaps version 0.02 might do this, but for now I see little value in it !
<BR>;) :)</DIV>
<DIV> </DIV>
<DIV>I shall now continue working on my TDynamicPointer concept which
uses<BR>the concepts presented here in TDynamicIndex and expands on it to
support<BR>direct access to the memory.</DIV>
<DIV> </DIV>
<DIV>}</DIV>
<DIV> </DIV>
<DIV>uses<BR>SysUtils;</DIV>
<DIV> </DIV>
<DIV>type<BR>TDynamicIndex = record<BR>private<BR> mIndex :
integer;<BR> mStride : integer;<BR> mDimensionCount :
integer;<BR> mVolume : integer;</DIV>
<DIV> </DIV>
<DIV> function StoreIndex( ParaIndex : integer ) :
TDynamicIndex;<BR>public<BR> constructor Create( ParaDimensionCount :
integer; ParaStride : integer );</DIV>
<DIV> </DIV>
<DIV> property IndexOperator[ ParaIndex : integer ] : TDynamicIndex read
<BR>StoreIndex; default;</DIV>
<DIV> </DIV>
<DIV> class operator Multiply( ParaA, ParaB : TDynamicIndex ) :
TDynamicIndex;<BR>end;</DIV>
<DIV> </DIV>
<DIV>constructor TDynamicIndex.Create( ParaDimensionCount : integer; ParaStride
: <BR>integer );<BR>begin<BR>mIndex := 0;<BR>mStride := 1;<BR>mDimensionCount :=
1;<BR>mVolume := 1;</DIV>
<DIV> </DIV>
<DIV>if ParaDimensionCount > 1 then<BR>begin<BR> mDimensionCount :=
ParaDimensionCount;<BR>end;</DIV>
<DIV> </DIV>
<DIV>if ParaStride > 1 then<BR>begin<BR> mStride :=
ParaStride;<BR>end;</DIV>
<DIV> </DIV>
<DIV>mVolume := mDimensionCount * mStride;<BR>end;</DIV>
<DIV> </DIV>
<DIV>// store index, and return a copy, not because we want to, but because we
<BR>must :(<BR>// I would much rather return a pointer, but unfortunately
calling multiple <BR>operator on pointer derefence won't work well ?!)<BR>//
perhaps it should be retried sometime...<BR>function TDynamicIndex.StoreIndex(
ParaIndex : integer ) : TDynamicIndex;<BR>begin<BR>mIndex :=
ParaIndex;<BR>result.mIndex := mIndex;<BR>result.mStride :=
mStride;<BR>result.mDimensionCount := mDimensionCount;<BR>result.mVolume :=
mVolume;<BR>end;</DIV>
<DIV> </DIV>
<DIV>class operator TDynamicIndex.Multiply( ParaA, ParaB : TDynamicIndex ) :
<BR>TDynamicIndex;<BR>begin<BR>result.mStride := 1;<BR>result.mIndex :=
(ParaA.mIndex * ParaA.mStride) + (ParaB.mIndex *
<BR>ParaA.mVolume);<BR>result.mVolume := (ParaA.mVolume *
ParaB.mVolume);<BR>end;</DIV>
<DIV> </DIV>
<DIV>procedure Main;<BR>var<BR>X : TDynamicIndex;<BR>Y : TDynamicIndex;<BR>Z :
TDynamicIndex;<BR>Result : TDynamicIndex;<BR>vErrorDetected : boolean;</DIV>
<DIV> </DIV>
<DIV>vX : integer;<BR>vY : integer;<BR>vZ : integer;</DIV>
<DIV> </DIV>
<DIV>vCheck : integer;<BR>begin<BR>X := TDynamicIndex.Create( 320, 1 );<BR>Y :=
TDynamicIndex.Create( 200, 1 );<BR>Z := TDynamicIndex.Create( 60, 1
);</DIV>
<DIV> </DIV>
<DIV>// first a few single tests to see/show how it works.<BR>Result := X[ 0 ] *
Y[ 0 ] * Z[ 1 ]; // should display 320*200*1*1=64000<BR>writeln(
Result.mIndex );</DIV>
<DIV> </DIV>
<DIV>Result := X[ 319 ] * Y[ 0 ] * Z[ 0 ]; // should display
319*1*1*1=319<BR>writeln( Result.mIndex );</DIV>
<DIV> </DIV>
<DIV>Result := X[ 319 ] * Y[ 100 ] * Z[ 0 ]; // should display 319*1 +
<BR>(100*320)*1*1 = 32319<BR>writeln( Result.mIndex );</DIV>
<DIV> </DIV>
<DIV>Result := X[ 319 ] * Y[ 100 ] * Z[ 5 ]; // should display 319*1 +
<BR>(100*320)*1 + (5*200*320)*1 = 32319 + 320000 = 352319<BR>writeln(
Result.mIndex );</DIV>
<DIV> </DIV>
<DIV>// so far so could so now let's do some exhaustive/full
verifications.<BR>writeln('Verification started.');</DIV>
<DIV> </DIV>
<DIV>vErrorDetected := false;<BR>for vZ := 0 to 59 do<BR>begin<BR> for vY
:= 0 to 199 do<BR> begin<BR> for vX := 0 to 319
do<BR> begin<BR> Result := X[ vX ] * Y[ vY ] * Z[
vZ ];</DIV>
<DIV> </DIV>
<DIV> vCheck := (vZ * 200 * 320) + (vY * 320) + vX;</DIV>
<DIV> </DIV>
<DIV> if Result.mIndex <> vCheck
then<BR> begin<BR> writeln('Index
calculation error detected at (vX, vY, vZ): ' + '(' + <BR>IntToStr(vX) + ',' +
IntToStr(vY) + ',' + IntToStr(vZ) + ')' );<BR>
vErrorDetected := true;<BR> end;<BR>
end;<BR> end;<BR>end;</DIV>
<DIV> </DIV>
<DIV>writeln('Verification done.');</DIV>
<DIV> </DIV>
<DIV>if vErrorDetected then<BR>begin<BR> writeln('Verification result:
errors detected !');<BR>end else<BR>begin<BR> writeln('Verification
result: no errors detected.');<BR>end;<BR>end;</DIV>
<DIV> </DIV>
<DIV><BR>begin<BR>try<BR> Main;<BR>except<BR> on E: Exception
do<BR> Writeln(E.ClassName, ': ',
E.Message);<BR>end;<BR>ReadLn;<BR>end.</DIV>
<DIV> </DIV>
<DIV>// *** End of Program ***</DIV>
<DIV> </DIV>
<DIV>Bye,<BR> Skybuck. </DIV></DIV></DIV></DIV></BODY></HTML>