Hallo Com,
Seit .NET FW 1.1 gibt es die sog. BitShift-Operatoren
<< (-> LShift od. Links-shift) und
>> (-> RShift od. Rechts-shift)
Diese machen Mathematisch gesehen:
ACHTUNG: sie "kegeln" die anderen Bits einfach raus und schreiben am "Anfang" oben rein:
1001 >> 3 = 0001 (1001 << 3 = 1000)
Folgender Stub sollte die Funktionsweise eläutern (gibt in der Konsole ein paar Operationen aus):
Daraus ergibt sich ein sehr schneller Bitflag-Code:
Die Modulation mit 2 = 0010 sorgt dafür, dass wir den Stellenwert des LSB bekommen (wo wir vorher das gesuchte Bit hingeshiftet haben).
Vergleich mit 1 gibt demnach den Boolschen Wert des Bits zurück - ein sehr schneller Einzeiler, der es in sich hat
Alternativ dazu kann man auch mit dem And-Operator arbeiten und den offset "hochshiften":
Beziehungsweise, wenn man weis, dass (0) = False und (1 << offset) = True gilt:
//EDIT:
Wie vermutet wird in dem Fall bei VB implizit konvertiert, also bleibt noch 1 << offset > 0 (für alle offset im zugelassenen bereich) also abschätzung.
Was schneller ist, werde ich nun überprüfen.
//EDIT:
Ich werde2 KiB 40 MB (40.000.000 Bytes) UInt32er zufällig befüllen und von jeder Funktion jedes Bitflag auslesen lassen. Ergebnisse später.
Dieser Vorgang, 5x Wiederholt ergibt
//EDIT2:
Ich habe nun also
500 Iterationen mit
10000000 UIntgers Testdaten (Eigene für jede Iteration)
gemacht.
Hier die Durchschnittswerte (in Ticks / Loop = Ticks / UInteger (jedes Bit)):
BitFlag1: 32261,858
BitFlag2: 23841,384
BitFlag3: 25041,44
Demnach ist die schnellste Operation (flags And 1 << offset) = 1 << offset
Hier die Testklasse: clsBitFlagBM.vb
Wenn ihr in der Main den Initialisierungswert von
ändert, könnt ihr die Testbreite variieren.
Was bekommt ihr heraus?
Man beachte, dass Bitshift eigentlich nur bei Unsigned werten Sinn macht (Math. gesehen), aber da ein Integer einfach nur als MSB das vorzeichen hat, wäre das Vorzeichen als offset 31 auslesbar.
Vielleicht hilft dieser Tipp den Fortgeschrittenen und Profis hier ein wenig weiter; wenn es um die ultimative Performance und eleganten Code geht.
Rückfragen beantworte ich gerne, nur zu. Auch Kritik ist erwünscht.
Seit .NET FW 1.1 gibt es die sog. BitShift-Operatoren
<< (-> LShift od. Links-shift) und
>> (-> RShift od. Rechts-shift)
Diese machen Mathematisch gesehen:
ACHTUNG: sie "kegeln" die anderen Bits einfach raus und schreiben am "Anfang" oben rein:
1001 >> 3 = 0001 (1001 << 3 = 1000)
Folgender Stub sollte die Funktionsweise eläutern (gibt in der Konsole ein paar Operationen aus):
VB.NET-Quellcode
- Module Module1
- Sub Main()
- Dim b As UInteger = 1 '= 2^0
- For i = 0 To 10
- Console.WriteLine("1 << " & i & ": " & (b << i))
- Next
- b = 65536 '= 2^16 = 0x010000 = 0b1:0000:0000:0000:0000 (Hier sieht man besonders schön, was der maximalwert für einen Int16 (Short) ist: 2^16 - 1
- For i = 0 To 16
- Console.WriteLine("65536 >> " & i & ": " & (b >> i))
- Next
- Console.ReadLine()
- End Sub
- End Module
Daraus ergibt sich ein sehr schneller Bitflag-Code:
VB.NET-Quellcode
- Public Shared Function BitFlag(flags As UInt32, offset As Integer) As Boolean
- 'offset muss zwischen 0 und 31 liegen, da 2^32 > UInt32.MaxValue
- 'dementsprechend reicht ein Byte aus.
- 'Da VB aber standardmäßig mit Integer (bzw. Long bei x64) rechnet, wäre dann mehr (langsamere) Konveriterung erforderlich
- If offset < 0 OrElse offset > 31 Then Throw New ArgumentOutOfRangeException("offset", "Es sind nur Werte zwischen 0 und 31 (einschliesslich) erlaubt")
- Return (((flags >> offset) Mod 2) = 1)
- End Function
Die Modulation mit 2 = 0010 sorgt dafür, dass wir den Stellenwert des LSB bekommen (wo wir vorher das gesuchte Bit hingeshiftet haben).
Vergleich mit 1 gibt demnach den Boolschen Wert des Bits zurück - ein sehr schneller Einzeiler, der es in sich hat
Alternativ dazu kann man auch mit dem And-Operator arbeiten und den offset "hochshiften":
VB.NET-Quellcode
//EDIT:
Wie vermutet wird in dem Fall bei VB implizit konvertiert, also bleibt noch 1 << offset > 0 (für alle offset im zugelassenen bereich) also abschätzung.
Was schneller ist, werde ich nun überprüfen.
//EDIT:
Ich werde
Dieser Vorgang, 5x Wiederholt ergibt
//EDIT2:
Ich habe nun also
500 Iterationen mit
10000000 UIntgers Testdaten (Eigene für jede Iteration)
gemacht.
Hier die Durchschnittswerte (in Ticks / Loop = Ticks / UInteger (jedes Bit)):
BitFlag1: 32261,858
BitFlag2: 23841,384
BitFlag3: 25041,44
Demnach ist die schnellste Operation (flags And 1 << offset) = 1 << offset
Hier die Testklasse: clsBitFlagBM.vb
Wenn ihr in der Main den Initialisierungswert von
ändert, könnt ihr die Testbreite variieren.
Was bekommt ihr heraus?
Man beachte, dass Bitshift eigentlich nur bei Unsigned werten Sinn macht (Math. gesehen), aber da ein Integer einfach nur als MSB das vorzeichen hat, wäre das Vorzeichen als offset 31 auslesbar.
Vielleicht hilft dieser Tipp den Fortgeschrittenen und Profis hier ein wenig weiter; wenn es um die ultimative Performance und eleganten Code geht.
Rückfragen beantworte ich gerne, nur zu. Auch Kritik ist erwünscht.
Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „FAtheone“ () aus folgendem Grund: Benchmarkergebnisse