2009-08-08 20 views
10

Die meisten der Konstanten ich in anderen Code zu sehen sind Potenzen von 2, dhWarum deklarieren wir Konstanten immer als Potenzen von 2?

#define SIZE 256 

oder

public static final int SIZE = 2048; 

Gibt es einen besonderen Grund, warum wir das tun, statt dh

#define SIZE 257 

?

+2

Ich glaube nicht, dass diese Frage beantwortet werden kann, ohne zu wissen, wofür die Konstante verwendet wird. Der Zweck der Konstanten bestimmt, welche Werte die Konstante annehmen kann. –

+0

Ein Beispiel könnte die Größe eines Arrays von Ints sein. –

+1

Ich glaube, du denkst, wir verwenden mehr als 2-mal mehr als sie tatsächlich benutzt werden. Leute werden ein Array von 100 Ints genauso verwenden wie ein Array von 256 Bitmasking ist der Hauptgrund für Potenzen von 2 und trifft nicht auf Größen von Arrays zu. –

Antwort

29

Potenzen von 2 sind praktisch, da sie sich gut auf die zugrunde liegenden Einschränkungen in der Hardware abbilden lassen.

wie:

  1. Seitengröße
  2. Adressraum Grenzen
  3. Ausrichtung constaints (DWORD oder QWORD Ausrichtung im Allgemeinen, beide Potenzen von 2)

Für Fahnen, Potenzen von 2 habe immer ein einzelnes Bit gesetzt. So funktionieren Dinge wie MY_FLAG_1 | MY_FLAG_2 | MY_FLAG_3 | ... nur mit Zweierpotenzen. Ebenso zum Testen auf Fahnen mit &.

Es ist auch etwas von einer Konvention, um die nächste größere Potenz von zwei für Puffergrößen und dergleichen auszuwählen.

-2

Da Computer Memory mit 0/1 arbeitet, ist das binäre System.

+0

Und welchen Unterschied macht es, wenn ich ein Array von 256 Zeichen anstelle von 100 Zeichen mache? –

+0

Meine Antwort bezieht sich auf die Art, wie der Prozessor auf den Speicher zugreift, es ist einfacher, wenn es 2^n – programmernovice

18

Ein guter Grund ist bitmasking. Wenn Sie beispielsweise Konstanten verwenden, um Attribute eines Objekts (oder eines anderen Objekts) darzustellen, können Sie viele Attribute durch Bitmasken in einer einzigen Ganzzahl speichern und später die einzelnen Attribute identifizieren. Ideal zum Speichern vieler "Flags" in einer Datenbank.

4

Der Arbeitsspeicher wird in der Regel in mehreren Seiten des Betriebssystems zugewiesen, und in vielen Fällen ist es sinnvoll, die Seiten so anzuordnen, dass sie genau auf die Seiten passen (um keinen Speicher zu verschwenden). Es hängt von der spezifischen Zuteilungsroutine ab, ob dies wirklich hilft; z.B. Wenn es einen impliziten Header gibt, kann die Größe einer Potenz von zwei tatsächlich weh tun.

1

Nicht viel Grund wirklich. Aufgrund der Ausrichtung von Variablen in strukturierten und auf dem Stapel wird ein Array von drei Bytes wahrscheinlich von 4 oder 8 Bytes im Speicher dauern. Ich denke, es fühlt sich einfach gut an.

Die Zuweisung einer ganzen Anzahl von Seiten aus dem Heap funktioniert aufgrund des Overheads der internen Struktur des Heap möglicherweise nicht so effektiv wie gewünscht. Die Zuweisung von 4096 Bytes (1 Seite für eine 32-Bit-Windows-Maschine) kann wahrscheinlich zu einer Zuweisung von 4104 Bytes oder mehr führen.

Wenn die Konstanten Flags sind, dann ist die Geschichte sehr unterschiedlich. Es ist typischerweise effizienter, Bit-Flags als Flags in einer Base zu haben, die keine Potenz von 2 ist.

2

Unsere Variablengrößen sind Potenzen von 2 (1, 2, 4 oder 8 Bytes). Der Computer arbeitet komfortabel an diesen Grenzen. Früher pflegten wir unsere Strukturen sorgfältig zu puffern, um unseren Code schneller zu machen und manchmal die Zeigerarithmetik zu vereinfachen.

