• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

a multi-dimensional Safearray attempt with dynamic index

Started by Eduardo Jorge, June 12, 2018, 08:34:10 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Eduardo Jorge

complicated this,
macro also did not accept to apply the pointer in its interior
I will do a cleanup on the amount of arrays and try to add a single control macro, and also add a redim preserve


'indexbase 0
skip {
arrayN( -2 to 5 , 3 to 10 )

' 3 4 5 6 7 8 9 10

{ 0 ,1 ,2 ,3 ,4 ,5 ,6 ,7, ' -2
8 ,9 ,10 ,11 ,12 ,13 ,14 ,15,' -1
16 ,17 ,18 ,19 ,20 ,21 ,22 ,23,' 0
24 ,25 ,26 ,27 ,28 ,29 ,30 ,31,' 1
32 ,33 ,34 ,35 ,36 ,37 ,38 ,39,' 2
40 ,41 ,42 ,43 ,44 ,45 ,46 ,47,' 3
48 ,49 ,50 ,51 ,52 ,53 ,54 ,55,' 4
56 ,57 ,58 ,59 ,60 ,61 ,62 ,63}' 5


}

int n0,n1
dim L, C,an
L=3

redim long ArrayNx_M(L)
redim int LBoundNx_M(L*3)
redim int UBoundNx_M(L*3)
redim int TBoundNx_M(L*3)
redim LONG  IBoundNx_M(L*3)
int *Arr1



function  CriaArray(int  ArrayNx,       
int Linha_Lbound,int Linha_Ubound,
int Coluna_Lbound,int Coluna_Ubound)

int n= ArrayNx

LBoundNx_M(N)=Linha_Lbound
UBoundNx_M(N)=Linha_Ubound
IBoundNx_M(N)=-Linha_Lbound
TBoundNx_M(N)=abs(Linha_Lbound - Linha_Ubound)+1
LBoundNx_M(N+1)=Coluna_Lbound
UBoundNx_M(N+1)=Coluna_Ubound
IBoundNx_M(N+1)=-Coluna_Lbound
TBoundNx_M(N+1)=abs(Coluna_Lbound - Coluna_Ubound)+1
ArrayNx_M(n)=getmemory TBoundNx_M(N)*TBoundNx_M(N+1)*sizeof int

end function

MACRO ARRAYnx_C(AN , L,C)
'@Arr1= ArrayNx_M(an) '<<<<<<<<

int B=(L+IBoundNx_M(AN))*TBoundNx_M(AN+1)+(c+IBoundNx_M(AN+1))

Arr1(B)

END MACRO


an=1
CriaArray(an, -2,5,3,10)

@Arr1= ArrayNx_M(an)     '<<<<<
int n=0

for L=LBoundNx_M(aN) to uBoundNx_M(aN)
for  c=LBoundNx_M(aN+1) to uBoundNx_M(aN+1)

ARRAYnx_C(AN, L , C)=N
n=n+1
next
next
L=-1
C=8

PRINT ARRAYnx_C(AN, L , C)
PRINT ARRAYnx_C(AN, 3 , 6)





I have to set up a matrix cleanup function "after learning how to do it"

Charles Pegge

Eduardo,

Got it!

There are too many state-variables here for macros. They would not provide a clean solution. You need to use an object to contain all the variables and functions associated with the array.

I suggest something like this: (you can adapt it)


'2018-06-13T15:03:24
class IntArrayYX
================
  '
  %= si sizeof(int)
  '
  int lboundX 'lower limit X
  int uboundX 'upper limit X
  int lboundY 'lower limit Y
  int uboundY 'upper limit Y
  int width
  sys buf    'data buffer
  int bytes  'sizeof buffer
  '
  method constructor(int ly=0, uy=0, lx=0, ux=0)
  ===============================================
  'ly lbound y lines
  'uy ubound y lines
  'lx lbound x rows
  'ux ubound x rows
  lboundY=ly
  uboundY=uy
  lboundX=lx
  uboundX=ux
  width=(uboundx-lboundx+1)
  bytes=si*(uboundy-lboundy+1)*width
  buf=getmemory bytes
  end method
  '
  method destructor()
  ===================
  freememory buf
  end method
  '
  method vi(int i, j, int v)
  ==========================
  'SET
  'i index
  'v value
  int a at buf+si*( (i-lboundy)*width+(j-lboundx) )
  a=v
  end method
  '
  method vi(int i, j) as int
  ==========================
  'GET
  'i index
  int a at buf+si*( (i-lboundy)*width+(j-lboundx) )
  return a
  end method
  '
  method ptr(int i, j) as sys
  ===========================
  'GET POINTER
  'i index
  return buf+si*( (i-lboundy)*width+(j-lboundx) )
  end method
  '
