Search code examples
c++assemblyvisual-c++x86masm

Count array elements where there are significant 0 bits (below the highest 1 bit)


An array of 3 bytes is specified. Count the number of bytes where there's a zeros after any one. i.e. where the bits below the most-significant 1 are not all 1.

{00000100, 00000011, 00001000} - for this array the answer is 2.

My code gives 1, but it is incorrect; how to fix that?

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    int res = 0, res1 = 0;
    _int8 arr[3] = { 4, 3, 8 };
__asm {
    mov ecx, 3 
    mov esi, 0
    start_outer:
        mov bx, 8 
        mov al, arr[esi]
    start_inner :
        shl al, 1 
        jnb zero 
        jc one 
    one :
        dec bx к
        test bx, bx
        jnz start_inner 
        jmp end_ 
    zero :
        dec bx 
        test bx, bx
        jz end_
        inc res 
        shl al, 1 
        jnb was_zero 
        jc start_inner 
    was_zero :
        dec bx 
        dec res 
        jmp start_inner 
    end_ :
        inc esi
        loop start_outer
}
cout << res << endl;
system("pause");
}

Solution

  • Next try.

    Please try to explain better next time. Many many people did not understand your question. Anyway. I hope that I understood now.

    I will explain the used algorithm for one byte. Later in the program, we will run simple a outer loop 3 times, to work on all values. And, I will of course show the result in assembler. And, this is one of many possible solutions.

    We can observe the following: Your satement "Count the number of bytes where there's a zeros after any one." means, that you want to count the number of transition of a bit from 1 to 0 in one byte. And this, if we look at the bits from the msb to the lsb. So, from left to right.

    If we formulate this vice versa, then we can also count the number of transitions from 0 to 1, if we go from right to left.

    A transition from 0 to 1 can always be calculated by "and"ing the new value with the negated old value. Example:

    OldValue NewValue NotOldValue And
           0 0        1           0
           0 1        1           1   --> Rising edge
           1 0        0           0
           1 1        0           0
    

    We can also say in words, if the old, previous vale was not set, and the new value is set, then we have a rising edge.

    We can look at one bit (of a byte) after the other, if we shift right the byte. Then, the new Value (the new lowest bit) will be the LSB. We remember the old previous bit, and the do the test. Then we set old = new, read again the new value, do the test and so on and so on. This we do for all bits.

    In C++ this could look like this:

    #include <iostream>
    #include <bitset>
    
    using byte = unsigned char;
    
    byte countForByte(byte b) {
        // Initialize counter variable to 0
        byte counter{};
    
        // Get the first old value. The lowest bit of the orignal array entry
        byte oldValue = b & 1;
    
        // Check all 8 bits
        for (int i=0; i<8; ++i) {
    
            // Calculate a new value. First shift to right
            b = b >> 1;
    
            // Then mask out lowest bit
            byte newValue = b & 1;
    
            // Now apply our algorithm. The result will always be 0 or one. Add to result
            counter += (newValue & !oldValue);
    
            // The next old value is the current value from this time
            oldValue = newValue;
        } 
        return counter;
    }
    
    int main() {
        unsigned int x;
        std::cin >> x;
        std::cout << std::bitset<8>(x).to_string() << "\n";
        byte s = countForByte(x);
        std::cout << static_cast<int>(s) << '\n';
        return 0;
    }
    

    So, and for whatever reason, you want a solution in assembler. Also here, you need to tell the people why you want to have it, what compiler you use and what target microprocessor you use. Otherwise, how can people give the correct answer?

    Anyway. Here the solution for X86 architecture. Tested wis MS VS2019.

    #include <iostream>
    
    int main() {
        int res = 0;
        unsigned char arr[3] = { 139, 139, 139 };
    
        __asm {
                mov esi, 0;         index in array
                mov ecx, 3;         We will work with 3 array values
    DoArray:
                mov ah, arr[esi];   Load array value at index
                mov bl, ah;         Old Value
                and bl, 1;          Get lowest bit of old value
    
                push ecx;           Save loop Counter for outer loop
                mov ecx, 7;         7Loop runs to get the result for one byte
    DoTest:
                shr ah, 1;          This was the original given byte
                mov al, ah;         Get the lowest bit from the new shifted value
                and al, 1;          This is now new value
                not bl;             Invert the old value
                and bl, al;         Check for rising edge
                movzx edi, bl
                add res, edi;       Calculate new result
                mov bl, al;         Old value = new value
                loop DoTest
    
                inc esi;            Next index in array
                pop ecx;            Get outer loop counter
    
                loop DoArray;       Outer loop
        }
        std::cout << res << '\n';
        return 0;
    }
    

    And for this work, I want 100 upvotes and an accepted answer . . .