2015-09-01 11 views
18

Ho scritto il seguente programma per emettere l'equivalente binario di un intero prendendo (ho controllato che int sul mio sistema è di 4 byte) è di 4 byte. Ma l'output non è quello giusto. Il codice è:Perché il calcolo dell'equivalente binario diventa errato?

#include<iostream> 
#include<iomanip> 
using namespace std; 

void printBinary(int k){ 
    for(int i = 0; i <= 31; i++){ 
     if(k & ((1 << 31) >> i)) 
      cout << "1"; 
     else 
      cout << "0"; 
    } 
} 

int main(){ 
    printBinary(12); 
} 

Dove mi sto sbagliando?

+4

Non hai fornito ciò che effettivamente accade e quello che ti aspettavi isntead. – dhein

+1

+ Perché pensi che sia errato? – dhein

+0

+ Forse facci sapere cosa pensi di sbagliare? Difficile dirti dove trovi qualcosa di sbagliato se non ci dici cosa ti confonde ... – dhein

risposta

29

Il problema è in 1<<31. Poiché 2 non possono essere rappresentati con un intero con segno a 32-bit (gamma -2 a 2 - 1), il risultato è indefinito [1].

La correzione è semplice: 1U<<31.


[1]: Il comportamento dipende dall'implementazione dal C++ 14.

+3

[Dal C++ 14] (http://stackoverflow.com/questions/26331035/why-was-1-31-changed-to -be-implementation-defined-in-c14) non c'è UB –

+4

@MattMcNabb: Non vedo l'OP taggato come C++ 14 – dhein

+0

@Zaibis che cosa stai cercando di fare –

8

Questa espressione non è corretta:

if(k & ((1<<31)>>i)) 

int è un firmato tipo, in modo che quando si sposta 1 31 volte, diventa il bit di segno sul sistema. Dopodiché, spostando il risultato a destra i volte firma il numero il numero, il che significa che i bit in cima rimangono 1 s. Si finisce con una sequenza che assomiglia a questo:

80000000 // 10000...00 
C0000000 // 11000...00 
E0000000 // 11100...00 
F0000000 // 11110...00 
F8000000 
FC000000 
... 
FFFFFFF8 
FFFFFFFC 
FFFFFFFE // 11111..10 
FFFFFFFF // 11111..11 

Per risolvere questo problema, sostituire l'espressione con 1 & (k>>(31-i)). In tal modo si evita il comportamento non definito * risultante dallo spostamento di 1 nella posizione del bit di segno.

*C++14 changed the definition in modo che lo spostamento 1 31 volte a fianco in un 32 bit int non è indefinito (Grazie, Matt McNabb, per la precisazione).

+0

Mentre è tecnicamente corretta spiegazione guardando come le istruzioni vengono eseguite sulla macchina, lo standard di linguaggio lascia il comportamento indefinito per '1 << 31'. Dalle specifiche: 'Il valore di E1 << E2 è E1 a sinistra con posizioni di bit E2 spostate a sinistra; i bit vuoti sono riempiti a zero. [...] Altrimenti, se E1 ha un tipo firmato e un valore non negativo e E1 × 2^E2 è rappresentabile nel tipo di risultato, allora questo è il valore risultante; altrimenti, il comportamento non è definito. – nhahtdh

+0

@nhahtdh Ecco perché ho scritto che questo è il comportamento sul sistema di OP. – dasblinkenlight

+0

Penso che dovresti renderlo più prominente e chiarire anche il fatto che, mentre la tua correzione potrebbe essere corretta sul sistema dell'OP, è un comportamento indefinito in base alle specifiche. – nhahtdh

4

Una tipica rappresentazione memoria interna di un valore intero con segno assomiglia:

enter image description here

Il m ost s ignificant b esso (primo da destra) è il segno bit e in signed numbers (come int) rappresenta se il numero è negativo o meno. Quando si spostano bit aggiuntivi , l'estensione di segno viene eseguita per conservare il segno del numero. Questo viene effettuato da digitando le cifre sul lato più significativo del numero (seguendo una procedura dipendente dalla particolare rappresentazione di numero con segno utilizzata).
In numeri senza segno il primo bit da destra è solo l'MSB del numero rappresentato, quindi quando si spostano bit aggiuntivi non viene eseguita alcuna estensione di segno.

Nota: l'enumerazione dei bit parte da , in modo 1 << 31 sostituisce il vostro bit di segno e dopo che il funzionamento ogni bit spostamento a sinistra >> risultati in estensione del segno. (come sottolineato da @dasblinkenlight)

Quindi, la soluzione semplice al tuo problema è rendere il numero non firmato (questo è ciò che U fa in 1U << 31) prima di iniziare la manipolazione dei bit. (Come sottolineato da @Yu Hao)

Per ulteriori approfondimenti si veda signed number representations e two's complement. (In quanto è il più comune)

Problemi correlati