Реализация решения задачи с одномерным массивом Assembler

С помощью ассемблерной вставки в C++ надо реализовать следующую задачу: В массиве из 10 чисел обнулить все отрицательные элементы, если сумма их модулей меньше суммы положительных элементов. Написал такой код, но результат не радует... Почему то меняется только первый элемент массива на выводе, и то выдает степени двойки либо 0. Хотелось бы, чтобы кто-нибудь указал на ошибки и помог с реализацией. :)

#include <iostream>
#include <conio.h>
using namespace std;

void fillArray(int*, int);
void showArray(int*, int);

int main() {
    const int n = 10;
    int a[n];
    fillArray(a, n);
    __asm {
            mov ecx, n
            lea edi, a
            mov esi, edi
            mov ebx, 0
            mov edx, 0

            check:
            mov eax, [esi]
            add esi, 1
            cmp eax, 0
            jl sum_minus
            jpe sum_plus

            sum_minus :
            add ebx, eax
            cmp esi, 10
            jl check
            jpe modul

            sum_plus :
            add edx, eax
            cmp esi, 10
            jl check
            jpe modul

            modul :
            neg ebx
            cmp ebx, edx
            jl zero_check

            zero_check :
            mov eax, [edi]
            cmp eax, 0
            jl zero_make
            jpe plus_const

            zero_make :
            mov [edi], 0
            cmp edi, 10
            jl go
            jpe finish

            go :
            add edi, 1
            jmp zero_check

            plus_const :
            mov [edi], eax
            cmp edi, 10
            jl go
            jpe finish

            finish :
    }
    cout << "New array:" << endl;
    for (int i = 0; i < 10; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

void fillArray(int* a, int n) {
    for (int i = 0; i < 10; i++) {
        cout << "Enter the " << i + 1 << " array element..." << endl;
        cin >> a[i];
    }
    cout << "Your array: ";
    for (int i = 0; i < 10; i++) {
        cout << a[i] << " ";
    }
    cout << endl;
}

Ответы (2 шт):

Автор решения: Harry

Просто аккуратненько расписать, и никаких проблем...

int main()
{
    const int n = 10;
    int a[n];
    fillArray(a, n);

    int ng = 0, ps = 0;

    __asm {
        mov ecx, n
    loop1:
        mov eax, [a + ecx*4 - 4]
        cmp eax, 0
        jge next1
        neg eax
        add ng, eax
        jmp next2
    next1:
        add ps, eax
    next2:
        loop loop1
        mov eax, ng
        cmp eax, ps
        jge quit
        mov ecx, n
    loop2:
        mov eax, [a + ecx*4 - 4]
        cmp eax, 0
        jge next3
        mov [a + ecx*4 - 4], 0
    next3:
        loop loop2

    quit:
    }


    cout << "New array:" << endl;
    for (int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

В loop1 накапливаем суммы модулей и положительных (переменные ng и ps). Затем сравниваем, и во втором цикле, если нужно, обнуляем... Сделано для VC++, с другими ассемблерами я не очень знаком...

→ Ссылка
Автор решения: Илья К

Ты пишешь "правильно" но "плохо", суть ассемблера в том чтобы действие выполнялось так быстро как это только возможно, иначе нет смысла писать на ассемблере вообще.

__asm {
// пушим два нуля и теперь в стеке у нас есть две нулевые переменные
push 0
push 0

// устанавливаем счетчик и сразу декрементируем его на единицу
mov ecx, n
dec ecx

SumMod: 
    mov eax, [a + ecx * dword]  // загружаем число
    mov edx, eax                // копируем число
    neg eax                     // получаем негативное число
    cmovs eax, edx
    // возвращаем в регистр EAX копию числа только при условии что негативное число 
    // отрицательное, таким образом после этой процедуры EAX всегда будет положительным,
    // и как следствие отпадает надобность в условном переходе,
    // функция стала проще, быстрей и наглядней

    bt  edx, 1Fh  // помещаем знаковый бит во флаг переполнения 
    sbb edx, edx
    // вычитаем EDX из самого себя с учетом флага переполнения, и получаем
    // -1 для всех случаев когда число положительно
    // и 0 для всех случаев когда число отрицательно

    add [esp + edx * dword + dword], eax
    // суммируем полученное число с одним из двух значений в стеке,
    // при этом с каким именно определяется значением регистра EDX
    // снова мы "схлопнули" две ветви кода в одну
    dec ecx
jns SumMod

pop eax         // загружаем модуль отрицательных чисел
cmp eax, [esp]  // сравниваем его с модулем положительных чисел
jnc exit        // покидаем процедуру если отрицательный модуль больше

// настраиваем начальные значения цикла
mov ecx, n
xor edx, edx
dec ecx

ReSaveData: 
    mov eax, [a + ecx * dword]  // загружаем число
    test  eax, eax              // тестим его и узнаем его знак
    cmovs eax, edx
    // загружаем в EAX нулевое значение из EDX, если число отрицательно
    // теперь ЕАХ всегда содержит либо положительное число либо ноль

    mov [a + ecx * dword], eax
    dec  ecx
jns ReSaveData

exit:
    pop eax  // восстанавливаем значение стека
}
→ Ссылка