2012-03-25 1 views
0

Following my previous question einstellen, ich brauche die aus einem festen Bereich von Bits I die folgende Funktion verwendet, um einen Wert 1 zu erzeugen:einen Bitbereich in einer ordinalen

void MaskAddRange(UINT& mask, UINT first, UINT count) 
{ 
    mask |= ((1 << count) - 1) << first; 
} 

Wie jedoch entdeckt, es didn‘ t funktionieren korrekt für count = 32. Das Ergebnis der 1 << count in einem solchen Fall theoretisch ist nicht definiertes Verhalten (oder Ergebnis) und praktisch auf x86 es 1 ist, weil Verschiebung Operand Modulo 32.

behandelt ich diesen Ausdruck beheben wollen für richtig arbeiten Dieser Extremfall auch. Was ist der einfachste/nice/effizienteste Weg dies zu tun?

Die Handhabung dieses speziellen Fall über Verzweigung (if, ?) ist ein bisschen einfach, obwohl hässlich, und ich wette, es ist auch ineffizient.

Eine andere Möglichkeit besteht darin, den Verschiebeoperanden zu einem größeren Typ (64 Bit) zu fördern. Ich meine folgendes:

void MaskAddRange(UINT& mask, UINT first, UINT count) 
{ 
    mask |= (UINT(unsigned __int64(1) << count) - 1) << first; 
} 

Gibt es einen besseren Weg?

+0

Warum nicht 'UINT (-1)'? –

+0

@Kerrek SB: Wie? – valdo

+0

Hmm. Können Sie eine einfache, kurze und prägnante Beschreibung des erforderlichen Verhaltens Ihrer Funktion hinzufügen? Ich würde es vorziehen, die Anforderungen aus dem betreffenden Code nicht rückentwickeln zu müssen. –

Antwort

1

Niemals annehmen, dass etwas ineffizient ist, es sei denn, Sie können es beweisen. Das if-else kann genauso gut auf Ihrer Architektur + OS als die Förderung auf 64-Bit. Ich glaube nicht, dass es einen anderen, vernünftigen Ansatz gibt als die beiden, die Sie bereits veröffentlicht haben.

würde ich für die if-sonst gehen, weil es dokumentiert die Absicht der Handhabung des Extremfalls. Die Förderung auf 64-Bit zeigt diese Absicht nicht an.

+0

Vielen Dank für den theoretischen Aufsatz über die Richtlinien zum Schreiben effizienter Software. In meinem speziellen Fall kann ich jedoch leicht beweisen, dass die Verzweigung weniger effizient ist als eine einzelne CPU-Anweisung (dies ist bereits geschehen). Ich glaube auch, dass ein * vernünftiger * Ansatz einige Fakten annehmen sollte, die auf der "gebildeten Vermutung" beruhen, gefolgt von der obligatorischen Verifizierung. – valdo

+0

P.S. Ich stimme zu, dass das explizite 'if-else' die Absicht, einen bestimmten Extremfall zu behandeln, selbst dokumentiert, was ziemlich wertvoll ist. OTOH, der allgemeiner spricht, ziehe es vor, etwas zu schreiben, das inhärent alle extremen Fälle abdeckt (wenn ich kann). Dann ist es einfacher, den Programmablauf zu sehen, ohne alle Fälle im Kopf zu betrachten. Dies führt in der Regel auch zu einer besseren und universelleren Formulierung. – valdo

+0

Können Sie uns die "single CPU instruction" angeben, auf die Sie sich beziehen? Da Ihre (oder Howards) Funktion niemals eine einzige Anweisung sein wird, kann ich das versichern.Aber um die Diskussion kurz zu halten, lassen Sie mich Folgendes sagen: Auf einer CPU, die 64-Bit-Integer-Operationen effizient unterstützt, wird Ihr 64-Bit-Promotion-Code am effizientesten sein. Und da Sie wissen, wie Sie Windows verwenden, werden Sie wahrscheinlich mit einer CPU arbeiten, die 64-Bit-Integer-Operationen effizient unterstützt. – Irfy

0

können Sie

mask |= (UINT(-1)<<first) & (UINT(-1)>>(32-first-count)) 

verwenden, das sollte komplizierter ist aber in jedem Fall arbeiten. Die Effizienz dieses Ausdrucks in Bezug auf andere Lösungen kann von der Architektur und dem Compiler abhängen.

+0

Interessant. Es ist jedoch anfällig für einen anderen Extremfall, wobei "first = 0" und "count = 0" sind. – valdo