Reputation: 11
I have a task:
Given the array of 7 bytes. Representing it as an array of 8 7-bit words, count the number of words with an odd number of zeros in them.
Here's my code so far. I have a code sample with the check for the number of 1's oddity but can't understand how to check for an odd number of zeros in the word. How can I do it?
data segment
result dw ?
NB dw 04h, 07h, 14h, 23h, 04h, 38h, 3Fh, 2Ah
data ends
code segment
assume cs: code, ds: data
start: mov ax, data
mov ds, ax
lea bx, NB
mov cx, 7
BEG:
mov al, [bx]
test al, 0ffh
jp OK
or add result, 1
loop BEG
quit: mov ax, 4C00h
int 21h
exit: ret
code ends
end start
Upvotes: 1
Views: 542
Reputation: 39411
Given the array of 7 bytes. Representing it as an array of 8 7-bit words, count the number of words with an odd number of zeros in them.
Your current solution is misinterpreting the task description!
For now, you have given the array 8, word-sized elements, whereas the task wants you to deal with 8 elements that are 7 bits wide and importantly those 8 elements have to be packed together in just 7 bytes of memory!
The array in effect is a bitstring that has 56 bits (8*7).
What does it mean to 'count the number of words with an odd number of zeros in them'?
word here is referring to a group of 7 bits, it's confusing I know.
The below snippet uses the bt
(BitTest) instruction to test if a certain bit in a string of bits is ON (CF=1) or OFF (CF=0).
xor bx, bx ; Indexing the bitstring, BX=[0,55]
mov [result], bl
OuterLoop:
mov cl, 7
xor ax, ax
InnerLoop:
bt [array], bx ; Sets CF if bit is ON
cmc ; Makes CF=1 if bit is OFF
adc al, 0 ; Tallies the OFF bits
inc bx
dec cl
jnz InnerLoop
and al, 1 ; Becomes 1 if tally is odd
add [result], al
cmp bx, 56 ; {7, 14, 21, 28, 35, 42, 49, 56}
jb OuterLoop
The above code can easily be written without using that cmc
instruction (see Peter's comment).
Doing so will reveal a substantial speedgain. On my computer, executing the code a thousand times made the execution time drop from 597 µsec to 527 µsec (11% better).
This code will tally based on the inverse condition and subtract (the lowest bit of) the tally from the maximum achievable result.
xor bx, bx ; Indexing the bitstring, BX=[0,55]
mov byte [result], 8
OuterLoop:
mov cl, 7
xor ax, ax
InnerLoop:
bt [array], bx ; Sets CF if bit is ON
adc al, 0 ; Tallies the ON bits
inc bx
dec cl
jnz InnerLoop
and al, 1 ; Becomes 1 if tally is odd
sub [result], al
cmp bx, 56 ; {7, 14, 21, 28, 35, 42, 49, 56}
jb OuterLoop
An alternative solution would extract 7 consecutive bits from the bitstring into a byte and (just like you did) inspect the parity flag PF. An odd number of zeroes in a group of 7 bits means that there will be a complementary even number of ones (PF=1). This solution is more than 4 times faster than the above snippets!
Next is an implementation of this:
result db 0 ; (*)
array db 12h, 34h, 56h, 78h, 9Ah, 0BCh, 0DEh
db 0 ; (*)
...
lea bx, [array-1] ; Start before the array
mov byte [bx], 0 ; Result=0
mov cl, 8 ; 8 elements
NextGroupOf7:
mov ax, [bx]
shr ax, cl
and al, 7Fh ; Keep just 7 bits and define parity flag
setp al ; If parity then AL=1 else AL=0
add [result], al
inc bx
dec cl
jnz NextGroupOf7
(*) The above code reads one byte before the array and reads one byte after the array. We have to make sure that these are addressable.
At the expense of increased codesize, we could split off the first and last iterations and not read outside of the array at all.
In case this should be 8086 code, you can not use the bt
or setp
instructions. Then next change to the 3rd snippet will work:
From:
setp al ; If parity then AL=1 else AL=0
add [result], al
inc bx
to:
jnp .a
inc byte [result]
.a: inc bx
ps. Don't use this jnp
on anything better than 8086 as it will make the loop more than 10 times slower!
Upvotes: 2