end class
'
'TESTS
======
new IntArrayYX ia(-10,20,30,40) 'lbound,ubound pairs
print ia.lboundY ", " ia.bytes
ia.vi(-5,31)=42
print ia.vi(-5,31)
del ia

Eduardo Jorge

Charles,
  I'm doing this is more to learn and assimilate the workings of the O2 macros, scope and pointers,
and also the operation of the code structure.

but what about the index of the array?
the fact of having to put the value already calculated inside a variable to apply to the array?
this can cause problems because it accepts simple calculations and the person will be left without realizing errors by complex calculations like index

Charles Pegge

This is an example of a macro function to access an array of pixels. It does not involve Lbound and Ubound terms, so it is a simpler situation.

Macro functions work by creating a temporary variable, which is substituted into the expression, replacing the macro invocation.


indexbase 0
int pix[800*600]
'
macro pix2d int* (v,x,y,  vv)
=============================
  'v  return pixel pointer supporting read/write
  'x  horizontal coordinate
  'y  vertical coodinate
  'vv sink pixel
  if x>=0 and x<800 and y>=0 and y<600
    @v=@pix(y*800+x)
  else
    int vv=0xffffffff 'value when out of bounds
    @v=@vv
  end if
end macro
'
'TEST
pix2d(1,20)=0xaabbccdd
print hex pix2d(1,20)
print hex pix2d(800,10)

Charles Pegge

#4
To accommodate index expressions, instead of variables or constants:

@v=@pix(y*800+x)
-->
@v=@pix((y)*800+x)


indexbase 0
int pix[800*600]
'
macro pix2d int* (v,x,y,  vv)
=============================
  'v  return pixel pointer supporting read/write
  'x  horizontal coordinate
  'y  vertical coodinate
  'vv sink pixel
  if x>=0 and x<800 and y>=0 and y<600
    @v=@pix((y)*800+x)
  else
    int vv=0xffffffff 'value when out of bounds
    @v=@vv
  end if
end macro
'
'TEST
pix2d(1,20)=0xaabbccdd
print hex pix2d(1,20)
print hex pix2d(800,10)

Eduardo Jorge

Thanks, Charles.
I think I understood how MACROS work
they are a kind of pointers that can define expressions
in this case the macro would be a pointer to another pnteiro
it was stupid of me not to notice this when I returned the address instead of the value

Eduardo Jorge

about index of arrays I think this has to be a first line item in the help file
can generate a lot of confusion, because as it accepts small calculations, the person can think that the internal expreções are totally solved
I took some time having error problems without understanding what was happening

on macros, what I understand is that as pointers do not work in different scopes.
in NAMESPACE for example even putting "::" the variable for which it points will not have the same treatment, the variable of work in this case would have to be public

Eduardo Jorge

#7
I went to do a performance test and I liked it a lot
array( -2 to 5 , 3 to 10 )   

int n    =0
int ln   
int l1   =LBoundnx(aN,1)
int l2   =UBoundnx(aN,1)
int c1   =LBoundnx(aN,2)
int c2   = UBoundnx(aN,2)
for  ln= 1 to 1000000000
for L=l1 to l2
for  c=c1 to c2
ARRAYnx_l(AN, L , C)=N
n=n+1
next
next
next



less than 30 seconds

while my vba even failed to complete, and to complete has to 2 zeros less and still takes almost 2 minutes
maybe this will encourage me to complete the things I did not do because of the processing time

Eduardo Jorge

Charles
his proposal using objects took 3 minutes to run with 1 zero less, 6,400,000,000,
an acquaintance from another forum tested in delphi and took 50 seconds the 64 billion of interaction upon matrix
using macros takes 30 seconds the 64 billion interaction

only this macro is breaking my head, it's difficult to define its limits and what exactly it will return
in the attempt posted here I defined an int B and put B as the matrix index,
and it worked,
and now I try INT A = (AN) * 10 and the macro returns me the value of A


even though it is a dirty solution as you said, I still prefer to try a solution using macros

Charles Pegge

Eduardo,

