Плющит мозг, нужен свежий взгляд

Тема в разделе "Arduino & Shields", создана пользователем KindMan, 9 авг 2019.

  1. KindMan

    KindMan Гуру

    Вчера, или даже уже сегодня в районе полуночи, уже плохо соображая, в процессе изготовления подарка на ДР дяде, столкнулся с недостатком опыта в математике и соответствующем мышлении. Задача: для перебора битов в массиве чисел, нужно организовать такую последовательность цифр - 0..7, 0..7, 7..0, 7..0 и всё заново. т.е. два раза от 0 до 7 бита пройтись, два раза в обратном порядке и так по кругу. Не думая, по привычке сворганил всё на IF-ах.
    Код (C++):
    int8_t pos;
    int8_t znak = 1;
    uint8_t steps;

    void setup() {
    Serial.begin(9600);
    }

    void loop() {
      if (pos == 8) {
          if (steps) {
              znak = -1;
              steps = !steps;
              pos = 7;
          } else {
              pos = 0;          
              steps = !steps;
          }
      }
      Serial.println(pos);
      delay(100);
      pos = pos + znak;
      if (pos == -1) {
          if (steps) {
              znak = 1;
              steps = !steps;
              pos = 0;
          } else {
              pos = 7;
              steps = !steps;
          }
      }
    }

    Посмотрел и ужаснулся ...
    Переписал всё на конченных автоматах :)
    Код (C++):
    int8_t pos = -1;
    uint8_t steps = 1;

    void setup() {
    Serial.begin(9600);
    }

    void loop() {
      switch (steps) {
        case 1:
        case 2:
          pos++;
          if (pos == 8) {pos = 0; steps++;}
          if (steps == 3) {pos = 7;}
          break;
        case 3:
        case 4:
          pos--;
          if (pos == -1) {pos = 7; steps++;}
          if (steps == 5) {pos = 0; steps = 1;}
          break;
      }
      Serial.println(pos);
      delay(100);
    }
    Уже лучше ... хотел вчера ночью тему создать, но вставать рано, лёг ...
    Сегодня на работе осенило, какой я тупой и сделал так
    Код (C++):
    uint8_t pos = 8;
    int8_t znak = 1;

    void setup() {
    Serial.begin(9600);
    }

    void loop() {

      Serial.println(pos % 8);
      delay(100);
      pos = pos + znak;
      if (pos == 24) { pos = 23; znak = -1;}
       else
      if (pos == 7) { pos = 8; znak = 1;}
     
    }

    На это уже смотреть можно. Но не оставляет чувство, что можно сделать лучше ... что скажете, комрады?
     
    Daniil и arkadyf нравится это.
  2. Daniil

    Daniil Гуру

    Я бы слово "else" убрал)
     
    KindMan и NikitOS нравится это.
  3. NikitOS

    NikitOS Король шутов Администратор

    Пробела перед скобками нет..
    ...и тут нет...
    ...и тут...
    ...но вдруг... появился...
    [​IMG]
     
    KindMan нравится это.
  4. KindMan

    KindMan Гуру

    Не было, не было… вдруг раз - появился!

    Ну вот, теперь ещё и вы лишаете меня выбора!
     
    Последнее редактирование модератором: 10 авг 2019
    Daniil нравится это.
  5. SergeiL

    SergeiL Оракул Модератор

    Не, else там нужен, ибо красота кода не в его размере, а в его оптимальности :).
    Пускай даже на одну проверку один раз из 16, даже с delay :).
    Но одновременно pos не может быть и 24 и 7.

    А так, мне кажется, более читаемо:
    Код (C++):
    #define STEPS_UP 2
    #define STEPS_DOWN 2
    int8_t pos = 0;
    int8_t znak = 1;

    void setup() {
    Serial.begin(9600);
    }

    void loop() {

      Serial.println(pos & 7);
      delay(100);
      pos += znak;
      if (pos == STEPS_UP*8) { pos = STEPS_DOWN*8-1; znak = -1;}
       else
      if (pos < 0) { pos = 0; znak = 1;}
    }
    Надо только проверить :)
     
    Последнее редактирование модератором: 10 авг 2019
    Daniil и KindMan нравится это.
  6. KindMan

    KindMan Гуру

    Этот делэй для проверки :)

    Я на даче, отдыхаю :)
    Кстати, заметил, что если pos определена как беззнаковая, то прошивка на выходе весит на 40 (точно не помню) байт меньше. Это как так выходит?
     
  7. parovoZZ

    parovoZZ Гуру

    Какая-то проверка на выход за пределы не осуществляется. Тут же все просто - чтобы писать эффективный код, необходимо четко представлять, какие флаги и когда поднимаются в системном регистре у МК.
     
  8. Daniil

    Daniil Гуру

    Я себе бы ответил так:
    "компилятор" компилирует и оптимизирует. Оптимизация включает в себя изменение кода на "шаблоны".
    цикл от 0 до n преобразуется в цикл от 0 до n/4 а внутри цикла операции дублируются 4 раза
    было
    Код (C++):
    for(int i=0; i<n; i++)
    {a[i]=a+i}
    стало
    Код (C++):
    for(int i=0; i<n/4; i=i+4)
    {a[i]=a+i;
    a[i+1]=a+(i+1);
    a[i+2]=a+(i+2);
    a[i+3]=a+(i+3)}
    пределы цикла надо аккуратнее проверить.
    Работа со знаком числа может занимать пару доп. операций на всякие проверки.
     
    SergeiL нравится это.
  9. SergeiL

    SergeiL Оракул Модератор

    Пару. И со знаком, без знака, обычно, нет принципиальной разницы.
    Разница есть, когда появляется float.
     
  10. SergeiL

    SergeiL Оракул Модератор

    Я тоже на даче. Погода хорошая, ходим купаться!
    Стало интересно, по поводу знаковой без знаковой переменной, скомпилировал Ваш код под Uno и свой.
    Ваш код с беззнаковой:
    Код (Text):
    Скетч использует 1744 байт (5%) памяти устройства. Всего доступно 32256 байт.
    Глобальные переменные используют 190 байт (9%) динамической памяти, оставляя 1858 байт для локальных переменных. Максимум: 2048 байт.
    Код моего варианта:
    Код (Text):
    Скетч использует 1738 байт (5%) памяти устройства. Всего доступно 32256 байт.
    Глобальные переменные используют 189 байт (9%) динамической памяти, оставляя 1859 байт для локальных переменных. Максимум: 2048 байт.
     
     
  11. KindMan

    KindMan Гуру

    Только добрался до компьютера. Всё проверил, работает!

    Ваш & тоже занимает места после компиляции меньше чем мой %. Плюс мне приходится присваивать pos = 8, это ещё пара байт :)
    Спасибо! Прихватизирую ваш вариант!
     
  12. SergeiL

    SergeiL Оракул Модератор

    Да было бы за что :).
    Мне тоже было интересно разобраться!
     
  13. qwone

    qwone Гик

    Похоже логика организовать массив констант и тупо перебрать никому в голову не пришла. Этот метод проще и компактнее.
     
  14. Daniil

    Daniil Гуру

    ну, это решение в лоб) хотя, признаюсь, не сообразил)