<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>