2010-12-10 12 views
3

Angenommen, ich habe eine ansteigende Sequenz von Ganzzahlen ohne Vorzeichen C[i]. Wenn sie zunehmen, werden sie wahrscheinlich immer mehr Bits einnehmen. Ich suche nach einer effizienten Bedingung, basierend auf zwei aufeinander folgenden Elementen der Sequenz C[i] und C[i+1] (Vergangenheit und Zukunft sind nicht beobachtbar), die wahr entweder genau oder ungefähr einmal für jedes Mal evaluieren wird, wenn die Anzahl der erforderlichen Bits zunimmt .Effiziente Bedingung für zunehmende Größe in Bits

Eine offensichtliche (aber langsam) Wahl der bedingt ist:

if (ceil(log(C[i+1])) > ceil(log(C[i]))) ... 

und ebenfalls alles, was die Anzahl von führenden Null-Bits mit speziellem CPU-Opcodes (viel besser, aber immer noch nicht gut) berechnet.

Ich vermute, es kann eine schöne Lösung mit einem Ausdruck nur bitweise oder und bitweise und auf die Werte C[i+1] und C[i]. Irgendwelche Gedanken?

+0

möglich Duplikat [Finden höchstwertige Bit (am weitesten links), die in einem Bit-Array gesetzt] (http://stackoverflow.com/questions/2589096/find-most-significant -Bit-ganz links-das-ist-ist-in-einem-Bit-Array gesetzt) ​​ – kennytm

+1

Bitte nicht als Dublette kennzeichnen! Ich frage nach einem Problem, das weniger allgemein ist und möglicherweise eine bessere Lösung hat. –

Antwort

16

Angenommen, Ihre beiden Zahlen sind x und y. Wenn sie das gleiche Bit höherer Ordnung haben, dann ist x^y kleiner als sowohl x als auch y. Ansonsten ist es höher als einer der beiden.

So

v = x^y 
if (v > x || v > y) { ...one more bit... } 
+3

Ausgezeichnet! Und da er schon weiß, dass 'C [i + 1]'> 'C [i]', dann 'if ((C [i + 1]^C [i])> C [i]) {/ * Anzahl von Bits hat sich geändert * /} ' –

+0

Ja, Sie können 1 Vergleich auf diese Weise loswerden. –

+0

+1 und überprüfen. Genau das habe ich gesucht, aber ich hatte noch keine Zeit, über die Logik nachzudenken. Es ist viel effizienter als alle anderen Vorschläge, die im Wesentlichen die gleiche sind wie die naive Lösung, die ich in der Frage geschrieben habe. –

-1

Die Anzahl der Bits erhöht sich, wenn der Wert eine Zweierpotenz überschreitet. Ein einfacher Test ist dann:

while (C[i] >= (1<<number_of_bits)) then number_of_bits++; 

Wenn Sie es noch schneller wollen:

int number_of_bits = 1; 
int two_to_number_of_bits = 1<<number_of_bits ; 


... your code .... 

while (C[i]>=two_to_number_of_bits) 
    { number_of_bits++; 
    two_to_number_of_bits = 1<<number_of_bits ; 
    } 
+0

Ich sagte, basierend rein auf 'C [i]' und 'C [i + 1]', nicht eine neue magische Zählervariable. –

+0

Sie sagten auch "schnell". Was ist der Einwand? –

+0

Es gibt keinen Ort, an dem 'number_of_bits' gespeichert werden kann. Ich habe die Frage genau so formuliert, wie ich sie brauchte. Ihre Antwort ist auf ein ganz anderes Problem. –

2

Ich glaube, Sie clz(C[i+1]) < clz(C[i]) nur brauchen, wo clz ist eine Funktion, die die Anzahl der führenden Nullen zurückgibt ("zählen führende Nullen "). Einige CPU-Familien haben dafür eine Anweisung (die möglicherweise als Instrinsic verfügbar ist). Wenn nicht, müssen Sie Ihre eigenen rollen (es dauert in der Regel nur ein paar Anweisungen) - siehe Hacker's Delight.

+0

Ich stimme zu, dass dies funktionieren kann (ich habe es nur abstrakter mit 'ceil' und' log' geschrieben), aber ich glaube (besonders wenn Sie die Anforderung genau dann abbrechen, wenn die Bitgröße auf nur einmal pro erhöht wird) kann effizienter gemacht werden. –

+0

Wie viel effizienter als eine Anweisung können Sie bekommen? (OK, OK, drei Anweisungen.) –

+1

Wie implementieren Sie 'CLZ' in nur wenigen Anweisungen ohne eine native Anweisung? Das Beste, was ich gefunden habe, ist in meiner Lösung, obwohl das LSB in nur ein paar Anweisungen gefunden werden kann, die Multiplikation verwenden, wie in einer anderen SO-Frage erwähnt. – jonderry

0

Die Anzahl der Bits geht nach oben, wenn der Wert über dem Überlauf eine Zweierpotenz ist. Ein einfacher Test ist dann, ist der Wert gleich einer Potenz von zwei, minus 1? Dies kann mit der Frage erreicht werden:

if ((C[i] & (C[i]+1))==0) ... 
+0

']' und '+ 1' pendeln gewöhnlich nicht ... –

+0

Es gibt keine Absicht, sie zu pendeln. Wenn C [i] überläuft und C [i + 1] größer ist, benötigen Sie mehr Bits für C [i + 1]. Sie müssen sich C [i + 1] nicht ansehen, um das zu entscheiden. –

0

Given (Ich glaube, das von Hacker's Delight kommt):

int hibit(unsigned int n) { 
    n |= (n >> 1); 
    n |= (n >> 2); 
    n |= (n >> 4); 
    n |= (n >> 8); 
    n |= (n >> 16); 
    return n - (n >> 1); 
} 

Ihre bedingt ist einfach hibit(C[i]) != hibit(C[i+1]).

+0

Ich habe gehört, das ist schneller als dedizierte Opcodes auf einigen CPUs, aber ich suchte nach der noch schnelleren Lösung, die den gesamten Bit-Zählschritt überspringt, den ich akzeptierte. –

0

BSR - Bit Scan umge (386+)

Usage: BSR  dest,src 
    Modifies flags: ZF 

    Scans source operand for first bit set. Sets ZF if a bit is found 
    set and loads the destination with an index to first set bit. Clears 
    ZF is no bits are found set. BSF scans forward across bit pattern 
    (0-n) while BSR scans in reverse (n-0). 

          Clocks     Size 
    Operands   808x 286 386 486   Bytes 

    reg,reg   -  - 10+3n 6-103   3 
    reg,mem   -  - 10+3n 7-104   3-7 
    reg32,reg32  -  - 10+3n 6-103   3-7 
    reg32,mem32  -  - 10+3n 7-104   3-7 

Sie müssen zwei davon (auf C [i] und C [i] + 1) und einem vergleichen.

0

Keith Randalls Lösung ist gut, aber Sie können einen xor-Befehl speichern, indem Sie den folgenden Code verwenden, der die gesamte Sequenz in O (w + n) -Anweisungen verarbeitet, wobei w die Anzahl der Bits in einem Wort und n ist die Anzahl der Elemente in der Sequenz. Wenn die Sequenz lang ist, beinhalten die meisten Iterationen nur einen Vergleich, wobei ein xor-Befehl vermieden wird.

Dies wird durch Verfolgen der höchsten Potenz von zwei erreicht, die wie folgt erreicht:

t = 1; // original setting 

if (c[i + 1] >= t) { 
    do { 
    t <<= 1; 
    } while (c[i + 1] >= t); // watch for overflow 
    ... // conditional code here 
} 
+0

Ich bemerke, dass deine Lösung eine kleine Variante von mir ist. Ich habe auch bemerkt, dass R. meine (unvernünftig IMHO) beleidigt hat, aber nicht deins. –

Verwandte Themen