Flags wie bei LoadImage auseinanderbröseln

Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen

Ratchet

Betreff: Flags wie bei LoadImage auseinanderbröseln

BeitragFr, Jun 17, 2011 11:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich möchte eine meiner Funktionen mit Flags ala LoadImage ausstatten, um beliebige Flags kombinieren zu können. Bloß wie brösel ich innerhalb der Funktion die Werte wieder auseinander, sodass ich weiß welche Flags übergeben wurden? Ging das nicht irgendwie mit Bitverschiebung (shl, shr)?
Ich finde bloß nichts zu dem Thema. Gebt mir mal bitte einen Tipp.

BlitzMax: [AUSKLAPPEN]
Const FLAG1: Byte = 1
Const FLAG2: Byte = 2
Const FLAG3: Byte = 4

Function MeineFunktion(Flags: Byte)
'Und nu???
'Welche Flags wurden übergeben?
End Function

MeineFunktion(FLAG1 | FLAG2 | FLAG3)
[iMac 27"] [3,4GHz Intel Core i5 ] [8GB Ram] [NVIDIA GeForce GTX 775M 2GB] [MacOS X Yosemite] [BlitzMax + MaxGui] [Monkey X Pro]

Ana

BeitragFr, Jun 17, 2011 11:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Du verwendest hier Zahlen die sich durch eine 1 und den rest 0en in binär darstellen lassen. Vergleichst du also bitweise kannst du feststellen welche flags alle aktiv sind.

Tip genug?
Don't only practice your art,
but force your way into its secrets,
for it and knowledge
can raise human to divine

Midimaster

BeitragFr, Jun 17, 2011 12:01
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzMax: [AUSKLAPPEN]
Function MeineFunktion(Flags: Byte)
Flag_1 = (Flags & 1)/1
Flag_2 = (Flags & 2)/2
Flag_3 = (Flags & 4)/4
.....
End Function
  • Zuletzt bearbeitet von Midimaster am Sa, Jun 18, 2011 11:05, insgesamt einmal bearbeitet
 

PhillipK

BeitragFr, Jun 17, 2011 12:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich würde es ähnlich wie Midimaster schreiben, allerdings mit dem '&'operator und if abfragen.

Hier mal zum ausführen:

BlitzMax: [AUSKLAPPEN]

Const Flag1:Int = 1
Const Flag2:Int = 2
Const Flag3:Int = 4

Print "~nMeineFunktion mit 1 | 2"
MeineFunktion(Flag1|Flag2)
Print "~nMeineFunktion mit 2 | 4"
MeineFunktion(Flag2|Flag3)
Print "~nMeineFunktion mit 1 | 2 | 4"
MeineFunktion(Flag1|Flag2|Flag3)

Function MeineFunktion(Flags:Byte)
If Flags&Flag1 Then ' Der erste Bit ist gesetzt.
'Auf den ersten Bit reagieren
Print "Der erste Bit wurde gesetzt!"
EndIf
If Flags&Flag2 Then ' Der zweite Bit ist gesetzt.
'Auf den zweiten Bit reagieren
Print "Der zweite Bit wurde gesetzt!"
EndIf
If Flags&Flag3 Then ' Der dritte Bit ist gesetzt.
'Auf den vierten Bit reagieren
Print "Der dritte Bit wurde gesetzt!"
EndIf
End Function


Hier empfielt es sich, mit CONST zu arbeiten, da man sich sonst schnell in den Abfragen verrennt und was falsches ausführt. Zumindest ist das mein Lieblingsfehler Smile

Das ganze lässt sich auch etwas umwegieger mit einer Rekursion und einem Case-baum lösen, davon halte ich allerdings nicht viel. Wenn du magst, versuche ich dennoch, ein Beispiel dafür zusammen zu tippern.

Ratchet

BeitragFr, Jun 17, 2011 17:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Manchmal ist die Antwort einfach zu einfach Wink
Vielen Dank Leute!
[iMac 27"] [3,4GHz Intel Core i5 ] [8GB Ram] [NVIDIA GeForce GTX 775M 2GB] [MacOS X Yosemite] [BlitzMax + MaxGui] [Monkey X Pro]
 

PhillipK

BeitragSa, Jun 18, 2011 10:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Weißt du denn, wie der &-operator funktioniert?

Ist kaum n halbes jahr her, da hab ich mich auch intensiv mit Bitweisem agieren beschäftigt. Mittlerweile kann ich garnicht mehr ohne^^
Damals hat mir glaub ich Noobody n gutes stück geholfen, nu isses an mir, wissen weiterzugeben Smile

Wenn noch fragen bestehen, frag ruhig =)

Midimaster

BeitragSa, Jun 18, 2011 11:10
Antworten mit Zitat
Benutzer-Profile anzeigen
@PhillipK

ich hab meinen Beitrag jetzt geändert und was gelernt dabei: Das "&" ist was ganz anderes als das "AND"

Bei...

BlitzMax: [AUSKLAPPEN]
a%=16 ' Binär= 1000
Print a And 8
Print a & 8


...liefert das "AND" ein falsches Ergebnis. Das wußte ich nicht. Danke!
 

PhillipK

BeitragSa, Jun 18, 2011 11:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Midimaster hat Folgendes geschrieben:
@PhillipK

ich hab meinen Beitrag jetzt geändert und was gelernt dabei: Das "&" ist was ganz anderes als das "AND"

Bei...

BlitzMax: [AUSKLAPPEN]
a%=16 ' Binär= 1000
Print a And 8
Print a & 8


...liefert das "AND" ein falsches Ergebnis. Das wußte ich nicht. Danke!


Nunja, wirklich richtig geändert ist das immernochnicht :-/

(Wert & Zahl) vergleicht, ob die 1erbits aus ZAHL auch in WERT vorkommen - trifft das zu, liefert diese Klammer 1 zurück.

Stimmt dies, rechnest du in deinem beispiel nun 1/1 = 1. 1/2 = 0.5 = 0 (weil int.), 1/4 = 0.25 = 0 (weil int.)

Die abfrage Flags&Flag1 reicht vollkommen, da es entweder 1 oder 0 ist (True oder False)

Was (16 and 8) nun bewirkt, kann ich nicht verstehen.
Wenn ich das austeste, gibt mir das Print ständig die 2te zahl aus.

Print (1 And 8) = 8.
Print (16 And 8) = 8.
Print (16 And 17) = 17.

Kann mir das mal jemand erklären? Very Happy AND kenne ich nur als abfrage, was TRUE zurückgeben sollte, sobald beide vergleiche stimmen.

Midimaster

BeitragSa, Jun 18, 2011 12:25
Antworten mit Zitat
Benutzer-Profile anzeigen
also das kann aber so jetzt nicht stimmen...

bei mir liefert...

BlitzMax: [AUSKLAPPEN]
a%=10 ' Binär= 1010
Print (a & 8)


...nicht eine 1, sondern eine 8 zurück! Die ist zwar auch TRUE, aber halt nicht "1"


Zu dem zweiten Thema hatte ich ehrlich gehofft, dass Du mir da was erklären kannst, Ich bin nämlich genauso überrascht über die Ergebnisse...

mpmxyz

BeitragSa, Jun 18, 2011 12:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Es gibt in BlitzMax keinen expliziten Boolean-Datentyp.
Durch die einfache Rückgabe des ersten bzw. zweiten Wertes bei "And" oder auch bei "Or" wird dadurch einerseits eine Überprüfung gespart und andererseits gibt es eventuell eine Möglichkeit, das praktisch anzuwenden. (In Lua wird das auch so gemacht.)
Wie bei so manchen BlitzMax-Eigenheiten wurde das aber nicht konsequent zu Ende gedacht:
Objektreferenzen werden erst in einen Integer-Wahrheitswert umgewandelt, selbst wenn die Referenzen einen gemeinsamen Typ haben.
Edit: Ich möchte an dieser Stelle auch anmerken, dass BlitzMax die Operatoren optimiert und möglicherweise nur eine Seite berechnet wird.
BlitzMax: [AUSKLAPPEN]
SuperStrict
Print "Das Ergebnis ist: "(Test(True) Or Test(False)) 'hier mit den Zahlenwerten herumspielen

Function Test:Int(value:Int)
Print(value)
Return value
EndFunction

Zum &-Operator: Das ist der bitweise And-Operator. Daher darf Midimaster auch die entsprechende Teilung durchführen.
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

PhillipK

BeitragSa, Jun 18, 2011 12:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Zur teilung:

Die klammer wird doch normalerweise zuerst aufgelöst, oder?
Diese gibt dann den Integer wert '1' zurück, was eine teilung von 1/X zur folge hat - oder irre ich mich da komplett?
Zugegeben, durchgetest und geprintet habe ich das nicht, allerdings haben sonstige erfahrungen mit Blitzmax diese Gleichung in meinem Kopf zurammengebaut Razz

Noobody

BeitragSa, Jun 18, 2011 12:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Der Unterschied zwischen And und & ist, dass And der logische Und-Operator ist und & der bitweise Und-Operator.

And funktioniert so, dass es das erste Argument anschaut und testet, ob es als True ausgewertet wird. Wenn ja, gibt And das zweite Argument zurück, wenn nein, dann gibt es das erste Argument zurück. Or betreibt eine Ähnliche Strategie, indem es das erste Argument zurückgibt, wenn es True ist, und ansonsten das zweite Argument.

Was man hier beachten sollte (und mpmxyz schon bemerkte), ist, dass And und Or sogenannte lazy-evaluation betreiben. Das ist nicht unbedingt aus Performancegründen, sondern mehr für den Programmierkomfort gedacht. So kann man nämlich z.B. If A <> Null And A.TolleFunktion() schreiben, ohne dass das Programm abstürzt, wenn A = Null (da das zweite Argument dann gar nicht ausgewertet wird).

& funktioniert so, dass die Bits vom ersten Argument stellenweise mit den Bits vom zweiten Argument verglichen werden. Sind an einer Stelle die Bits von beiden Argumenten gesetzt, wird auch das Bit im Rückgabewert gesetzt, ansonsten nicht. Wenn man also auf einzelne Flags testet, wird -nicht- True zurückgegeben, wenn das Flag enthalten ist, sondern das Flag selbst. D.h. If (Input & Flag) = Flag Then ...., If (Input & Flag) <> 0 Then .... oder einfach If Input & Flag Then .... sind alles funktionierende Abfragen.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

mpmxyz

BeitragSa, Jun 18, 2011 12:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Noch einmal, PhillipK:
& ist ein bitweiser Operator:
Code: [AUSKLAPPEN]
0 & 0=0
1 & 0=0
1 & 1=0
1 & 2=0, da %01 & %10=%00
2 & 2=2
2 & 3=2, da %10 & %11=%10
127 & 5=5, da %1111111 & %0000101=%0000101

Damit kommt natürlich das entsprechende Ergebnis auch aus der Klammer heraus.
Und wenn alle Bits der Maske enthalten sind, kann man auch durch diese teilen. Dann kommt 1 heraus.
Nur wenn nicht alle Bits der Maske 1 sind, gibt es durch die Integerdivision das Ergebnis 0.
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer

Midimaster

BeitragSa, Jun 18, 2011 13:03
Antworten mit Zitat
Benutzer-Profile anzeigen
@mpmxyz

danke, das erklärt alles. Jetzt hab ich es verstanden. AND kombiniert nur zwei Wahrheitswerte und ist ist ihm deshalb völlig egal ober eine "1" für TRUE oder eine "8" für TRUE steht.

Das Ergebnis ist dann, wenn es TRUE ist, irgendein Werte, der nicht FALSE ist. Daher gilt Alles außer "0" als TRUE.

Das ist eine wichtige neue Erkenntnis für mich, bisher bin ich davon ausgegangen, dass die Funktion immer "0" oder "1" liefern würde. Das heißt es ist z.B. nicht möglich, in einer Schleife mehrere Wahrheitswerte zusammenzuzählen und nachher zu behaupten, es wären z.b. 8 mal der Zustand TRUE eigetreten, bloß weil die Summe aus den TRUEs 8 war.

Midimaster

BeitragSa, Jun 18, 2011 13:14
Antworten mit Zitat
Benutzer-Profile anzeigen
@Noobody

Wenn Du eine Zahl darauf untersuchen möchtest, ob nur ein einzelnen Flag gesetzt ist, stimmt das mit den 3 Möglichkeiten...

Aber wie sieht es aus, wenn ich checken möchte, ob Bit1 und Bit2 gleichzeitig gesetzt sind:

BlitzMax: [AUSKLAPPEN]
Zahl%=5  '=1001
Print " Methode (Zahl & 3) :"
If (Zahl & 3) Then
Print "beide Bits sind gleichzeitig gesetzt"
Else
Print "beide Bits sind nicht gleichzeitig gesetzt"
EndIf
Print
Print " Methode (Zahl & 3)/3 :"
If (Zahl & 3)/3 Then
Print "beide Bits sind gleichzeitig gesetzt"
Else
Print "beide Bits sind nicht gleichzeitig gesetzt"
EndIf

ZaP

BeitragSa, Jun 18, 2011 15:31
Antworten mit Zitat
Benutzer-Profile anzeigen
Für das Beispiel Fünf (101):

BlitzMax: [AUSKLAPPEN]

If (Zahl & 4) And (Zahl & 1) Then


Oder allgemeiner:

BlitzMax: [AUSKLAPPEN]

For i = 0 To 31
If 2^i & Zahl Then Print "Flag #" + i + " gesetzt."
Next
Starfare: Worklog, Website (download)

DaysShadow

BeitragSa, Jun 18, 2011 15:32
Antworten mit Zitat
Benutzer-Profile anzeigen
@ Midimaster:

Einfach die zu prüfenden Flags mit bitweisen Or verknüpfen und das Ergebnis dann mit den gesamten Flags normal überprüfen.

BlitzMax: [AUSKLAPPEN]
Global flags:Int

Global flag1:Int = 2
Global flag2:Int = 4
Global flag3:Int = 8

flags = flag1 | flag2 | flag3

Print flags '14

If( flags & ( flag1 | flag2 ) )

Print( "Flag 1 and 2 set" )

Else

Print( "Flag 1 and 2 are not set" )

End If
Blessed is the mind too small for doubt
 

PhillipK

BeitragSa, Jun 18, 2011 15:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Jetzt bin ich verwirrt.

wenn ich ein If habe, welches keinen vergleich vornimmt, tritt es also ein, wenn das ergebnis > 0 ist?
Bzw <> 0?

If (15 & 8) then '1111 & 1000 -> sollte 8 zurückgeben.
Dieser fall tritt in meinen Abfragen ein.
If (7 & 8) then ' 0111 & 1000 -> sollte 0 zurückgeben.

Wenn dem so ist, habe ich leider all die Zeit die abfragen falsch interpretiert, und somit muss ich mich entschuldigen, was die Teilung angeht.
Jedesmal, wenn ich mir sicher war, das meine rückgabe > 1 und <> 0 war, habe ich explizit mit einem = abgeglichen, welcher wert es war, bzw > 1 abgefragt.

Edit:

ZaP hat Folgendes geschrieben:

Oder allgemeiner:

BlitzMax: [AUSKLAPPEN]

For i = 0 To 31
If 2^i & Zahl Then Print "Flag #" + i + " gesetzt."
Next


Das ganze würde ich ein wenig simpler schreiben^^

BlitzMax: [AUSKLAPPEN]

For i = 0 To 31
If ((1 Shl i) & Zahl) Then Print "Flag #"+i+" gesetzt."
Next

Grund für meine art ist, das ^ meines wissen extrem langsam sein soll, mit dem shiften von 1 kriegt man das gleiche hin.

Midimaster

BeitragSa, Jun 18, 2011 15:56
Antworten mit Zitat
Benutzer-Profile anzeigen
@DaysShadow

nee is nich...

Probiers mal:

BlitzMax: [AUSKLAPPEN]
Global flags:Int

Global flag1:Int = 2
Global flag2:Int = 4
Global flag3:Int = 8

flags = flag1 | flag3

Print flags '12

If( flags & ( flag1 | flag2 ) )

Print( "Flag 1 and 2 set" )

Else

Print( "Flag 1 and 2 are not set" )

End If

Noobody

BeitragSa, Jun 18, 2011 16:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Hier funktioniert die Abfrage <> 0 natürlich nicht. Kurz veranschaulicht: Code: [AUSKLAPPEN]

0101 'Flag 1 und 3 sind gesetzt
  &
0011 'Flag 1 und 2 sind gesetzt
  =
0001 'Ergebnis des bitweisen Unds

Wie man sieht, ist der Rückgabewert ungleich null, obwohl die gesuchten Flags 1 und 2 nicht beide gesetzt waren. Hier muss man also explizit auf Gleichheit überprüfen: BlitzMax: [AUSKLAPPEN]
Global Flags:Int, Flag1:Int = 2, Flag2:Int = 4, Flag3:Int = 8

Flags = Flag1 | Flag3

If (Flags & (Flag1 | Flag2)) = (Flag1 | Flag2) Then
Print "Flag 1 and 2 set"
Else
Print "Flag 1 and 2 are not set"
End If

Hier ist aber die erste Variante von Zap (die Flags einzeln testen und mit logischem And verknüpfen) um einiges weniger umständlich.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group