Как обнаружить разницу между счетчиком упаковки и большим отрицательным значением в языке Си

Извиняюсь за мою слабость, так как это мой первый пост на этом форуме. Я пытаюсь обнаружить разницу между упаковочным 32-разрядным счетчиком без знака и большим отрицательным переходом с помощью следующего кода, но компилятор выдает мне ошибку:

ошибка: сравнение всегда верно из-за ограниченного диапазона типа данных [-Werror = type-limit]

Вот мой фрагмент кода:

#define MAX_BACKWARD_JUMP -4294959295 //UINT_MAX - 8000
#define MIN_BACKWARD_JUMP -3600
#define MAX_FORWARD_JUMP   4800000

signed int rtpDelta; //Signed 32-bit
unsigned int currRTPTs, prevRTPTs; //unsigned 32-bit

rtpDelta = currRTPTs - prevRTPTs;

if ((rtpDelta > MAX_BACKWARD_JUMP && rtpDelta < MIN_BACKWARD_JUMP)
|| (rtpDelta > MAX_FORWARD_JUMP))
{
printf("Delta in Timestamps too large\n",rtpDelta);
}

Идея здесь состоит в том, чтобы перехватить недопустимые большие дельты в метках времени RTP. У нас есть текущая метка времени и предыдущая метка времени, полученная от однорангового RTP-клиента. Граничные пределы для недопустимых значений меток времени RTP -4294959295 < rtpDelta < -3600, то есть он должен выдавать ошибку, если дельта меньше -3600 и больше -4294959295, потому что значения, близкие к UMAX_INT, будут рассматриваться как опрокидывание. Что я здесь не так делаю?

5

Решение

Рассматривать:

unsigned int LowerBound = -3600u, UpperBound = 4800000u;

unsigned int difference = currRTPTs - prevRTPTs;

Обратите внимание, что из-за LowerBound, -3600u, будет большое положительное целое число. Теперь, когда математическая разница (рассчитанная без переполнения) меньше -3600 на разумную величину, значение difference будет большим целым числом, и оно будет меньше LowerBound, Кроме того, если разница не становится слишком большой (в отрицательном направлении), то difference останется больше, чем UpperBound,

Аналогичным образом, если разница превышает 4 800 000 на разумную сумму, значение difference будет больше чем UpperBound, Если разница не станет слишком большой, то она останется меньше LowerBound,

Таким образом, в обоих случаях значение difference когда математическая разница находится за пределами желаемых границ (но не слишком сильно) меньше LowerBound и больше чем UpperBound:

if (difference < LowerBound && difference > UpperBound)
printf("Delta in timestamps is outside acceptable bounds.\n");

Обратите внимание, что это не удастся, когда математическая разница превышает -3600u (что составляет 4 294 967 296 — 3600) или меньше 4 800 000 — 4 294 967 296. Таким образом, тест работает, когда разница составляет [-4,290,167,296, 4,294,963,696].

1

Другие решения

В общем, если у вас есть два неподписанных счетчика a а также bсо значениями от 0 до LIMIT-1включительно, с типом данных, способным представлять 2*LIMIT-1, вы можете использовать арифметику по модулю с точкой разделения в середине:

difference = (a + LIMIT - b) % LIMIT;
if (difference <= LIMIT/2) {
/* a = b + difference */
} else {
/* b = a + (LIMIT - difference) */
}

Это обычно иметь LIMIT быть степенью двойки, в этом случае оператор по модулю (% LIMIT) можно заменить двоичным И (& (LIMIT-1)), что намного быстрее на современных процессорах.

Для C целочисленные типы без знака определены в стандартах как имеющие арифметику по модулю (C99, C11 6.2.5p9), поэтому a - b используя любой беззнаковый целочисленный тип для a а также b даст правильные результаты, с LIMIT будучи соответствующим Utype_MAX макрос, определенный в "limits.h" заголовочный файл Например,

const unsigned int  d = (unsigned int)a - (unsigned int)b;
if (d <= UINT_MAX/2)
/* a >= b, a = b + d */
else
/* a < b,  b = a + UINT_MAX - (d - 1) */
2

Мне кажется, что все усложняется без необходимости:

#include <cstdio>
#include <cstdlib>
#include <limits>

#define COMPLICATED 0

#if COMPLICATED

int main()
{
const unsigned MAX_BACKWARD_JUMP = std::numeric_limits<unsigned>::max() - 8000;
const unsigned MIN_BACKWARD_JUMP = 3600;
const unsigned MAX_FORWARD_JUMP = 4800000;
unsigned prevRTPTs = 0;
for(unsigned i = 0; i < 10; ++i) {
unsigned currRTPTs = std::rand();
std::printf("previous = %10d: ", prevRTPTs);
std::printf(" current = %10d: ", currRTPTs);
if(currRTPTs < prevRTPTs) {
// Negative
unsigned rtpDelta = prevRTPTs - currRTPTs;
// Why a range and no threshold?
if(MIN_BACKWARD_JUMP < rtpDelta && rtpDelta < MAX_BACKWARD_JUMP)    {
std::printf("Invalid range: %10d\n", rtpDelta);
}
else {
std::printf("           OK: %10d\n",rtpDelta);
}

}
else {
// Positive
unsigned rtpDelta = currRTPTs - prevRTPTs;
if(MAX_FORWARD_JUMP < rtpDelta) {
std::printf("    Too large: %10d\n",rtpDelta);
}
else {
std::printf("           OK: %10d\n",rtpDelta);
}
}
prevRTPTs = currRTPTs;
}
}

#else

int main()
{
const unsigned MAX_JUMP = 4800000;
unsigned prevRTPTs = 0;
for(unsigned i = 0; i < 10; ++i) {
unsigned currRTPTs = std::rand();
std::printf("previous = %10d: ", prevRTPTs);
std::printf(" current = %10d: ", currRTPTs);
unsigned rtpDelta = currRTPTs - prevRTPTs;
if(currRTPTs < rtpDelta) {
// Negative (Underflow)
rtpDelta = prevRTPTs - currRTPTs;

}
if(MAX_JUMP < rtpDelta) {
std::printf("    Too large: %10d\n",rtpDelta);
}
else {
std::printf("           OK: %10d\n",rtpDelta);
}
prevRTPTs = currRTPTs;
}
}

Примечание: все значения RTPT не имеют знака.

0

Существует только один способ надежной проверки на переполнение: проверьте перед вычислением суммы. Как это:

unsigned old = ..., delta = ...;
if((int)delta > 0) {    //cast to int, because we need to interprete negative numbers here.
if(old > maxvalue - delta) printf("Overflow!\n");    //No signed arithmetic, so we don't trigger undefined behavior.
} else {
if(old < minvalue - delta) printf("Underflow!\n");
}

Важно, чтобы дельта отображалась с правой стороны сравнений.

Что делать, если у вас нет доступа к дельте до ее добавления к сумме? К счастью, вы можете просто восстановить дельту:

unsigned old = ..., new = ...;
unsigned delta = new - old;
//Now you can proceed as above.

Это работает, потому что беззнаковое вычитание действительно является обратным к беззнаковому сложению, нет никаких необратимых случаев или неопределенного поведения, которое может быть вызвано.

0
По вопросам рекламы [email protected]