XOR-Operator für logische Werte?



  • Hi,

    ist es möglich, den XOR-Operator für logische Werte einzusetzen?
    Beispiel:

    if ((a>b)^(a<c))
    

    Oder muss so stehen:

    if( ((a>b)^(a<c)) == 1)
    

    ?

    Gruss



  • Du darfst die kurze Version verwenden.

    Die Vergleiche sorgen für Ergebnisse Null oder nicht Null und auch die binäre Verknüpfung sorgt für ein boole- auswertungsmäßiges Ergebnis, eben Null oder nicht Null.
    Edit: Der explizite Vergleich gegen eins ist sogar problematischer, besser != 0 verwenden!



  • Das Äquivalent zum logischen xor ist eigentlich der Vergleich auf Ungleichheit.

    if ((a>b)!=(a<c))
    

    Nicht jede Sprache erlaubt bitweise Operatoren für boolsche Ausdrücke. Dass C dies erlaubt, liegt wohl auch nur an der impliziten Umwandlung bzw an der fehlenden strikten Typisierung für Wahrheitswerte. 🙂



  • groovemaster schrieb:

    Das Äquivalent zum logischen xor ist eigentlich der Vergleich auf Ungleichheit.

    Gut erklärt, um's abzurunden: C kennt bei der logischen Auswertung nur (leer == 0) oder (irgendwasdrin != 0), das ist allen Prozessoren sehr nahe (zero- Flag), gibt flotten Code ab.
    Durch die Terme (a>b) usw. bildest Du das logische Ergebnis auf das Deiner Plattform (Compiler/Target/OS) ab und rein logisch unterscheiden sich dann "^" und "!=" nicht.
    Wenn Dein Compiler aber keine "1" für logisch "nicht 0" vorhält (kann sein), führt Dein Vergleich ggf. über den Jordan,
    deswegen ist "!= 0" was anderes als "== 1". 😉



  • pointercrash() schrieb:

    Wenn Dein Compiler aber keine "1" für logisch "nicht 0" vorhält (kann sein), führt Dein Vergleich ggf. über den Jordan,
    deswegen ist "!= 0" was anderes als "== 1". 😉

    Das wäre dann aber ein Compilerfehler. Der Standard sagt, dass der boolsche Wert true dem Wert 1 (Typ int) entspricht.



  • Tim schrieb:

    Das wäre dann aber ein Compilerfehler. Der Standard sagt, dass der boolsche Wert true dem Wert 1 (Typ int) entspricht.

    Du hast noch nie Pferde vor der Apotheke kotzen gesehen?

    Mein NC74 verwendet für boolesche Ergebnisse Typ char 255 und 0, hat man oft so für 8 Bit-Akkumaschinen gemacht, weil so logische und binäre Operationen weitgehend zusammenfallen. In den Precautions ist hauptsächlich vermerkt, daß ich den Compiler entscheiden lassen soll, was er für "nicht 0" nehmen mag und ein paar andere don'ts. Für's Ergebnis ist das egal und somit kein Fehler.

    Schon klar, jetzt kommt der ANSI- Zeigefinger, ich kann mit einem switch extended ANSI- compatibility erzwingen, dann muß sich aber der kleine Prozessor bei solchen Geschichten ordentlich abrackern - wozu denn, es ist nur möglicherweise nicht genau, was der Standard sagt, aber wen juckt's? Der Standard würde bei diesen Kistchen nur die Performance schädigen.



  • Wenn man das Ergebnis (genauer, den Wert) eines Vergleichs nicht weiter verwenden, sondern nur den Programmfluss steuern will, ist es auch total egal ob da 1, 5 oder 255 im Register steht. z.B.:

    if ( a > b ) {
        // ...
    }
    

    Relevant ist der (Zahlen-)Wert des Ausdrucks ( a > b ) nur wenn dieser weiterverarbeitet wird. z.B.:

    uint8_t status = 0;
    status |= ( a >  b ) << 0;
    status |= ( a == b ) << 1;
    status |= ( a >  c ) << 2;
    // ...
    

    Und selbst dann wäre es doch wohl nur eine Operation mehr, um aus einem 255 eine 1 zu machen. Von "ordentlich abrackern" kann hier imho nicht die Rede sein.



  • Tim schrieb:

    Und selbst dann wäre es doch wohl nur eine Operation mehr, um aus einem 255 eine 1 zu machen. Von "ordentlich abrackern" kann hier imho nicht die Rede sein.

    Sogar Dir könnte klar sein, daß für 'nen 8- Bitter eine Integer 1 auf den Returnstack zu legen, bei einem 6502- Derivat viermal indirekt- indizierten Zugriff bedeutet und daß die Compilerdesigner die Notwendigkeit dafür zu verhindern suchten. Stattdessen verboten sie by default numerische Auswertungen logischer Verknüpfungen und nutzten aus, daß ein 8- bittiges 255 invertiert 0 ergibt (ein Befehl) und umgedreht.

    Eine 1 wird ja so bekanntermaßen zu 254 (uchar) bzw. 65534 (uint) respektive zur -2 (int), was ja wohl die durchdachteste aller Lösungen sein dürfte, weil hochheiliger Standard.

    Nur, wenn ich das fordere, bleibt merklich mehr Zeit liegen, zumindest bei den 8- Bittern.

    ANSI hin, ANSI her, "!=0" ist die bessere Wahl.



  • pointercrash() schrieb:

    Tim schrieb:

    Und selbst dann wäre es doch wohl nur eine Operation mehr, um aus einem 255 eine 1 zu machen. Von "ordentlich abrackern" kann hier imho nicht die Rede sein.

    Sogar Dir

    🙄

    pointercrash() schrieb:

    könnte klar sein, daß für 'nen 8- Bitter eine Integer 1 auf den Returnstack zu legen, bei einem 6502- Derivat viermal indirekt- indizierten Zugriff bedeutet

    Nein, erklär mal. Und was würde die optimierte, nicht-konforme Lösung mit 0xFF kosten?



  • Tim schrieb:

    Nein, erklär mal. Und was würde die optimierte, nicht-konforme Lösung mit 0xFF kosten?

    Weniger Rechenzeit, alleine beim Umspeichern in den Returnstack die Hälfte (wg. 8Bit/16Bit).
    Die Invertierung braucht zudem keine Vergleiche, weil man sie über die binäre Invertierung abbilden kann:

    Standard:
    Akku laden ;1
    Zero- Flag prüfen
    Invertierten Wert laden ; wohl 0

    Geht kürzer:
    Akku laden ;255
    binär invertieren ; ah, da ist ja schon die 0

    Solange man keine CPU hat, die mit 50 Bittest&Branch- Befehlen daherkommt, macht das wirklich was aus. Mag sein, daß Compiler heutzutage das meiste selbst optimieren, aber unter Verzicht auf die numerische Auswertung logischer Operationen "mal so" rund 10% Performance- Plus zu kriegen, ist doch was, oder? 😉



  • muss ja nicht sein, dass so'n compiler aufgrund von vorschriften des C-standards umständlichen code erzeugt. hauptsache ein 'printf ("%d", 9==9)' gibt 'ne 1 aus und nicht -1, 255, 65535, oder sowas. intern kann er ja mit 0xff arbeiten, wenn's besser ist.
    🙂


Anmelden zum Antworten