Wenn Sie zwischen einer Größe von 256 und 257 wählen können, gehen wir mit 256. Ein Grund wäre für das Debuggen.Wenn Sie sich den Speicher oder eine Datei ansehen, zeigt Ihr Debugger oder Hex-Dateibetrachter Daten in Zweierpotenzen an.

hier ein, das 16 Bytes pro Zeile zeigt, in Gruppen von 4.

alt text http://upload.wikimedia.org/wikipedia/en/2/2c/Hexedit-screenshot.png

Für Fahnen, wir machen sie Potenzen von zwei, so können wir sie alle einzeln in eine Variable behandeln, anstatt in vielen Variablen oder ein Array.

So können sie alle von der gleichen Variable und and'd sein.

bits |= 8;  //00000100 
bits |= 32;  //00010000 

//bits is now 40 00010100 

bits &= 32;  //00010000 

//bits is now 32 00010000 

Viele Programmierer werden die Zahlen in Hexadezimal statt dezimal schreiben, so dass es einfacher ist, zu sehen, was mit den einzelnen Bits vor sich geht.

1

Mit binären Computern, ist es bequem zu verwenden Standard-basierte binary multiples wie Mebibyte (oder Kibi, Gibi, Tebi ...). Diese Potenz von 2 Zahlen sehen auch in Octal oder Hex Notationen gut aus.

1

Das Hinzufügen von mehr Bits zu einem Speicherchip erfolgt normalerweise durch Vervierfachen der Anzahl der "Zellen" auf dem Chip. Doppelt so breit, doppelt so lang, viermal so viel Speicher (außer kleineren Abständen zwischen den "Zellen").

Es ist auch einfacher, mit einer einzigen Schicht zu multiplizieren, als mit dem generischen Multiplikationsalgorithmus des Hinzufügens sukzessiver Verschiebungen, abhängig davon, ob ein bestimmtes Bit gesetzt ist oder nicht. OpenGL war berühmt dafür, dass Texturen in zwei Größenordnungen benötigt werden, um auf bestimmte Scanlinien zuzugreifen.

2

Wenn es um Array-Größen geht, vermute ich, dass es zwei Gründe gibt, warum Potenzen von zwei bevorzugt werden. Einer - wie mehrere Antworten hier zeigen - ist, dass Programmierer, die nicht wissen, was "unter der Haube" vor sich geht, den Eindruck haben, dass es effizienter ist, eine Zweierpotenz zu verwenden. Das andere ist (hauptsächlich in historischer Zeit) mit zyklischen Puffern zu tun.

Zyklische Puffer, die Zweierpotenzen sind, können einfacher und schneller gehandhabt werden, indem Masken die Lese- und Schreibindizes (oder Zeiger) verwenden, anstatt die normalerweise langsamere Modulooperation oder Bedingungen zu verwenden, die Verzweigungen erfordern. Dies war bei älteren Maschinen entscheidend, kann aber immer noch wichtig sein für die Übertragung großer Datenmengen - z. Verarbeitung von Grafik

beispielsweise in C, die die Anzahl der verfügbaren Bytes in einem zyklischen Puffer gelesen werden, kann durchgeführt werden, erhalten:

pending = (SIZE + wr - rd) & (SIZE - 1); 

Wenn nicht Zweierpotenz verwendet dann würde die äquivalent sein:

pending = (SIZE + wr - rd) % (SIZE - 1); 

Bei Maschinen, die nicht über eine Abteilung/Modul Anweisung, dass wenig „%“ implementieren könnte mehrere hundert Zyklen dauern, so dass Sie so etwas wie brauchen würden:

if (wr >= rd) 
    pending = wr - rd; 
else 
    pending = (SIZE + wr) - rd; 

Die den Code verstopft und Verzweigungen verursacht, die die Befehlspipeline blockieren können.

in den Puffer schreiben, die etwas war wie

buf[wr++] = x; 
if (wr == SIZE) 
    rd = 0; 

wird die (in der Regel) effizienter:

buf[wr++] = x; 
wr &= SIZE-1; 

Natürlich, wenn Sie eine nicht signierte 8-Bit-Variable Index ein 256 Eintrag Array verwendet dann musstest du nicht einmal die Maskierung machen.

+0

Guter Punkt ist. Ich denke immer noch in Assemblersprache und mache Ringpuffer mit ands. Wenn ich eine trig-Tabelle erstelle, baue ich sie mit 256 Grad, so dass ich nach einer Addition oder Subtraktion nur das untere Byte betrachten kann. – Nosredna

Verwandte Themen