Почему поймал переполнение?
- Войдите на сайт для отправки комментариев
Вычисляю выражение L=L+New-Old-1; Если не использовать промежуточную переменную delta=New-Old-1; L=L+delta; то возникает переполнение .
Отрицательных чисел в явном виде не создаю, New приходит ко мне строго как беззнаковое uint32_t и всегда больше Old хотя на 1 или на 2. Подозреваю компилятор изменил порядок выполнения формулы и начал с вычитания ? Значение New в первом цикле =0, а после вычитания 1 переходит что-ли в -1, те 0xFF FF FF FF ?
При использовании промежуточной переменной переполнения нет, пытался ставить скобки для изменения порядка операции, но не помогает тк компилятор может оптимизировать на свое усмотрение.
Как принципиально избежать таких ошибок кроме введения дополнительных переменных и разбивания формулы на несколько операций - сначала сложение, а вторыи и третьим этапом вычитания?
"Правильный"
uint32_t PN_New=0; uint32_t PN_Old=0, Qty_Lost=0; uint32_t delta; int CountW=0; void setup(void) {Serial.begin(115200); } void loop(void) { PN_New++; // номер текущ цикла delta=PN_New-PN_Old-1; PN_Old=PN_New; // номер предыдущего цикла Qty_Lost=Qty_Lost+delta; //Qty_Lost=Qty_Lost+PN_New-PN_Old-1; // if(CountW ++ >5) {CountW=0; PN_New++; } Serial.print("QTY "); Serial.println(Qty_Lost); } /* QTY 0 QTY 0 QTY 0 QTY 0 QTY 0 QTY 0 QTY 0 QTY 1 QTY 1 QTY 1 QTY 1 QTY 1 QTY 1 QTY 1 QTY 2 QTY 2 QTY 2 QTY 2 QTY 2 QTY 2 QTY 2 QTY 3 QTY 3 QTY 3 QTY 3 QTY 3 QTY 3 QTY 3 QTY 4 QTY 4 QTY 4 */
"Неправильный"
uint32_t PN_New=0; uint32_t PN_Old=0, Qty_Lost=0; uint32_t delta; int CountW=0; void setup(void) {Serial.begin(115200); } void loop(void) { PN_New++; // номер текущ //delta=PN_New-PN_Old-1; PN_Old=PN_New; // номер предыдущего // Qty_Lost=Qty_Lost+delta Qty_Lost=Qty_Lost+PN_New-PN_Old-1; // if(CountW ++ >10) {CountW=0; PN_New++; } Serial.print("QTY "); Serial.println(Qty_Lost); } /* QTY 4294967295 QTY 4294967294 QTY 4294967293 QTY 4294967292 QTY 4294967291 QTY 4294967290 QTY 4294967289 QTY 4294967288 QTY 4294967287 QTY 4294967286 QTY 4294967285 QTY 4294967284 QTY 4294967283 QTY 4294967282 QTY 4294967281 QTY 4294967280 QTY 4294967279 QTY 4294967278 QTY 4294967277 QTY 4294967276 QTY 4294967275 */
"Скобки не защитили от переполнения: "
uint32_t PN_New=0; uint32_t PN_Old=0, Qty_Lost=0; uint32_t delta; int CountW=0; void setup(void) {Serial.begin(115200);} void loop(void) { PN_New++; // номер текущ //delta=PN_New-PN_Old-1; PN_Old=PN_New; // номер предыдущего // Qty_Lost=Qty_Lost+delta Qty_Lost=(Qty_Lost+(PN_New-PN_Old)) -1; // Изменен порядок вычисления if(CountW ++ >10) {CountW=0; PN_New++; } Serial.print("QTY "); Serial.println(Qty_Lost); }
PS: даже такое явное определение порядка не помогает:
Подозреваю компилятор изменил порядок выполнения формулы и начал с вычитания ?
Не мог он такого сделать. Можете посмотреть ассемблерный код и убедиться в этом.
PS: даже такое явное определение порядка не помогает:
давно не было такого глупого вопроса. Возьмите бумажку и посчитайте самый первый вход в цикл....
Кто Вам сказал, что Ваши "правильный" и неправильный" коды идентичны? Ни грамма не так. Сравните:
Вот и смотрите. Самый первый проход, когда PN_New и PN_Old оба равны 0.
В верхнем коде перед последней строкой delta равна 0
В нижнем коде перед последней строкой "PN_New - PN_Old - 1" равно -1 (с точностью до беззнаковости, конечно)
Т.е. у Вас просто два разных кода, которые работают именно так, как написаны и выдают разные результаты.
Вот и смотрите. Самый первый проход, когда PN_New и PN_Old оба равны 0.
В верхнем коде перед последней строкой delta равна 0
В нижнем коде перед последней строкой "PN_New - PN_Old - 1" равно -1 (с точностью до беззнаковости, конечно)
Т.е. у Вас просто два разных кода, которые работают именно так, как написаны и выдают разные результаты.
Наверное на меня напал "тупизм", но код с первого взгляда для меня эквивалентен.
В верхнем фрагменте отдельно вычисляется delta=New+Old-1; (строка 05 в цитате Вашего кода) и вторым действием суммируется с Qty=Qty+delta; В нижнем фрагменте (строка 14) сразу же вычисляется Qty=Qty+New+Old-1; Присваивания Old=New; имхо на суть дела не влияют и переполнение возникает уже в первом проходе цикла.
Прошу Вас не обижаться на меня, но пока не могу понять суть моей ошибки.
Наверное на меня напал "тупизм"
Похоже на то.
Давайте, так (я своему внуку так всегда говорю). Печатаешь текст на бумаге, ставишь палец на первую строчку и идёшь по коду, записывая на полях всё, что происходит. Поехали:
Изначально оба PN_New и PN_Old равны 0.
Незачто. Успехов!