Битовые операции на с++ с помощью __asm
Помогите не могу понять как сделать это с ассемблерной вставкой Переписать в массив те элементы массива слова, которого имеют парную количество единичных битов в пределах от 5-го до и 10-го разрядов
.
#include<iostream>
#include<string>
using namespace std;
int main() {
string mas[4] = { "sad","213","dwer","we234" };
string mas2[4];
_asm {
}
for (int i = 0; i < 4; i++) {
cout << mas2[i] << endl;
}
system("pause");
}
Ответы (2 шт):
Разобъем задачу на несколько кусков - посчитать биты в числе, проверить их четность, сделать цикл.
Начнем с подсчета битов.
Есть два способа сделать эту задачу. Можно взять и посчитать от 5 до 10 разряда биты.
int c = 0; // счетчик
unsigned int n = 1000; // наше число
for (int i = 5; i <10; i++) {
unsigned int r = 1 << i;
if (n & r > 0) {c++;}
}
возможно, в условии нужно написать i<=10, в зависимости от того, "включая 10 бит или нет".
Не думаю, что это будет сложно перевести на ассемблер.
Но можно сделать проще и легче. Есть такая инструкция popCount и она доступна в ассемблерном коде. И вся задача сводиться к двум действиям - вначале все биты, которые не входят в наш диапазон зануляем, а потом с помощью popCount считаем оставшиеся единичные биты. popCount доступна в Intel/AMD процессорах с 2008 года, так что сойдет.
unsigned int n = 1000; // наше число
n = n & 0x07E0; // 0'0111'1110'0000 // c 5 по 10 включительно
int r = popcount(n);
на ассемблерном коде это где то так
and eax, 2016
popcnt eax, eax
ret
В случае Visual Studio нужно подключить #include <intrin.h> и сама функция называется __popcnt.
Если по какой то причине так просто нельзя, можно взять готовый алгоритм подсчета единичных битов
Теперь у нас есть функция, которая умеет считать биты. Проверить, четное ли количество очень просто - по последнему биту (он должен быть нулевым для парного) или использовать % 2 == 0
В принципе, осталось завернуть в цикл и готово решение.
P.S. преподаватель может по другому считать биты (слева на право или с единицы, а не нуля, да и я мог в коде промазать), так что лучше уточнить этот момент персонально, благое дело, это очень легко поправить в коде.
Вариант который мне скинули на кибер форуме
#include<iostream>
#include<string>
using namespace std;
int main() {
string mas[4] = { "sad","213","dwer","we234" };
string mas2[4];
size_t size2 = 0; //размер второго массива
for (int i = 0; i < 4; ++i)
{
//берем два последних байта, т.к. в них находятся биты с 5 по 10
// будем считать, что нумерация битов и байтов начинается с правого края
// при чтении предпоследний символ попадет в младший байт uint16_t, а последний - в старший
// поэтому маска "перевернута"!
uint16_t x = *((uint16_t*) &mas->c_str()[mas[i].size() - 2]); //читаем 2 последних символа, как 16-ричное число
bool f; //признак четности указанных бит
_asm
{
and x, 1110000000000111b //выделяем биты (см выше)
lahf //читаем флажки, нас интересует флаг четности P
and ah, (1<<2) //выделяем бит P
mov f, ah //и результат сохраняем в f
}
if (f)
mas2[size2++] = mas[i]; //если не 0, то сохраняем слово в новый массив
}
for (size_t i = 0; i < size2; i++) {
cout << mas2[i] << endl;
}
system("pause");
}