Реализация решения задачи с одномерным массивом 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 шт):
Просто аккуратненько расписать, и никаких проблем...
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 // восстанавливаем значение стека
}