[C] esiste una funzione che inverte l'ordine dei bit, all'interno di un byte?

Pubblicità

vercigetorix

Nuovo Utente
Messaggi
12
Reazioni
0
Punteggio
25
volevo chiedere se in C, esiste una funzione apposita che dato un byte, ne inverte i bit al suo interno..una sorta di mirror dei bit..

es: byte: 0001 1011 (valore intero 27).

La funzione deve restituire il byte cosi composto: 1101 1000 (intero 216)
 
Di una funzione non ne sono a conoscenza, peró se inserisci questo numero binario in un vettore (o array, chiamalo come vuoi) potresti reinserirlo in un altro vettore al contrario tramite un ciclo.


Int main ()
{
Int numbinario [8]= { 0, 0, 1, 0, 1, 1, 0, 1}
Int numbinario2 [8], i, j;
J=7;
for (i=0; i <8; i++)
{
numbinario2=numbinario[j];
J--;
}
}


Come puoi vedere uso due vettrori, Numbinario e Numbinario2. Nel primo inserisco il numero 00101101. Con il ciclo for andro ad inserire il valore di numbinario [j], in cui nel primo step è la settima casella di numbinario ( j=7 )contenente quindi il valore 1, in Numbinario2 , in cui, sempre nel primo step, è la prima casella di Numbinario2 (i=0 ).
Avremmo quindi che la prima casella di Numbinario2 è uguale all'ultima di numbinario. Fatto questo il ciclo incrementera i, e decrementera j, in questo modo la seconda casella di Numbinario2 sarà uguale alla penultima di Numbinario ecosi via.
Ti ritroverai cosi il tuo numero binario invertito nell'array numbinario2.

Spero di esserti stato d'aiuto. :)
 
Ultima modifica:
Di una funzione non ne sono a conoscenza, peró se inserisci questo numero binario in un vettore (o array, chiamalo come vuoi) potresti reinserirlo in un altro vettore al contrario tramite un ciclo.


Int main ()
{
Int numbinario [8]= { 0, 0, 1, 0, 1, 1, 0, 1}
Int numbinario2 [8], i, j;
J=7;
for (i=0; i <8; i++)
{
numbinario2=numbinario[j];
J--;
}
}


Come puoi vedere uso due vettrori, Numbinario e Numbinario2. Nel primo inserisco il numero 00101101. Con il ciclo for andro ad inserire il valore di numbinario [j], in cui nel primo step è la settima casella di numbinario ( j=7 )contenente quindi il valore 1, in Numbinario2 , in cui, sempre nel primo step, è la prima casella di Numbinario2 (i=0 ).
Avremmo quindi che la prima casella di Numbinario2 è uguale all'ultima di numbinario. Fatto questo il ciclo incrementera i, e decrementera j, in questo modo la seconda casella di Numbinario2 sarà uguale alla penultima di Numbinario ecosi via.
Ti ritroverai cosi il tuo numero binario invertito nell'array numbinario2.

Spero di esserti stato d'aiuto. :)


grazie mille.. ti volevo chiedere una cosa a tal proposito.. la mia variabile di cui devo invertire i bit, in realtà, è una unsigned char.. come faccio a mettere una unsigned char in un vettore? se è banale perdona l'ignoranza! :)

- - - Updated - - -

però tu mi hai messo 8 int dentro un array.. io in realtà ho varaibile di un byte, di cui devo invertire i bit al suo interno..
 
mmmh... soluzione molto artigianale :asd: :

Codice:
#include <stdio.h>

int intPow(int base, int esp) {
  if (esp == 0) return 1;
  if (base == 1) return base;
  return base * intPow(base, esp-1);
}

unsigned char specchio(unsigned char in){
    unsigned char out = 0x00;    
    unsigned char mask,shift;
    for (int i = 0; i < sizeof(char)*4; i++){    
        shift = (sizeof(char)*8 - (i*2 + 1)); //distanza dal centro
        mask = intPow(2,i);    //maschera selezione bit a destra del centro
        out += (in&mask)<<shift;    //shift a sinistra
        mask = intPow(2,sizeof(char)*8- (i+1));    //maschera selezione bit a sinistra del centro
        out += (in&mask)>>shift;    //shift a destra
    }            
    return out;
}

