Reputation: 3
I'm trying to determine if there's a more efficient coding technique I can use for an if statement. I have a bit array that can contain 128 bits, either 0 or 1. Currently, my code looks like this:
if bi(64)='1' or bi(66)='1' or bi(67)='1' or bi(68)='1'
or bi(69)='1' or bi(70)='1' or bi(71)='1' or bi(72)='1'
or bi(73)='1' or bi(74)='1' or bi(75)='1' or bi(76)='1'
or bi(77)='1' or bi(78)='1' or bi(79)='1' or bi(80)='1'
or bi(81)='1';
Obviously this doesn't work, but is there a method I could use to simplify this expression like this or something?
if bi(64) or bi(65) or bi(66) or bi(67) = '1';
I have actually tried the statement above, but the compiler doesn't like it.
Upvotes: 0
Views: 252
Reputation: 11493
RPG doesn't have bit arrays, but it does have character arrays and bit functions. You can write a subprocedure to make something like your proposed syntax workable.
dcl-proc bitSet;
dcl-pi *n ind;
bitarr128 char(16);
ix int(10);
end-pi;
dcl-ds bitarrds;
bitarr char(1) dim(16);
end-ds;
dcl-ds maskds;
*n char(1) inz(x'80');
*n char(1) inz(x'40');
*n char(1) inz(x'20');
*n char(1) inz(x'10');
*n char(1) inz(x'08');
*n char(1) inz(x'04');
*n char(1) inz(x'02');
*n char(1) inz(x'01');
mask char(1) dim(8) pos(1);
end-ds;
dcl-s arrayix int(10);
dcl-s maskix int(10);
bitarrds = bitarr128;
arrayix = ((ix-1)/8)+1;
maskix = %rem((ix-1):8)+1;
return %bitand(bitarr(arrayix): mask(maskix)) <> x'00';
end-proc;
Then use the function like this
if bitSet(bi:61) or bitSet(bi:62) or bitSet(bi:63) or
bitSet(bi:64) or bitSet(bi:65) or bitSet(bi:66);
You would have to make sure you didn't pass an out of bounds index, or with a little extra work you could add some exception handling, or even make the function generic enough to handle variable size bit arrays.
Upvotes: 1
Reputation: 453
It might work out like this:
128 bits is 16 bytes. Let's assume that the bits are numbered from left to right, starting from 1st to 128th.
Then
Bit Byte M1 M2
1-8 1 0x00 0x00
9-16 2 0x00 0x00
17-24 3 0x00 0x00
25-32 4 0x00 0x00
33-40 5 0x00 0x00
41-48 6 0x00 0x00
49-56 7 0x00 0x00
57-64 8 0x01 0x01
65-72 9 0x7F 0xE0
73-80 10 0xFF 0x00
81-88 11 0x80 0x00
89-96 12 0x00 0x00
97-104 13 0x00 0x00
105-112 14 0x00 0x00
113-120 15 0x00 0x00
121-128 16 0x00 0x00
M1 set of bytes for the condition
if bi(64)='1' or bi(66)='1' or bi(67)='1' or bi(68)='1'
or bi(69)='1' or bi(70)='1' or bi(71)='1' or bi(72)='1'
or bi(73)='1' or bi(74)='1' or bi(75)='1' or bi(76)='1'
or bi(77)='1' or bi(78)='1' or bi(79)='1' or bi(80)='1'
or bi(81)='1';
and M2 - for the condition
if bi(64) or bi(65) or bi(66) or bi(67) = '1';
define
dcl-c bitMask1 const(x'00000000000000017FFF800000000000');
dcl-c bitMack2 const(x'0000000000000001E000000000000000');
dcl-s bitArr128 char(16);
where bitArr128 is the bit array to be checked.
Then the first condition will be written in the form
if %bitand(bitArr128: bitMask1) <> 0;
and the second - in the form
if %bitand(bitArr128: bitMask2) <> 0;
I’ll say right away that I haven’t tested it myself (personally, it would be easier for me to write such a function in C and include it as a separate module in the RPG program). But try it - it might work.
Naturally, for each check you will need to determine the required bit mask
Upvotes: 0
Reputation: 453
Unfortunately, RPG does not support bitmaps.
We can declare an array of "indicators", but each element of the array will occupy one byte with the boolean value *on (character '1' ) or *off (character '0' )
To work with bits in RPGs there are BIFs - %bitand / %bitnot / %bitor / %bitxor - see how suitable they may be for your purposes.
Upvotes: 0
Reputation: 23823
You don't include your definitions, but I assume that "bit array" really means "indicator array".
dcl-s bi ind dim(128);
You also don't mention how/why you're picking the elements you've shown. Assuming it's always a contiguous range, the %SUBARR built-in function may be of use. And if you are on a supported version of the OS the IN operator makes this easy.
// note this is 64-81, did you mean to leave 65 out of your example?
if '1' in %subarr(bi:64:18);
dsply 'at least one on';
else;
dsply 'all off';
endif;
Upvotes: 2
Reputation: 41208
Something like this should work:
if %scan('1' : bi(64) + bi(65) + bi(66) + bi(67)) > 0;
See the %SCAN function for more information.
Upvotes: 0