Parity of a number (Assembly) [duplicate]

2019-08-13 18:36发布

问题:

This question already has an answer here:

  • Parity of a number (Assembly 8086) 5 answers

So I'm trying to separate an octet by parity and I don't quite understand how the conditional jumps work(I tried it separately and I don't understand how it works it)

Here is what I came up with:

bits 32
global start
extern exit,printf
import exit msvcrt.dll
import printf msvcrt.dll

segment data use32 class=data

    s db '1', '2', '3', '4','5','7','8','9' ; declararea sirului initial s
l   equ $-s ; stabilirea lungimea sirului initial l
    d1 times l db 0
    d2 times 1 db 0
format db "%s", 0

segment code use32 class=code

start:
mov ecx, l
    mov esi, 0
    jecxz Sfarsit
Repeta:
    ;loop so it gets all the elements from s
mov al, [s+esi]
    mov bl,al
    sub bl,'0'
    cmp bl,2; if is even adds it to d1
    JP et2
    mov [d1+esi], al
inc esi
et2:
    mov bl,al
    sub bl,'0'
    cmp bl,2; if is odd adds it to d2
    JP et1
    mov [d2+esi], al
    inc esi
et1:
    loop Repeta
Sfarsit: ;terminarea programului
    ;Daca dorim si afisarea sirului d, avem urmatoarele:
    push dword d1 ; punem parametrii pe stiva de la dreapta la stanga
    push dword format
    call [printf] ;apelam functia printf
    add esp, 4 * 2 ; eliberam parametrii de pe stiva
    ; exit(0)
    push dword d2 ; punem parametrii pe stiva de la dreapta la stanga
    push dword format
    call [printf] ;apelam functia printf
    add esp, 4 * 2 ; eliberam parametrii de pe stiva
    ; exit(0)
    push dword 0 ; push the parameter for exit onto the stack
    call [exit] ; call exit to terminate the program

I think the problem is the JP but I'm not completely sure.

回答1:

    cmp bl,2; if is even adds it to d1
    JP et2

cmp in this case does temp = bl - 2 and throws away the result, but keeps the flags affected (same way as sub bl,2 would affect them).

And jp is "jump parity", which means it will jump when PF=1, it has also alias jpe or "jump when even".

But that's about bit-parity of the low 8 bits of result, i.e. it counts number of "1" values in low 8 bits of result and sets PF=1 when there's even number of ones. As you use only 8 bits in the arithmetic flag setting instruction (cmp), the whole result is used to calculate PF, but if you would do for example cmp ebx,2, it would have same result in PF, as only 8 bits of result are used to count ones.

In your case the values processed (in binary):

bl          temp (low 8b)    PF
0001 (1)    11111111 (-1)    1 (8 mod 2 = 0)
0010 (2)    00000000 (0)     1 (0 mod 2 = 0)
0011 (3)    00000001 (1)     0 (1 mod 2 = 1)
0100 (4)    00000010 (2)     0 (1 mod 2 = 1)
0101 (5)    00000011 (3)     1 (2 mod 2 = 0)
0111 (7)    00000101 (5)     1 (2 mod 2 = 0)
1000 (8)    00000110 (6)     1 (2 mod 2 = 0)
1001 (9)    00000111 (7)     0 (3 mod 2 = 1)

So bl values 1, 2, 5, 7, 8 will take jp jump.

If you want to test bl if the value is even (bl mod 2 = 0), then you need:

    test bl,1           ; mask-out all bit except the lowest one
    jz   even_value     ; when lowest bit is zero, value is even

The test instruction does temp = bl AND 00000001, and throws away result (temp), keeps only flags. Binary values are even, when their lowest digit (bit) is zero, because that one has value 20 = 1, so that's the one which makes odd values possible. When you bit-wise mask the original value against 00000001, you keep only the lowest bit, so jz "jump zero" will happen when that lowest bit was zero -> value was even.


also probably some more problems you will encounter:

d1 times l db 0
d2 times 1 db 0    ; probably "times l db 0" meant?

And you wanted to split values into d1 / d2 when they are even odd? But you are using the same index esi, so if you will fix your test, and your "store value into" logic, you will split the values into two arrays:

d1:    '1', 0, '3', 0, '5', '7', 0, '9'
d2:    0, '2', 0, '4', 0, 0, '8', 0

And your current code will store only values which set PF=0, but into both arrays, as both your branches have identical calculation.

To get the arrays as described above (with odd/even values, on their original index) you can do:

    mov   edi,d1        ; target array ptr for odd values
    mov   edx,d2        ; target array ptr for even values
    test  al,1          ; test if al has even value
      ; you can test directly the ASCII digit, '0' = 0x30 = even
    cmovz edi,edx       ; edi = target array ptr
    mov   [edi+esi],al  ; store AL into desired array

... and I will rather not even check code below that loop, but I think you should execute it in debugger, and single-step over each instruction to see, what it does (very likely NOT, what you did want/expect).