void main(){
    unsigned char a = 0x1B; //27d
    unsigned char b = specchio(a);
    printf("%d => %d", a, b);
}
Stampa 27 => 216 come atteso

ps: l'uso del sizeof ti permette di adattare la funzione a qualsiasi valore numerico. Per lavorare con gli int, basta che cambi il tipo delle variabili e metti sizeof(int) anziche sizeof(char)
 
Ultima modifica:
non complicatevi la vita!
Questa è algebra booleana, basta una sola istruzione XOR.

esempio:
byte: 0001 1011 (valore intero 27), contenuta in prova (nome a caso)
La funzione deve restituire il byte prova cosi composto: 1101 1000 (intero 216) --ma credo tu intenda 1110 0100 (intero 228)

allora:

prova ^= 0xFF;

fine.
Se hai problemi fammi sapere
 
Ultima modifica:
non complicatevi la vita!
Questa è algebra booleana, basta una sola istruzione XOR.
Se fosse un complemento a 1 non me la sarei complicata per niente la vita, e avrei usato appunto uno XOR. :asd:
Io penso intenda proprio invertire l'ordine dei bit come esplicita nel primo post:
es: byte: 0001 1011 (valore intero 27).

La funzione deve restituire il byte cosi composto: 1101 1000 (intero 216)
 
Se fosse un complemento a 1 non me la sarei complicata per niente la vita, e avrei usato appunto uno XOR. :asd:
Io penso intenda proprio invertire l'ordine dei bit come esplicita nel primo post:

Hai ragione 1nd33d, ho capito male, per scusarmi ho scritto queste istruzioni da manicomio, dimmi se ti piacciono:

...
unsigned char out = 0;
// unsigned char varb = 0x1B;

out |= (0x01 == (0x01 & varb))? 0x80 : 0;
out |= (0x02 == (0x02 & varb))? 0x40 : 0;
out |= (0x04 == (0x04 & varb))? 0x20 : 0;
out |= (0x08 == (0x08 & varb))? 0x10 : 0;
out |= (0x10 == (0x10 & varb))? 0x08 : 0;
out |= (0x20 == (0x20 & varb))? 0x04 : 0;
out |= (0x40 == (0x40 & varb))? 0x02 : 0;
out |= (0x80 == (0x80 & varb))? 0x01 : 0;

return out;
....
(da mettere ovviamente in una funzione...)
 
Ultima modifica:
Hai ragione 1nd33d, ho capito male, per scusarmi ho scritto queste istruzioni da manicomio, dimmi se ti piacciono:

...
unsigned char out = 0;
// unsigned char varb = 0x1B;

out |= (0x01 == (0x01 & varb))? 0x80 : 0;
out |= (0x02 == (0x02 & varb))? 0x40 : 0;
out |= (0x04 == (0x04 & varb))? 0x20 : 0;
out |= (0x08 == (0x08 & varb))? 0x10 : 0;
out |= (0x10 == (0x10 & varb))? 0x08 : 0;
out |= (0x20 == (0x20 & varb))? 0x04 : 0;
out |= (0x40 == (0x40 & varb))? 0x02 : 0;
out |= (0x80 == (0x80 & varb))? 0x01 : 0;

