Necesario: Contador envolvente donde < y > hacer & # 8220; lo correcto & # 8221;

StackOverflow https://stackoverflow.com/questions/458060

  •  19-08-2019
  •  | 
  •  

Pregunta

Necesito el código para un couter que puede desbordarse y donde < > continuar distinguiendo los valores anteriores de los valores posteriores, durante un intervalo definido.

Para aclarar, una posible implementación sería:

Considere dos de estos contadores cur y dut (dispositivo bajo prueba), considere dos funciones:

bool isEarlier(cur, dut)    // Is dut earlier than cur?
bool isLater(cur, dut)

cur y dut son de 16 bits, cur acaba de desbordarse, su valor actual es, digamos 5 . Dependiendo del valor de dut , las funciones devolverían

  • 0 a 16384: isEarlier - > (cur < dut) , isLater - > (cur > dut)
  • 16384 a 32768: isEarlier - > falso, isLater - > cierto
  • 32768 a 49152: no válido, error de registro
  • 49152 a 65536: isEarlier - > cierto, isLater - > falso

Puedo escribir el código yo mismo, no hay problema. Solo soy vago. Sé, de hecho, que hay algo así en PostgreSQL (envoltura de identificadores de transacción), simplemente no pude localizar la función que realmente lo hace. Estoy bastante seguro de que hay algo así en el kernel de Linux, probablemente una macro. Pero ni la búsqueda de códigos de Google, ni grep over / usr / include / linux podrían subirlo. ¿Alguna idea de dónde está?

Papel aclarado de cur y dut. El " inválido " está ahí como salvaguarda. A medida que las diferencias entre cur y dut aumentan, la función finalmente se queja.

¿Fue útil?

Solución

Creo que estás hablando de manejar la envoltura del círculo numérico correctamente. Es bastante fácil, en realidad.

Esto no hace exactamente lo que dijiste (no estoy seguro de por qué tienes ese '' intervalo de excepción ''), pero:

typedef unsigned short uint16_t;
typedef signed short int16_t;
// abstract out 16-bit types in case "short" doesn't correspond to 16bits

bool isEarlier(uint16_t a, uint16_t b)
{
   int16_t diff = a-b;
   return diff < 0;
}
bool isLater(uint16_t a, uint16_t b)
{
   int16_t diff = a-b;
   return diff > 0;
}

editar : tiene un " punto de ramificación " en diff = -32768, de modo que si a = 5 yb = 32772, diff = -32767, que es menor que 0 y, por lo tanto, 5 es '' anterior '' que 32772. Si a = 5 yb = 32774, diff = -32769 = 32767 que es mayor que 0 y por lo tanto 5 es " más tarde " que 32774. Esto define " anterior " y "más tarde" en el sentido de (a) la matemática más simple, y (b) debido a que los contadores envolventes pueden interpretarse como que tienen múltiples soluciones mod 65536, selecciona la solución de a y b que están "más cercanas". entre sí con respecto al círculo numérico.

Si a y b difieren en 32768, entonces están igualmente separados y la matemática simple se usa para elegir más fácilmente ... esto '' viola '' la propiedad antisimétrica de " anterior " y "más tarde" en el sentido de que isLater (5,32773) es verdadero e isLater (32773,5) también es cierto. Pero, ¿cómo saber si " 5 " representa un recuento de 5, o '' 5 '' representa un recuento de 65541? (al igual que abs (-32768) == -32768 da una respuesta extraña sin sentido) Si desea mantener la antisimetría, p. isLater (b, a) == isEarlier (a, b), siempre puede hacer esto:

bool isLater(uint16_t a, uint16_t b)
{
   int16_t diff = b-a;
   return diff < 0;
}

Si desea sesgar el punto de ramificación en una dirección para que suceda en -32768 + K, use esto en su lugar:

bool isEarlier(uint16_t a, uint16_t b)
{
   int16_t diff = a-b-K;
   return diff < -K;
}
bool isLater(uint16_t a, uint16_t b)
{
   int16_t diff = b-a-K;
   return diff < -K;
}

Esto ya no usa el más cercano; si, por ejemplo, K = 12768 y a = 5, entonces para b = 6,7,8,9, ... 20005, isEarlier (a, b) e isLater (b, a) serán verdaderas, y para b = 20006, 20007, ... 65534, 65535, 0, 1, 2, 3, 4, 5 isEarlier (a, b) e isLater (b, a) serán falsos.

Usted tiene una elección particular de intervalos que es diferente de la lógica que uso con números envolventes. Las funciones definidas aquí no satisfarían sus necesidades como se indicó, pero encuentro esas elecciones de intervalo un poco peculiares. ¿Quizás podría explicar cómo los determinó?

Otros consejos

Primero calcule la diferencia, luego verifique en qué ventana cae.

Dado que es tan simple y los tamaños de las ventanas pasadas / futuras / de error varían, debe hacerlo usted mismo.

Ok, para el registro. Aquí está mi solución, esto es lo que quise decir:

#include <stdint.h>


void increase_cyclic_counter (uint16_t *cnt)
{
#ifdef CYCLIC_COUNTER_EXPLICIT_WRAP
    if (*cnt < 2^16-1)
        *cnt++;
    else
        *cnt = 0;
#else
    *cnt++;
#endif
}


#define SAME 1
#define LATER 0
#define EARLIER 2
#define FORBIDDEN -1

/* dut (device under test) is tested against cur
 * returns:
 *    EARLIER (LATER) if dut happened earlier (later) in the sequence than cur
 *    SAME            if dut == cur
 *    FORBIDDEN       if dut and cur are that far away in the cyclic sequence
 *                    that no unambigious jugement is possible
 *
 * The basic idea is the same as with two-character year codes, where 
 * '97' stands for 1997 and '11' stands for 2011. '50' is regarded as 
 * too ambigous and therefore rejected.
 *
 * The implementation splits the short integer range 0-65535 into 4 parts:
 *   0-16383, 16384-32767, 32768-49151, 49152-65536
 * With cur and dut in the same range, normal arithmetics apply, else the 
 * ranges are compared to each other.
 */

int test_cyclic_counter (uint16_t cur, uint16_t dut)
{
    switch (((int)(cur>>14)) - ((int)(dut>>14)))
    {
        case 0:  // same range
            if (dut < cur) 
                return EARLIER;
            else if (dut == cur)
                return SAME;
            else 
                return LATER;

        case 1:
        case -3:
            return EARLIER;

        case 3:
        case -1:        
            return LATER;

        default: 
            return FORBIDDEN;
    }
}

Me parece que lo acabas de escribir :). ¿Por qué no traducir su publicación en algún código C?

Tenga en cuenta que no puede obtener " > " y " < " hacer lo que quiera en C. Se aplican solo a números y no hay sobrecarga del operador. Lo mismo se aplica a su excepción; C no tiene excepciones.

Podría escribir algunas funciones de acceso que tratarían los tipos integrales sin signo de esa manera, y eso no sería difícil. (En C, el desbordamiento no está definido para los tipos integrales con signo, aunque en la mayoría de los sistemas modernos se ajusta). No sería tan difícil.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top