Функция, которая возвращает только четные биты из слова - PullRequest
1 голос
/ 14 июня 2019

Я пытаюсь сделать функцию, которая принимает в качестве параметра 16 битов и возвращает из него только четные биты (даже в виде индексов), в основном должно быть возвращено 8 битов.

Например, если у нас есть: yxyx yxyx yxyx yxyx;

Функция должна вернуть: xxxx xxxx;

Я совсем растерялся, но я начал как:

unsigned char function(unsigned short int p){
   unsigned char q=0;
   for(int i=15;i>=0;i--){
      if(i%2==0){
         //now we have somehow to take that bit because it has an even index
      }
   }
return q;
}

Не могли бы вы помочь мне закончить это?

Ответы [ 4 ]

2 голосов
/ 14 июня 2019

Существует множество способов записать этот вид алгоритма.Здесь я пойду с легким для понимания.Но сначала давайте изменим сигнатуру функции, чтобы использовать правильные типы:

#include <stdint.h>

uint8_t function(uint16_t p);

Мы преобразуем 16-разрядное целое число без знака в 8-разрядное, поэтому приведенная выше рекомендуемая подпись.Теперь об алгоритме.

Основная идея состоит в том, чтобы поместить бит, который мы хотим извлечь, в крайнее правое положение, чтобы мы могли получить его, используя & 1, который обнулит все биты, кроме первогоодин.Это:

uint8_t right_most_bit = p & 1;

даст нам этот бит.Теперь мы хотим сохранить этот бит в правильном положении в q.Для этого будет индекс i.Итак:

q = q | (right_most_bit << i);

или просто:

q |= (right_most_bit << i);

Затем нам нужно поместить следующий после следующего бита p в крайнее правое положение.Мы делаем это с помощью:

p = p >> 2;

или короче:

p >>= 2;

Таким образом, возникает проблема создания цикла, так что наш i увеличивается на 1 на каждой итерации,Цикл должен закончиться, когда p равен 0, с тех пор мы знаем, что больше не будет битов, которые можно извлечь.Преимущество заключается в том, что цикл будет выполняться только для минимально необходимого количества итераций.Итак,

for (unsigned i = 0; p != 0; i++)

Мы собрали все это вместе:

for (unsigned i = 0; p != 0; i++) {
    uint8_t right_most_bit = p & 1;
    q |= (right_most_bit << i);
    p >>= 2;
}

Конечно, вы можете упростить это еще больше:

for (unsigned i = 0; p != 0; i++, p >>= 2) {
    q |= ((p & 1) << i);
}

Собрав все это вместе:

uint8_t function(uint16_t p)
{
    uint8_t q = 0;

    for (unsigned i = 0; p != 0; i++, p >>= 2) {
        q |= ((p & 1) << i);
    }
    return q;
}
1 голос
/ 14 июня 2019

Другое решение (я тоже новичок)

#include <stdio.h>

int main()
{
    uint16_t i = 21; /* sample chosen because it's not a full mask */
    uint8_t k = 0;
    int l = 0;
    for (int j = 0; j < 16; j+=2){
        if(i & (1<<j)){
            k = k | 1<<l;
        }
        l++;
    }
    printf("Result: %d\n", k);
    return 0;
}

По общему признанию, на данный момент предлагаются гораздо более элегантные решения, но помощь вам помогла и мне улучшить.

1 голос
/ 14 июня 2019

Используйте некоторые побитовые операции:

char f(short int p) {
    char ans = 0;
    for(int i = 14; i >= 0; i -= 2) {
        ans |= ((p >> i) & 1) << (i / 2);
    }
    return ans;
}    

Шаги:

  • Объявить ans = 0000 0000
  • Цикл i от 14 до 0уменьшая на 2 каждую итерацию
    • Изолируйте нужный бит, сдвинув и выполнив операцию & (побитовое и).
      • Пример: 1100 0000 0000 0000 смещение в 14 раз вправо равно 0000 0000 0000 0011, теперь вы & с 1 (0000 0000 0000 0001) и получаете 0000 0000 0000 0001
    • Сдвиг назад (i / 2) (в данном случае сдвиг 7 раз влево) битов, поскольку ваш ответ равен 8 битам, а не 16.
      • Из последнего примера 0000 0000 0000 0001 становится 0000 0000 1000 0000,Бит был изолирован и теперь находится в правильном положении для ответа.
    • Теперь сделайте ans = ans | last-steps-result, это даст нам 0000 0000 | 1000 0000, так как это or результат1000 0000
  • Возврат ans
0 голосов
/ 14 июня 2019
#include <stdint.h>

uint8_t foo(uint16_t p)
{
    uint16_t tmp;
    uint8_t mask;
    uint8_t result;

    result = 0;
    for (int i = 0; i < 8; i++) {
        tmp     = p >> i;
        mask    = 1 << i;
        result  |= tmp & mask;
    }

    return result;
}

После оптимизации (улучшение примерно в 4 раза с GCC 8.3 с использованием -Ofast):

uint8_t foo(uint16_t p)
{
    uint8_t mask;
    uint8_t result;

    result  = 0;
    mask    = 1;
    for (int i = 0; i < 8; i++) {
        result  |= p & mask;
        mask    <<= 1;
        p       >>= 1;
    }

    return result;
}

Пример:

p = 0xA3B4;
p = 0b1010_0011_1011_0100;
desired output  = 0b0001_0110;

i   = 0;

tmp = 0b1010_0011_1011_0100;
mask    = 0x1;
result  = 0 | (0b1010_0011_1011_0100 & 0x1) = 0b0;
i   = 1;

tmp = 0b101_0001_1101_1010;
mask    = 0x2;
result  = 0b0 | (0b101_0001_1101_1010 & 0x2) = 0b10;
i   = 2;

mask    = 0x4;
tmp = 0b10_1000_1110_1101;
result  = 0b10 | (0b10_1000_1110_1101 & 0x4) = 0b110;
i   = 3;

mask    = 0x8;
tmp = 0b1_0100_0111_0110;
result  = 0b110 | (0b1_0100_0111_0110 & 0x8) = 0b0110;
i   = 4;

mask    = 0x10;
tmp = 0b1010_0011_1011;
result  = 0b0110 | (0b1010_0011_1011 & 0x10) = 0b1_0110;
i   = 5;

mask    = 0x20;
tmp = 0b101_0001_1101;
result  = 0b1_0110 | (0b101_0001_1101 & 0x20) = 0b01_0110;
i   = 6;

mask    = 0x40;
tmp = 0b10_1000_1110;
result  = 0b01_0110 | (0b10_1000_1110 & 0x40) = 0b001_0110;
i   = 7;

mask    = 0x80;
tmp = 0b1_0100_0111;
result  = 0b001_0110 | (0b1_0100_0111 & 0x80) = 0b0001_0110;
i   = 8;

return  0b0001_0110;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...