2016-05-24 29 views
0

Ich versuche, eine Zufallszahl unter Verwendung aller Bits eines int zu generieren. Wenn ich die rand() -Funktion verwende, scheint es nie das erste Bit zu verwenden, also habe ich versucht, das ganze Ding um einen Platz zu verschieben. Wenn ich jedoch versuche, die neue verschobene Nummer zu drucken, druckt es immer 4294967295, also denke ich, dass das ein Überlauf ist. Warum kann ich dieses Bit nicht benutzen? gibt es einen Weg?Warum kann ich das erste Bit eines Int nicht verwenden?

Wenn das erste Bit wird nicht verwendet, es funktioniert gut, wie diese (Druck vor und nach der Verschiebung der Zufallszahl):

00000100001100111111001010010111 
00001000011001111110010100101110 

aber wenn das erste Bit benötigt wird, geschieht dies:

01010110100001110011110011011111 
42949672950101101000011100111100110111110 

bitte helfen !! Es ist technisch Arbeits, druckt es nur zuerst die Zahl ...

typedef struct{ 
    int blocks[NUM_BLOCKS]; 
} WWord; 

void printbits(unsigned int n){ 
    int i; 
    //printf("%u = ",n); 
    for(i=SIZE_OF_INT*SIZE_OF_BYTE-1;i>=0;i--){ 
     int mask = 1<<i; 
     int maskedn = n&mask; 
     int thebit = maskedn >> i; 
     printf("%u",thebit); 
    } 
    printf("\n"); 
} 

void fillword(WWord *word){ 
    int i; 
    for(i=0; i<NUM_BLOCKS;i++){ 
     unsigned int ran = rand(); 
     printbits(ran); 
     ran = ran<<1; 
     printbits(ran); 
     word->blocks[i] = ran; 
     //word->blocks[i]<<1; 
     printf("\n"); 
    } 
} 
+3

signiert vs unsigned Ints. In einem vorzeichenbehafteten int ist das High-Bit für das Zeichen reserviert. In einem unsigned int wird das High-Bit nicht für ein Zeichen verwendet. Sie generieren und drucken nicht signierte Ints, aber Ihr Array 'blocks []' speichert signierte Ints. –

+1

Nein, bist du nicht. Der Standardwert für "int" ist signiert. – OldProgrammer

+0

oh, für die MASKE! Duh. Vielen Dank! – cmperezg

Antwort

5

Es scheint, Sie int statt unsigned int in printbits Funktion verwenden. So konvertiert es es in signed int, die MSB als Vorzeichenbit verwendet. Ändere diese int 's zu unsigned int es wird funktionieren.

Ihre Funktion ändern, wie unten:

void printbits(unsigned int n){ 
    int i; 
    //printf("%u = ",n); 
    for(i=SIZE_OF_INT*SIZE_OF_BYTE-1;i>=0;i--){ 
     unsigned int mask = 1u<<i; 
     unsigned int maskedn = n&mask; 
     unsigned int thebit = maskedn >> i; 
     printf("%u",thebit); 
    } 
    printf("\n"); 
} 
+2

Schlagen Sie '1 <' 1u << i; 'vor, um implementierungsdefiniertes Verhalten zu vermeiden. – chux

+0

ooooh, so die signierte Maske war das Problem .. Danke !!! – cmperezg

2

Ihre maskedn erklärt int vom Typ zu sein. Dies ist ein signierter Datentyp.

Ihre ran ist jedoch vom Typ unsigned.

C und C++ behandeln signed und unsigned Integer-Typen für Bit-Shifts unterschiedlich: Das Verhalten des >>-Operators für Ganzzahlen mit Vorzeichen ist implementierungsdefiniert nach dem C-Standard, wie @chux in einem Kommentar darauf hingewiesen hat.

jedoch bei den meisten Compilern x86 eine vorzeichenbehaftete Rechtsverschiebung als arithmetic shift umgesetzt wird, was im Allgemeinen bedeutet, dass der Vorzeichen-Bit (das signifikanteste Bit in der Darstellung unsigned) eher konserviert ist, als nach rechts verschoben.

Wenn Sie das MSB einer Ganzzahl mit Vorzeichen festlegen, setzen Sie das Vorzeichenbit, und wenn Sie nach rechts verschieben, werden immer wieder Kopien dieses Vorzeichenbits erstellt. Siehe this illustration from Wikipedia

Dies ist, warum Sie eine sehr große Anzahl bekommen, 4294967295, die (uint32_t)(0xFFFFFFFF) ist, oder 32 Bit alle auf 1 gesetzt

Wenn Sie vorsichtig sind überall ganze Zahlen ohne Vorzeichen verwenden, dann werden Sie das erwartete Verhalten erhalten, bei dem das Verschieben nach rechts das MSB verschiebt, anstatt es zu kopieren.

+1

In C führt die Verschiebung des Vorzeichenbits nach rechts zu _implementierungsdefiniertem Verhalten_, nicht "das Vorzeichenbit wird beibehalten, während Sie umschalten." – chux

+0

Ja, du hast Recht. Ich denke, ich habe dieses Verhalten angenommen, weil die meisten (alle?) X86-Compiler es mit 'sar' implementieren, der arithmetischen Rechtsverschiebungsanweisung. Ich werde das in meiner Antwort klären. –

+1

Die Verwendung von '(uint32_t) ((2L << 32) -1)' ist unklar (und undefiniert). Vielleicht willst du '(uint32_t) -1'? – chux