return out;
....
(da mettere ovviamente in una funzione...)
Un ottimo approccio orientato alle prestazioni (la mia funzione è molto più lenta in favore della genericità del tipo, tra l'altro usando una terza funzione per la potenza, che effettivamente avrei potuto realizzare con un semplice shift come hai fatto te manualmente essendo potenze sempre di 2).
Volendo migliorarla ancora nell'ottica delle prestazioni, la tua funzione potrebbe essere modificata in questo modo:
Codice:
unsigned char specchioo(unsigned char varb){
    unsigned char out = 0;

    if (0x01 & varb)
        out |= 0x80;
    if (0x02 & varb)
        out |= 0x40;
    if (0x04 & varb)
        out |= 0x20;
    if (0x08 & varb)
        out |= 0x10;
    if (0x10 & varb)
        out |= 0x08;
    if (0x20 & varb)
        out |= 0x04;
    if (0x40 & varb)
        out |= 0x02;
    if (0x80 & varb)
        out |= 0x01;
    
    return out;
}
Cambia che viene fatto un solo confronto anzichè due, e l'OR viene fatto solo se il bit vale 1, non se vale 0.
Statisticamente ci si può aspettare un dimezzamento del tempo di esecuzione e infatti l'esecuzione di 25 milioni di inversioni richiede circa 200ms contro i 350ms di prima.
Ovviamente è solo un dettaglio, il tuo codice è perfetto.

Se all'utente è sufficiente l'inversione dell'unsigned char, consiglio la tua soluzione per via delle prestazioni e tutto sommato è anche molto semplice e diretta.
 
Ultima modifica:
Cambia che viene fatto un solo confronto anzichè due, e l'OR viene fatto solo se il bit vale 1, non se vale 0.
Statisticamente ci si può aspettare un dimezzamento del tempo di esecuzione e infatti l'esecuzione di 25 milioni di inversioni richiede circa 200ms contro i 350ms di prima.
Giusto il secondo confronto non serve.
Il numero di confronti tuo è veramente ridotto all'osso, e sembra a questo punto a prova di bomba,
eppure si potrebbero migliorare ancora le prestazioni inserendo un blocco asm che permetterebbe di cambiarne approccio:

Codice:
unsigned char specchioo(unsigned char varb){
      unsigned char out = 0;
      _asm {
            RCL varb, 1
            . . . .
      }
      return out;
}

infatti RCL varb, 1 (rotate carry left) shifta a sinistra la variabile da invertire di una posizione, cambiando il
flag di riporto (carry) a seconda che il bit 'uscito' sia 0 o 1; a questo punto con ADC (add with carry) si puo sommare il flag
a una variabile, eliminando quindi i confronti...

si perderebbe la portabilità del codice, a favore di prestazioni esasperate ad hoc.
La genericità del tipo non lo vedo un problema, non mi risultano macchine in cui il char sia diverso da 8 bit o sbaglio?
 
Ultima modifica:
infatti RCL varb, 1 (rotate carry left) shifta a sinistra la variabile da invertire di una posizione, cambiando il
flag di riporto (carry) a seconda che il bit 'uscito' sia 0 o 1; a questo punto con ADC (add with carry) si puo sommare il flag
a una variabile, eliminando quindi i confronti...
si perderebbe la portabilità del codice, a favore di prestazioni esasperate ad hoc.
Hehe sicuramente sarebbe interessante :asd:
La genericità del tipo non lo vedo un problema, non mi risultano macchine in cui il char sia diverso da 8 bit o sbaglio?
No infatti, anche a me risultano sempre 8 bit i char, se l'utente deve usare solo char, tanto vale usare l'approccio "veloce".
 
Hehe sicuramente sarebbe interessante :asd:

L'ho appena scritta e verificata con Visual Studio:
Codice:
unsigned char specchio (unsigned char varb) {
    unsigned char ot = 0;
    _asm {
        XOR BL,BL    // di comodo
        RCL varb, 1
        ADC BL,0
        OR ot,BL

        XOR BL,BL
        RCL varb, 1
        ADC BL,0
        RCL BL,1
        OR ot,BL

        XOR BL,BL
        RCL varb, 1
        ADC BL,0
        RCL BL,2
        OR ot,BL

        XOR BL,BL
        RCL varb, 1
        ADC BL,0
        RCL BL,3
        OR ot,BL

        XOR BL,BL
        RCL varb, 1
        ADC BL,0
        RCL BL,4
        OR ot,BL

        XOR BL,BL
        RCL varb, 1
        ADC BL,0
        RCL BL,5
        OR ot,BL

        XOR BL,BL
        RCL varb, 1
        ADC BL,0
        RCL BL,6
        OR ot,BL

        XOR BL,BL
        RCL varb, 1
        ADC BL,0
        RCL BL,7
        OR ot,BL
    }
    return ot;
}
Credo sia impossibile riscriverla meglio in termini di efficienza
 
Ultima modifica:
Codice:
#include <stdio.h>


unsigned char specchio (unsigned char *n)
{
unsigned char out=0;  
int j, i;
for (j=7, i=0; i<8; i++, j--) 
    out |= ((*n>>i)&1)<<j;       
return out;
}


int main ()
{
unsigned char num = 27;
num = specchio (&num);
printf ("num = %d\n", num);
}
 
Pubblicità
Pubblicità
Indietro
Top