There is no problem, if you are comfortable using macros, and customising them. The important thing is to ensure that your code is readable, and that you will still be able to understand it six months from now :)

Eduardo Jorge

#10
charles
would probably be just a dumb question, but could not create an internal macro in the compiler to recognize matrices indexes?

the macros are called by name,
then it would have to have one for each array, but if called by a set 1 only "[] []" "(,)" could serve for all arrays
well, I do not know if it would be viable or possible
I do not like to have something controlled as an object since they are very slow


EDIT========================
I really said bullshit
I forgot the dimensional control of the array
each created matrix would have to have control variables or use elements of the matrix itself for that purpose
after all how are they done in C and Delphi for example?

Mike Lobanovsky

Quote from: Charles Pegge on June 13, 2018, 06:12:42 PM
indexbase 0
int pix[800*600]
'
macro pix2d int* (v,x,y,  vv)
=============================
  'v  return pixel pointer supporting read/write
  'x  horizontal coordinate
  'y  vertical coodinate

  'vv sink pixel
  if x>=0 and x<800 and y>=0 and y<600
    @v=@pix(y*800+x)
  else
    int vv=0xffffffff 'value when out of bounds
    @v=@vv
  end if
end macro
'
'TEST
pix2d(1,20)=0xaabbccdd
print hex pix2d(1,20)
print hex pix2d(800,10)

Hi Charles,

Please note well that the solution you've suggested implements O2 multidimesional dynamic arrays as row-major entities while since the times of Dartmouth, BASIC arrays and matrices have been stored in memory in a column-major order. Row-major is rather how the C language and its derivatives would store their arrays and matrices, which makes them element-by-element (pointer) incompatible with their genuine BASIC equivalents without prior transposition.

It is of course irrelevant for the O2 user as long as all access to the array contents is done via the array indices. But it makes the O2 arrays and matrices binary incompatible with the modules generated by other BASIC compilers, e.g. an O2 project main code and a PB/FB DLL or vice versa.
Mike
(3.6GHz Intel Core i5 w/ 16GB RAM, 2 x GTX 650Ti w/ 2GB VRAM, Windows 7 Ultimate Sp1)

Charles Pegge

#12
Hi Mike,

Yes, that example is for accessing pixels in x,y order, conforming to the original hardware layout of pixels in a video controller, and scan-lines in a TV set.

FreeBasic is Row-Major, like C. PowerBasic is Column-Major. But these terms are very confusing, so I have dodged the whole issue and left it to the programmer to decide how they like to arrange their arrays. :)

For general tabular layouts, Row then Column, with each row holding contiguous data, makes more intuitive sense. Each row is a record, and each column is a field.

This is the example I was about to provide for Eduardo:


'2D ARRAY USING A TYPE

uses console

type RowType
  int c[16] 'columns
end type

dim RowType r[100]
int i,j
for i=1 to 100
  for j=1 to 16
    r[i].c[j]=i*10+j
  next
next
'
for i=1 to 10
  for j=1 to 8
    print r[i].c[j] tab
  next
  print cr
next
wait

Eduardo Jorge

I think that this concern with the current type of array of O2 is unnecessary, since it is a visible implementation for the programmer

I myself was ignorant on the subject, and with this knowledge I have been able to improve some routines that I have in Vba

the same solution can be changed with simple change in the calculation of the index.
when this is something internal of the compiler, and transparent to the programmer, then Chales has to decide the course that will take.

Charles, thanks for the example,
this gives a greater margin of examples
I still prefer to implement the macros because they are faster, even though
  more work

Charles Pegge

When traversing an array, you can use a pointer as an alternative to a macro. The pointer is moved instead of recalculating the array index every time an element is accessed. It should be significantly faster!


'TRAVERSING 2D ARRAY USING A POINTER
'INSTEAD OF A MACRO

uses console

dim int ar(100*16)

'macro arr(r,c)
'  ar((r)*16+c)
'end macro

int i,j
int *a
for i=1 to 100
  @a=@ar(i*16) 'set pointer address
  for j=1 to 16
    'arr(i,j)=i*10+j
    a=i*10+j
    @a+=sizeof int 'ptr next element
  next
next
'
for i=1 to 10
  @a=@ar(i*16) 'set pointer address
  for j=1 to 8
    'print arr(i,j) tab
    print a tab
    @a+=sizeof int 'ptr next element
  next
  print cr
next
wait