Реализация bitRead, неправильная работа pow(); Please help

Тема в разделе "Микроконтроллеры AVR", создана пользователем Сергей777, 8 июл 2016.

Метки:
  1. Сергей777

    Сергей777 Нерд

    Помогите пожалуйста, объяснял ребенку побитовые операторы, понял, что сам ничего не понимаю, вынужден просить помощи.
    Для практики решили воссоздать функцию bitRead (оригинального кода ее в глаза не видел, основывались чисто на ее задачах)
    Вот что у нас получилось, а точнее не получилось. Внедрил в функцию переменную для проверки, и заморочки у нас с функцией pow она упорно не возвращает нам значения которые должна. При передаче в order = 0 отрабатывает как положено в power лежит 1; при order = 1 в power = 2; а вот при order = 2 в power = 3 !!! Что за хрень понять не могу, может где с типами напортачил? ибо pow возвращает значение в double, а я вроде как их пытаюсь запихать в int?

    Код (C++):

    int test =0; // для проверки переменных

    byte bitReadMode(byte num, float order){
      int power = pow(2, order);
      byte a = num & power;
      test = power; // для проверки переменных
      return a;
    }
    bitReadMode(value, 2);

    Serial.println (test);
     
     
  2. ostrov

    ostrov Гуру

    Зачем вы возводите что то в степень для этой задачи?
     
  3. DIYMan

    DIYMan Guest

    Как-то вы мудрёно объясняете ребёнку битовые операции ;) Вы лучше подойдите с другого боку - объясните, что каждая позиция бита в байте - это степень двойки:

    Код (C++):
    0 0 0 0 0 0 0 0 - пустой байт
    теперь представьте, что мы будем двигать единичку справа (от самого младшего бита) налево - к самому старшему. Битов всего 8, нумеруются от 0 до 7. И вот тут как раз для понимания и нужна степень двойки, т.к. мы оперируем двоичной системой. И получается, что: если первый бит установлен, то это число "2 в степени позиции бита" (т.е. 2 в нулевой степени), если второй бит установлен - это число "2 в первой степени" и т.д.

    На примере:

    Код (C++):
    0 0 0 0 0 0 0 1 - число 1 (2^0)
    0 0 0 0 0 0 1 0 - число 2 (2^1)
    0 0 0 0 0 1 0 0 - число 4 (2^2)
    0 0 0 0 1 0 0 0 - число 8 (2^3)
    и т.д.
    После понимания этой закономерности очень просто оперировать снятием/постановкой бита: достаточно знать, на сколько позиций влево сдвинуть единичку, чтобы получить нужную позицию бита в байте:

    Код (C++):

    byte |= (1 << 0) - устанавливаем первый бит в байте
    byte |= (1 << 1) - устанавливаем второй бит в байте
    byte |= (1 << 2) - устанавливаем третий бит в байте
    и т.д.
     
    или - так:

    Код (C++):

    byte |= 1 - устанавливаем первый бит в байте
    byte |= 2 - устанавливаем второй бит в байте
    byte |= 4 - устанавливаем третий бит в байте
    и т.д.
     
    Снимаем биты:

    Код (C++):

    byte &= ~(1 << 0) - снимаем первый бит в байте
    byte &= ~(1 << 1) - снимаем второй бит в байте
    byte &= ~(1 << 2) - снимаем третий бит в байте
    и т.д.
     
    Ну и битовые маски - например, надо установить первый и третий бит в байте. Битовая маска будет "2 в степени 0 И два в степени 2", т.е. 1 | 4 или, что то же самое,
    Код (C++):

    (1 << 0) | (1 << 2)
     
    Если сдвиги для вас непонятны - просто оперируйте десятичными числами степеней двойки
    • 1 - первый бит
    • 2 - второй бит
    • 4 - третий бит
    • 8 - четвёртый бит
    • 16 - пятый бит
    • 32 - шестой бит
    • 64 - седьмой бит
    • 128 - восьмой бит
    Т.е., опять же, чтобы установить второй и четвёртый бит в байте, надо взять маску "2 И 8", т.е.

    Код (C++):

    byte |= (2 | 8); // устанавливаем
    byte &= ~(2 | 8); // снимаем
     
    И не надо никаких bitRead и прочей ардуиновской мути.
     
    ostrov и Airbus нравится это.
  4. ostrov

    ostrov Гуру

    Еще проще: рисуем таблицу 8 столбиков (для случая байта) 2 ряда, в верхнем ряду пишем числа "128, 64, 32, 16, 8, 4, 2, 1", в нижний вписываем двоичное число по биту в клетку. Складываем те числа из верхнего ряда, под которыми стоит единичка, получаем результат. Это наглядно.

    А если вычислять 1 или 0 в заданной позиции числа, то лучше воспользоваться маской. Тогда функция будет выглядеть так:
    Код (C++):
    bool bitReadMode(byte num, int order) {
      return (order & (1 << num));
    }
    Однако, для разбора числа типа float этот способ не подойдет, там придется работать с указателями.
     
    Последнее редактирование: 9 июл 2016
    DIYMan нравится это.
  5. Сергей777

    Сергей777 Нерд

    Ребят, вы не на тот вопрос отвечаете! Я спрашиваю про непонятно почему возникающие отклонения в работе функции pow() ! Сдвиговые операторы эт попозжа, сейчас именно &, и как раз 0 1 2 4 8 16, являются степенями числа 2, для этого мне и нужна эта функция, а она не работает как ей положено. Если бы меня интересовали альтернативы я обязательно бы спросил, я прошу чтобы мне указали на ошибку почему у меня если передать в order = 2 в power оказывается 3 ?!
     
  6. DIYMan

    DIYMan Guest

    Вангую: всё из-за представления чисел с плавающей точкой. Подтверждение: http://forum.arduino.cc/index.php?topic=26152.0

    Если надо в целочисленные степени возводить - пишите свою pow, быстрее и проще. Если надо возводить двойку в степень - ещё проще, битовый сдвиг и всё.

    З.Ы. Ещё ссылок на проблему: https://www.google.ru/search?q=ardu...arduino+pow+site:forum.arduino.cc&newwindow=1
     
    Сергей777 нравится это.
  7. Сергей777

    Сергей777 Нерд

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

    ostrov Гуру

    Вы хотите разобраться с двоичным исчислением или со структурой числа float?