Почему поймал переполнение?
- Войдите на сайт для отправки комментариев
Вычисляю выражение 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: даже такое явное определение порядка не помогает:
Qty_Lost+=PN_New; // Порядок выполнения Qty_Lost-=PN_Old; // Порядок выполнения Qty_Lost--; // Порядок выполненияПодозреваю компилятор изменил порядок выполнения формулы и начал с вычитания ?
Не мог он такого сделать. Можете посмотреть ассемблерный код и убедиться в этом.
PS: даже такое явное определение порядка не помогает:
Qty_Lost+=PN_New; // Порядок выполнения Qty_Lost-=PN_Old; // Порядок выполнения Qty_Lost--; // Порядок выполнениядавно не было такого глупого вопроса. Возьмите бумажку и посчитайте самый первый вход в цикл....
Кто Вам сказал, что Ваши "правильный" и неправильный" коды идентичны? Ни грамма не так. Сравните:
Вот и смотрите. Самый первый проход, когда 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.
Незачто. Успехов!