Necessario: contatore avvolgibile dove < e > fai & # 8220; la cosa giusta & # 8221;

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

  •  19-08-2019
  •  | 
  •  

Domanda

Ho bisogno del codice per un computer che è autorizzato a traboccare e dove < & Gt; continua a distinguere i valori precedenti dai valori successivi, per un intervallo definito.

Per chiarire, una possibile implementazione sarebbe:

Prendi in considerazione due di questi contatori cur e dut (dispositivo in prova), considera due funzioni:

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

cur e dut sono a 16 bit, cur è appena traboccato, il suo valore attuale è, diciamo 5 . A seconda del valore di dut , le funzioni restituiscono

  • da 0 a 16384: isEarlier - > (cur < dut) , isLater - > (cur > dut)
  • da 16384 a 32768: isEarlier - > false, isLater - > true
  • da 32768 a 49152: non valido, errore di registro
  • da 49152 a 65536: isEarlier - > true, isLater - > false

Posso scrivere il codice da solo, nessun problema. Sono solo pigro. So per certo che c'è qualcosa di simile in PostgreSQL (wrapping degli ID transazione), non sono riuscito a individuare la funzione che lo fa effettivamente. Sono abbastanza sicuro che ci sia qualcosa di simile nel kernel di Linux, probabilmente una macro. Ma un altro codice di ricerca di Google, né grep su / usr / include / linux potrebbe alzarlo. Qualche idea su dove sia?

Ruolo chiarito di cur e dut. Il "quot" non valido " c'è come salvaguardia. Man mano che le differenze tra cur e dut diventano maggiori, la funzione alla fine si lamenta.

È stato utile?

Soluzione

Penso che tu stia parlando di gestire correttamente il wraparound del cerchio dei numeri. In realtà è abbastanza semplice.

Questo non fa esattamente quello che hai detto (non so perché hai quell'intervallo di "eccezione"), ma:

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

modifica : questo ha un " punto di diramazione " a diff = -32768, quindi se a = 5 eb = 32772, diff = -32767 che è inferiore a 0 e quindi 5 è "precedente"; di 32772. Se a = 5 eb = 32774, diff = -32769 = 32767 che è maggiore di 0 e quindi 5 è "più tardi"; di 32774. Questo definisce "prima" e "più tardi" nel senso di (a) la matematica più semplice, e (b) poiché i contatori avvolgenti possono essere interpretati come aventi soluzioni multiple mod 65536, sceglie la soluzione di aeb che sono "più vicine"; tra loro rispetto al cerchio dei numeri.

Se aeb differiscono di 32768, sono ugualmente distanti e la semplice matematica viene utilizzata per scegliere più facilmente ... questo "viola". la proprietà antisimmetrica di "precedente" e "più tardi" nel senso che isLater (5.32773) è vero e anche isLater (32773,5) è vero. Ma come fai a sapere se " 5 " rappresenta un conteggio di 5 o "5" rappresenta un conteggio di 65541? (proprio come abs (-32768) == -32768 dà una strana risposta senza senso) Se si desidera mantenere l'antisimmetria, ad es. isLater (b, a) == isEarlier (a, b), quindi puoi sempre farlo:

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

Se desideri deviare il punto di diramazione in una direzione in modo che avvenga a -32768 + K, usa invece questo:

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

Questo non utilizza più il più vicino; se, ad esempio, K = 12768 e a = 5, allora per b = 6,7,8,9, ... 20005, isEarlier (a, b) e isLater (b, a) saranno veri, e per b = 20006, 20007, ... 65534, 65535, 0, 1, 2, 3, 4, 5 isEarlier (a, b) e isLater (b, a) saranno falsi.

Hai una scelta particolare di intervalli che è diversa dalla logica che uso con i numeri avvolgenti. Le funzioni definite qui non soddisferebbero le tue esigenze come indicato, ma trovo quelle scelte di intervallo un po 'peculiari. Forse potresti spiegare come li hai determinati?

Altri suggerimenti

Prima calcola la differenza, quindi controlla in quale finestra cade.

Poiché è così semplice e le dimensioni delle finestre passate / future / di errore variano, devi farlo da solo.

Ok, per la cronaca. Ecco la mia soluzione, questo è ciò che intendevo:

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

Mi sembra che tu l'abbia appena scritto :). Perché non tradurre il tuo post in un codice C?

Ricorda che non puoi ottenere " > " e " < " fare quello che vuoi in C. Si applicano solo ai numeri e non c'è sovraccarico dell'operatore. Lo stesso vale per la tua eccezione; C non ha eccezioni.

Potresti scrivere alcune funzioni di accesso che tratteranno i tipi integrali senza segno in questo modo e che non sarebbe difficile. (In C, l'overflow non è definito per i tipi integrali firmati, anche se sulla maggior parte dei sistemi moderni si avvolge.) Non sarebbe così difficile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top