Pergunta

Eu preciso o código para um couter que é permitido ao transbordamento e onde <> continuar a contar os valores anteriores de valores posteriores, por algum intervalo definido.

Para esclarecer, uma possível implementação seria:

Considere dois desses contadores cur e dut (dispositivo em teste), considere duas funções:

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

cur e dut são de 16 bits, cur acaba transbordou, seu valor atual é, digamos 5. Dependendo do valor de dut, as funções voltaria

  • 0-16384: isEarlier -> (cur < dut), isLater -> (cur > dut)
  • 16384-32768: isEarlier -> false, isLater -> true
  • 32.768-49.152: inválido, erro de registo
  • 49.152-65.536: isEarlier -> true, isLater -> false

Eu posso escrever o código de mim mesmo, não há problema. Eu sou apenas preguiçoso. Eu sei para fato de que há algo parecido em PostgreSQL (ids de transação envoltório), eu simplesmente não conseguia localizar a função que realmente faz isso. Tenho a certeza que existe algo parecido no kernel do Linux, provavelmente um macro. Mas neighther Google codesearch, nem grep sobre / usr / include / linux poderia transformá-lo para cima. Alguma idéia onde é?

O papel Esclarecido de cur e dut. O "inválido" está lá como uma salvaguarda. Como as diferenças entre cur e dut se tornar maior, a função, eventualmente, reclama.

Foi útil?

Solução

Eu acho que você está falando sobre como lidar com a envolvente do círculo número corretamente. É muito fácil, na verdade.

Esta não faz exatamente o que você disse (não sei por que você tem que intervalo "exceção"), mas:

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 : este tem um "ponto de ramificação" no diff = -32768, de modo que se a = 5 e b = 32772, diff = -32767 que é inferior a 0 e, portanto, 5 é " mais cedo" que 32772. Se a = 5 e b = 32.774, diff = -32769 = 32767, que é maior do que 0 e, portanto, 5 é 'depois' do que 32774. Isto define 'anterior' e 'posterior', no sentido de (a ) a matemática simples, e (b) porque os contadores de wraparound podem ser interpretadas como tendo várias soluções mod 65536, que capta a solução de a e b, que são "mais próximo" uns com os outros no que diz respeito ao número de círculo.

Se a e b diferem por 32768, em seguida, eles são igualmente distantes e simples matemática é usada para pegar mais fácil ... esta "viola" a propriedade anti-simétrica de "antes" e "depois" no sentido de que isLater (5 , 32773) é verdadeiro e isLater (32773,5) também é verdadeiro. Mas como você sabe se o "5" representa uma contagem de 5, ou "5" representa uma contagem de 65541? (Assim como abs (-32768) == -32768 dá uma resposta sem sentido ímpar) Se você deseja manter antissimetria por exemplo isLater (b, a) == isEarlier (a, b), então você sempre pode fazer isso:

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

Se você deseja influenciar o ponto de ramificação em uma direção para acontecer em -32768 + K, então use este em vez disso:

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;
}

Isto já não usa mais próximo; Se, por exemplo, K = 12768, e a = 5, em seguida, para b = 6,7,8,9, ... 20005, isEarlier (a, b) e isLater (b, a) será verdadeiro, e por b = 20,006, 20,007, ... 65534, 65535, 0, 1, 2, 3, 4, 5 isEarlier (a, b) e isLater (b, a), vai ser falsa.

Você tem uma escolha particular de intervalos que é diferente da lógica que eu uso com números envolventes. As funções definidas aqui não iria atender às suas necessidades como foi dito, mas acho que essas escolhas de intervalo um pouco peculiar. Talvez você poderia explicar como você determinou eles?

Outras dicas

Em primeiro lugar calcular a diferença, então verificar em qual janela cai.

Uma vez que é tão simples e os tamanhos do passado / futuro / janelas de erro variam, você tem que fazê-lo sozinho.

Ok, para o registro. Aqui está a minha solução, é isso que eu quis dizer:

#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;
    }
}

Parece-me que você escreveu apenas que :). Por que não traduzir o seu post em algum código C?

Tenha em mente que você não pode começar ">" e "<" para fazer o que quiser em C. Eles aplicam-se apenas números, e não há sobrecarga de operadores. A mesma coisa se aplica ao seu exceção; C não tem exceções.

Você poderia escrever algumas funções de acesso que tratam tipos integrais não assinados que maneira, e isso não seria difícil. (Em C, estouro é indefinido para tipos integrais assinados, embora na maioria dos sistemas modernos que envolve em torno.) Não seria tão difícil.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top