код для КНОПОК - помогите разобраться

Тема в разделе "Микроконтроллеры AVR", создана пользователем Alexandro77, 26 сен 2019.

Метки:
  1. Asper Daffy

    Asper Daffy Иксперд

    Да, неужели?

    А если проверить? Вот так, например. Запускаем код:
    Код (C++):
    #include <Printing.h>

    uint32_t timePassed(uint32_t t1, uint32_t t2) {
        if (t2>=t1) return t2-t1;
        else return ((1<<(8*sizeof(t1)) - 1) - t1) + t2;
    }

    uint32_t tp(uint32_t t1, uint32_t t2) { return t2-t1; }

    void setup(void) {
        Serial.begin(57600);
        uint32_t first = 0xFFFFFFFF-11;
        uint32_t second = first + 9;
        for (int i = 0; i < 15; i++, first++, second++) {
            printf("timePassed(%lu,%lu) = %lu = %lu\r\n",
                first, second,
                timePassed(first, second),
                tp(first, second));
        }
    }

    void loop(void) {}
     
    Смотрим результат:
    Код (C++):
    timePassed(4294967284,4294967293) = 9 = 9
    timePassed(4294967285,4294967294) = 9 = 9
    timePassed(4294967286,4294967295) = 9 = 9
    timePassed(4294967287,0) = 9 = 9
    timePassed(4294967288,1) = 9 = 9
    timePassed(4294967289,2) = 9 = 9
    timePassed(4294967290,3) = 9 = 9
    timePassed(4294967291,4) = 9 = 9
    timePassed(4294967292,5) = 9 = 9
    timePassed(4294967293,6) = 9 = 9
    timePassed(4294967294,7) = 9 = 9
    timePassed(4294967295,8) = 9 = 9
    timePassed(0,9) = 9 = 9
    timePassed(1,10) = 9 = 9
    timePassed(2,11) = 9 = 9
     
    Как говорится, найдите отличия!

    Ну, так, всё-таки, чем отличается-то? Результат при переполнении, как видим, такой же.
     
    Andrey12 и b707 нравится это.
  2. Asper Daffy

    Asper Daffy Иксперд

    А разве это не одно и тоже? См. тест в моём предыдущем посте.

    Можно было. А можно было и универсально, чтобы и тип подходил любой, и компилятор не ругался. Попробуйте. :)
     
    Andrey12 и b707 нравится это.
  3. b707

    b707 Гуру

    Вот оно как... да, от модератора я такого не ожидал...

    Unixon, на самом деле (MAX_MILLIS-t1) + t2 и t2-t1 для unsigned дают одинаковый резульат, можете убедится на примере,
    Простое вычитаение t2-t1 дает правильный результат в любом случае и все эти заумные конструкции совершенно излишни
     
    Andrey12, Unixon, parovoZZ и ещё 1-му нравится это.
  4. Unixon

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

    Код (C++):
    uint32_t a = 1;
    uint32_t b = 2;
    uint32_t c = b-a;
    uint32_t d = a-b;
    std::cout<<c<<" "<<d<<std::endl;
    [QUOTE]1 4294967295[/QUOTE]
     
    Но это x86-64
     
    Последнее редактирование: 22 ноя 2019
  5. Unixon

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

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

    Ну вообще-то я это сделал чуть выше.
     
  6. Unixon

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

    Да, вы правы, в беззнаковой арифметике все получится само собой.
    Видимо я смотрел на это с точки зрения знаковой арифметики более высокой разрядности, где это бы пришлось учесть явно.
    Кстати, я там еще +1 забыл.
     
  7. Asper Daffy

    Asper Daffy Иксперд

    В знаковой - тоже! Поймите, тут главное слово не "знаковая", а "в дополнительном коде".

    Вот Вам тест для знаковой. В тесте проверяются два случая - переход через смену знака и переход через 0. Смотрите, всё нормально работает:
    Код (C++):
    #include <Printing.h>

    int32_t timePassed(int32_t t1, int32_t t2) {
        if (t2>=t1) return t2-t1;
        else return ((1<<(8*sizeof(t1)) - 1) - t1) + t2;
    }

    int32_t tp(int32_t t1, int32_t t2) { return t2-t1; }

    int32_t first, second;

    void doOneTest(void) {
        for (int i = 0; i < 15; i++) {
            printf("timePassed(%ld,%ld) = %lu = %ld\r\n",
                first, second,
                timePassed(first, second),
                tp(first, second));
                first++;
                second++;
        }
    }

    void setup(void) {
        Serial.begin(57600);
        //
        //    Тест на смену знака
        first = 0x7FFFFFFF-11;
        second = first + 9;
        printf("*** Sign change test\r\n");
        doOneTest();
        //
        //    Тест на переход через 0
        first = -11;
        second = first + 9;
        printf("*** Zero cross test\r\n");
        doOneTest();
    }

    void loop(void) {}
    *** Sign change test
    timePassed(2147483636,2147483645) = 9 = 9
    timePassed(2147483637,2147483646) = 9 = 9
    timePassed(2147483638,2147483647) = 9 = 9
    timePassed(2147483639,-2147483648) = 9 = 9
    timePassed(2147483640,-2147483647) = 9 = 9
    timePassed(2147483641,-2147483646) = 9 = 9
    timePassed(2147483642,-2147483645) = 9 = 9
    timePassed(2147483643,-2147483644) = 9 = 9
    timePassed(2147483644,-2147483643) = 9 = 9
    timePassed(2147483645,-2147483642) = 9 = 9
    timePassed(2147483646,-2147483641) = 9 = 9
    timePassed(2147483647,-2147483640) = 9 = 9
    timePassed(-2147483648,-2147483639) = 9 = 9
    timePassed(-2147483647,-2147483638) = 9 = 9
    timePassed(-2147483646,-2147483637) = 9 = 9
    *** Zero cross test
    timePassed(-11,-2) = 9 = 9
    timePassed(-10,-1) = 9 = 9
    timePassed(-9,0) = 9 = 9
    timePassed(-8,1) = 9 = 9
    timePassed(-7,2) = 9 = 9
    timePassed(-6,3) = 9 = 9
    timePassed(-5,4) = 9 = 9
    timePassed(-4,5) = 9 = 9
    timePassed(-3,6) = 9 = 9
    timePassed(-2,7) = 9 = 9
    timePassed(-1,8) = 9 = 9
    timePassed(0,9) = 9 = 9
    timePassed(1,10) = 9 = 9
    timePassed(2,11) = 9 = 9
    timePassed(3,12) = 9 = 9


    Вы имеете в виду 1LL - не, ну это некрасиво и избыточно. Вы заставили его все 64 бита двигать. Я имел в виду, что можно сделать аккуратно - заставить компилятор подставить туда единицу именно того типа, который нужен, без избыточности. Подумайте как это сделать. Если не получится, я могу потом подсказать.
     
    Andrey12 и ИгорьК нравится это.
  8. Asper Daffy

    Asper Daffy Иксперд

    Пример не про это. Ну, Вы уже, похоже, поняли.
     
  9. Unixon

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

    Это не тот тест, метки времени должны быть uint32, а операции над ними в int64.
    Т.е. безнаковые с периодом 32 бита конвертируем в знаковые 64 и потом делаем вычисления.
    Вчера я с этим сам поигрался, так что заваливать меня примерами не нужно.

    Нужно не единицу поставить, а 0xFF...F сделать определенной длины.
     
  10. offigate

    offigate Нерд

    Ответ был такой:

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

    Пришлось вопрос немного трансформировать (#96)
    • Может ли button.ts когда-либо принять значение 0xFFFFFFFF ?
    • Может ли когда-нибудь millis() после значения 0xFFFFFFFE сразу же, мгновенно, перейти в значение 0?
    Очевидно, что залипание произойдет, если выполнятся оба условия.

    После проведенных проверок я выяснил, что правильные ответы таковы:
    • button.ts никогда не примет значение 0xFFFFFFFF
    • millis() после значения 0xFFFFFFFE всегда переходит в значение 0.
    Таким образом, все приведенные варианты кода (еще раз, на всякий случай: в их неизменном виде) не залипнут никогда. :)
     
  11. Asper Daffy

    Asper Daffy Иксперд

    Простите, но это уже совсем "из другой оперы".

    Мы говорили о переполнении. Этот тест отлично показывает, что операция вычитания нечувствительна к переполнению при знаковой арифметике (а прошлый тест показывал, что и при беззнаковой тоже). Т.е. тесты показали, что для того, чтобы узнать насколько a больше b достаточно вычесть a-b безо всяких танцев с бубнами, и никакое переполнение этому не помешает.

    Вы же теперь начали говорить о совершенно других вещах, не связанных с переполнением (64-битная переменная у Вас не переполняется). Это просто: в огороде бузина, а в Киеве дядько.
    Ну, у Вас же в #119 написано 1ULL?
    Код (C++):
    (((1ULL<<(8*sizeof(t1))) - 1) - t1) + t2
    Вот я и предлагаю Вам попробовать написать туда единицу "правильного размера" и чтобы правильный размер выбрал компилятор. Хорошее упражнение. Не хотите - не делайте, кто я такой, чтобы настаивать.

    P.S. Впрочем "0xFF...F сделать определенной длины" - тоже хорошо - попробуйте хоть то, хоть это.
     
    Последнее редактирование: 22 ноя 2019
    Andrey12 нравится это.
  12. b707

    b707 Гуру

    В такой формулировке - со словами "всегда" и "никогда" - оба ответа бред. Можете пояснить, какие-такие "проверки" привели вас к этому выводу?

    Вся тема вообще парад тупости. Вместо того чтоб заменить сложение времени вычитанием - человек третий день доказывает. что ему удобнее надевать свитер через Ж

    Посмотрел в карточку ТС - возраст 63 года. Не срчтите за эйджизм, но только на моем опыте это уже третий или четвертый случай. когда человек за 60 на все доводы просто тупо повторяет одно и тоже. Убеждать тут бесполезно, а продолжать бессмысленно. Остановится должен тот, кто умнее.
    Отписываюсь.
     
    Последнее редактирование: 22 ноя 2019
    Andrey12, Daniil, SergeiL и ещё 1-му нравится это.
  13. Asper Daffy

    Asper Daffy Иксперд

    b707,
    на ардуино.ру я как-то выкладывал полный список чисел, которым никогда не будет равен millis, если ему не мешать. Но задача-то про коня в вакууме - "нельзя ничего добавлять в код", т.е. как раз "нельзя ничего реального делать". В реальности же, "там задержка, тут задержка" и может произойти всё, что угодно. Мне кажется, тут уже началось просто "сохранение лица" в стиле Великого - "а вот, я всё равно прав на некоторых четырёхразрядных процессорах". Помните такое заявление? :)
     
    Daniil, Andrey12, DetSimen и ещё 1-му нравится это.
  14. b707

    b707 Гуру

    очень интересно. А можно ссылку?
     
    Daniil нравится это.
  15. offigate

    offigate Нерд

    Я ипользовал корректные и строгие формулировки. Причем я вам не хамил ни разу, если вы не заметили еще.

    Кое-что почитал, потом посчитал на Ардуинке, потом - на калькуляторе.

    Вот два ключевых момента, они поддается аналитическому расчету, а это проверка:
    ts1=130, ts2=130, millis()=79=121, time=121.86 ms
    ts1=130, ts2=130, millis()=7A=122, time=122.88 ms
    ts1=130, ts2=130, millis()=7B=123, time=123.90 ms
    ts1=130, ts2=130, millis()=7C=124, time=124.93 ms
    ts1=130, ts2=130, millis()=7D=125, time=125.95 ms
    ts1=130, ts2=130, millis()=7E=126, time=126.98 ms

    ts1=130, ts2=130, millis()=80=128, time=128.00 ms
    ts1=130, ts2=130, millis()=81=129, time=129.02 ms
    ts1=140, ts2=140, millis()=82=130, time=130.05 ms
    ts1=140, ts2=140, millis()=83=131, time=131.07 ms
    ts1=140, ts2=140, millis()=84=132, time=132.10 ms
    ts1=140, ts2=140, millis()=85=133, time=133.12 ms



    ts1=12800, ts2=12800, millis()=31FB=12795, time=12795.90 ms
    ts1=12800, ts2=12800, millis()=31FC=12796, time=12796.93 ms
    ts1=12800, ts2=12800, millis()=31FD=12797, time=12797.95 ms
    ts1=12800, ts2=12800, millis()=31FE=12798, time=12798.98 ms

    ts1=12810, ts2=12810, millis()=3200=12800, time=12800.00 ms
    ts1=12810, ts2=12810, millis()=3201=12801, time=12801.02 ms
    ts1=12810, ts2=12810, millis()=3202=12802, time=12802.05 ms
    ts1=12810, ts2=12810, millis()=3203=12803, time=12803.07 ms
    ts1=12810, ts2=12810, millis()=3204=12804, time=12804.10 ms


    Я уже говорил, что пример рассматриваю как учебный. Надеялся от гур что-то умное услышать, кроме "делай как положено" и ошибочных ответов, когда дело доходит до рассмотрения конкретных деталей.
     
    Последнее редактирование: 22 ноя 2019
  16. Asper Daffy

    Asper Daffy Иксперд

    Вечером поищу
     
    Daniil и DetSimen нравится это.
  17. Unixon

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

    Да, но в дополнительном коде записываются только отрицательные знаковые, к положительным знаковым и беззнаковым дополнительный код не относится.
     
  18. Asper Daffy

    Asper Daffy Иксперд

    Правила "арифметики в дополнительном коде" относятся ко всему. Потому и a-b всегда работает одинаково и переполнение пофиг абсолютно.
     
    Andrey12, parovoZZ и DetSimen нравится это.
  19. b707

    b707 Гуру

    Ок, хорошо
    Я вижу. что уровень дискуссии тут уже выходит на академические высоты. чему я соответсвовать не могу.
    Чтоб не уподобляться некоторым персонажам, никогда не признающим своих ошибок - отмечу что я никогда не вникал столь глубоко в предмет, чтобы знать какие конкретные значения принимает миллис.
    Меня вполне устраивает соблюдение простых правил "делай так, а не иначе"

    Так что всем, кому мои заявления в дискуссии кажутся неверными - можете вообще не принимать их в рассчет
     
    Andrey12 нравится это.
  20. Unixon

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

    Ну вы можете написать
    Код (C++):
    #define MAXINT (-1)
    или
    Код (C++):
    #define MAXINT(type) ((type)-1)
    но в первом случае вы не будете знать длину результата, а во втором тип придется указывать явно. Кроме того для знаковых это будет не максимум, а просто "-1".

    Можно схалтурить:
    Код (C++):
    #define MAX_UINT (~0)
    #define MAX_SINT (~0 >> 1)
    но это уже не арифметический способ и с длиной опять проблемы будут.
     
    Последнее редактирование: 22 ноя 2019