So definieren Sie "oder" logisch

36

Kürzlich stieß ich auf ein Problem, bei dem ich den logischen Operator "OR" programmgesteuert definieren musste, ohne den Operator selbst zu verwenden.

Was ich mir ausgedacht habe, ist Folgendes:

OR(arg1, arg2)
  if arg1 = True and arg2 = True
     return True

  else if arg1 = True and arg2 = False
     return True

  else if arg1 = False and arg2 = True
     return True

  else:
     return False

Ist diese Logik richtig oder habe ich etwas verpasst?

logicNoob
quelle
10
@gnat: Um fair zu sein, listet eine Wahrheitstabelle die Ausgaben für jede Kombination der Eingaben auf, und der Wikipedia-Artikel gibt eine Beschreibung der Funktion. Ich denke, was das OP wirklich fragt, ist, wie man ein logisches ODER programmatisch ohne die Verwendung des Operators selbst definiert.
Blrfl
6
@ user3687688 Können Sie bitte die Grundelemente erläutern, die wir verwenden dürfen?
Fredoverflow
4
Diese Frage hat einen kollektiven Krampf der Mikrooptimierung ausgelöst;)
Rob
8
Sie könnten den ternären Operator verwendenreturn arg1 ? arg1 : arg2;
Matthew
4
Ich muss wissen, warum Sie den orOperator neu definieren mussten .
Kyle Strand

Antworten:

102

Ich würde sagen, das ist richtig, aber könnten Sie es nicht auf so etwas reduzieren?

or(arg1, arg2)
    if arg1 == true
        return true
    if arg2 == true
        return true

    return false

Da Sie eine oder einen Vergleich durchführen, glaube ich nicht, dass Sie die Kombination wirklich überprüfen müssen. Es ist nur wichtig, ob einer von ihnen wahr ist, um wahr zurückzukehren. Andernfalls möchten wir false zurückgeben.

Wenn Sie nach einer kürzeren Version suchen, die weniger ausführlich ist, funktioniert dies auch:

or(arg1, arg2)
    if arg1
        return arg1
    return arg2
Elliot Blackburn
quelle
6
Sie können auch das "else" in Zeile 4 entfernen (nur verlassen if arg2 == true).
Dawson Toth
1
@DawsonToth Es gibt viele verschiedene Möglichkeiten, wie Sie es drehen können, je nachdem, ob Sie wirklich ausführlich oder komprimiert sein möchten. Ich wäre mit dem Anderen zufrieden, wenn es sich aber so anhört, als wäre es eine Pseudocode-Frage, daher würde ich es der Klarheit halber wahrscheinlich so belassen. Sehr wahr!
Elliot Blackburn
@BlueHat Es scheint etwas inkonsistent zu sein, ein else if zu verwenden, am Ende jedoch kein else.
SBoss
1
@Mehrdad Danke! Ich habe die alte Antwort wieder aufgenommen, nur weil ich das Gefühl habe, dass sie etwas ausführlicher ist und die Lösung ein bisschen klarer erklärt. Aber Ihre Lösung ist viel kleiner und erledigt den gleichen Job.
Elliot Blackburn
1
noch besser (schlechter):or(a, b): a ? a : b
sara
149

Hier ist eine Lösung ohne oder und nicht ohne Vergleiche und boolesche Literale:

or(arg1, arg2)
  if arg1
    return arg1
  else
    return arg2

Fundamentaler geht es wohl nicht;)

fredoverflow
quelle
32
+1 für eine etwas kürzere Antwort als meine. Ich wäre jedoch versucht, das "Sonst" auch nur wegen der Eleganz fallen zu lassen.
Elliot Blackburn
10
@BlueHat Aber dann würden die beiden Rückgaben unterschiedlich eingerückt werden;)
Fredoverflow
5
Ich würde gerne jedes Mal einen EUR bekommen, wenn jemand etwas mit trueoder vergleicht false.
JensG
1
@JensG Woher kommt wohl das Einkommen von Bill Gates?
Kroltan
1
Kurz ||gesagt, JavaScript- Operator (bei Implementierung in einer dynamisch typisierten Sprache).
Nashorn
108

Eine Codezeile:

return not (not arg1 and not arg2)

Keine Verzweigung, kein ODER.

In einer C-basierten Sprache wäre es:

return !(!arg1 && !arg2);

Dies ist einfach eine Anwendung von De Morgans Gesetzen :(A || B) == !(!A && !B)


quelle
6
Ich denke, dieser Ansatz ist die beste Lösung, da (meiner Meinung nach) ein if/elseKonstrukt das gleiche ist wie die Verwendung von OR, nur mit einem anderen Namen.
Nick
2
@Nick using ifentspricht der Gleichheit. Normalerweise wird in Maschinencode eine ifals Arithmetik implementiert, gefolgt von einem Vergleich mit einem Sprung auf Null.
1
Ich mag diesen Ansatz, weil er IFF- andKurzschlüsse kurzschließt und so für Konsistenz unter den Betreibern sorgt.
Kyle Strand
1
@Schneemann Das stimmt. Ich meinte, das if (a) return true; else if (b) return true;scheint mehr oder weniger moralisch gleichwertig zu sein if (a OR b) return true;, aber diese Ansicht kann durchaus bestritten werden.
Nick
13

Wenn Sie nur andund haben not, können Sie das DeMorgan-Gesetz zum Umblättern verwenden and:

if not (arg1 = False and arg2 = False)
  return True
else
  return False

... oder (noch einfacher)

if arg1 = False and arg2 = False
  return false
else
  return true

...

Und da wir alle offensichtlich darauf fixiert sind, etwas zu optimieren, das sowieso fast immer als Maschinenanweisung verfügbar ist, läuft das auf Folgendes hinaus:

return not(not arg1 and not arg2)

return arg1 ? true : arg2

usw. usw. usw. usw.

Da die meisten Sprachen ein Bedingungs- und liefern, impliziert der Operator "und" ohnehin eine Verzweigung.

...

Wenn alles, was Sie haben, ist nand(siehe Wikipedia ):

return nand (nand (arg1, arg1), nand (arg2, arg2))

rauben
quelle
7
Vereinfachen:return not (not arg1 and not arg2)
@Snowman du solltest das wirklich eine Antwort machen damit ich es positiv bewerten kann. Sie sind (derzeit) der Einzige hier, der sich nicht mit der Verzweigung beschäftigt hat.
Lawtonfogle
4
Wollte die NAND-Lösung hinzufügen, aber du hast mich geschlagen. Alles sollte in Bezug auf NAND implementiert werden.
Andy
2
@Andy: Eigentlich sollte alles in Bezug auf NOR definiert sein. ;-)
Pieter Geerkens
1
Gute Arbeit mit der reinen nandLösung.
AAT
13

Funktionen (ECMAScript)

Sie benötigen lediglich Funktionsdefinitionen und Funktionsaufrufe. Sie benötigen keine Verzweigungen, Bedingungen, Operatoren oder eingebauten Funktionen. Ich werde eine Implementierung mit ECMAScript demonstrieren.

Definieren wir zunächst zwei Funktionen namens trueund false. Wir können sie so definieren, wie wir wollen, sie sind völlig willkürlich, aber wir werden sie auf eine ganz besondere Art definieren, die einige Vorteile hat, wie wir später sehen werden:

const tru = (thn, _  ) => thn,
      fls = (_  , els) => els;

truist eine Funktion mit zwei Parametern, die das zweite Argument einfach ignoriert und das erste zurückgibt. flsist auch eine Funktion mit zwei Parametern, die das erste Argument einfach ignoriert und das zweite zurückgibt.

Warum haben wir truund auf flsdiese Weise codiert ? Nun, auf diese Weise, die beiden Funktionen nicht nur repräsentieren die beiden Begriffe trueund false, nein, zugleich, sie auch das Konzept der „Wahl“, mit anderen Worten darstellen, sind sie auch ein if/ then/ elseAusdruck! Wir werten die ifBedingung aus und übergeben sie als Argumente an den thenBlock und den elseBlock. Wenn die Bedingung den Wert "0" ergibt tru, wird der thenBlock zurückgegeben. Wenn die Bedingung den Wert "0" ergibt fls, wird der elseBlock zurückgegeben. Hier ist ein Beispiel:

tru(23, 42);
// => 23

Dies kehrt zurück 23und dies:

fls(23, 42);
// => 42

kehrt zurück 42, so wie Sie es erwarten würden.

Es gibt jedoch eine Falte:

tru(console.log("then branch"), console.log("else branch"));
// then branch
// else branch

Dies druckt sowohl then branch als auch else branch! Warum?

Nun, es gibt den Rückgabewert des ersten Arguments zurück, wertet jedoch beide Argumente aus, da ECMAScript streng ist und immer alle Argumente für eine Funktion auswertet, bevor die Funktion aufgerufen wird. IOW: Es wertet das erste Argument aus console.log("then branch"), das einfach zurückgibt undefinedund den Nebeneffekt des Druckens then branchauf die Konsole hat, und es wertet das zweite Argument aus, das ebenfalls undefinedals Nebeneffekt zurückgibt und auf die Konsole druckt. Dann wird der erste zurückgegeben undefined.

In λ-Kalkül, wo diese Kodierung erfunden wurde, ist das kein Problem: λ-Kalkül ist rein , was bedeutet, dass es keine Nebenwirkungen hat; daher würde man nie bemerken, dass das zweite Argument auch ausgewertet wird. Außerdem ist λ-Kalkül faul (oder zumindest wird es oft in normaler Reihenfolge ausgewertet), was bedeutet, dass es keine Argumente auswertet, die nicht benötigt werden. Also, IOW: In der λ-Rechnung würde das zweite Argument niemals ausgewertet, und wenn es so wäre, würden wir es nicht bemerken.

ECMAScript ist jedoch streng , dh es wertet immer alle Argumente aus. Nun, eigentlich nicht immer: der if/ then/ elsezum Beispiel wertet nur den thenZweig , wenn die Bedingung ist trueund wertet nur den elseZweig , wenn die Bedingung ist false. Und dieses Verhalten wollen wir mit unserem replizieren iff. Glücklicherweise kann ECMAScript, obwohl es nicht faul ist, die Auswertung eines Codeteils verzögern, so wie es fast jede andere Sprache tut: Es wird in eine Funktion eingebunden, und wenn Sie diese Funktion nie aufrufen, wird der Code dies tun nie hingerichtet werden.

Wir binden also beide Blöcke in eine Funktion ein und rufen am Ende die zurückgegebene Funktion auf:

tru(() => console.log("then branch"), () => console.log("else branch"))();
// then branch

druckt then branchund

fls(() => console.log("then branch"), () => console.log("else branch"))();
// else branch

druckt else branch.

Wir konnten die traditionelle implementieren if/ then/ auf elsediese Weise:

const iff = (cnd, thn, els) => cnd(thn, els);

iff(tru, 23, 42);
// => 23

iff(fls, 23, 42);
// => 42

Auch hier benötigen wir einen zusätzlichen Funktionsumbruch beim Aufrufen der iffFunktion und der zusätzlichen Funktionsaufrufklammern in der Definition von iff, und zwar aus dem gleichen Grund wie oben:

const iff = (cnd, thn, els) => cnd(thn, els)();

iff(tru, () => console.log("then branch"), () => console.log("else branch"));
// then branch

iff(fls, () => console.log("then branch"), () => console.log("else branch"));
// else branch

Nachdem wir diese beiden Definitionen haben, können wir sie implementieren or. Zunächst untersuchen wir die Wahrheitstabelle nach or: Wenn der erste Operand wahr ist, ist das Ergebnis des Ausdrucks dasselbe wie der erste Operand. Ansonsten ist das Ergebnis des Ausdrucks das Ergebnis des zweiten Operanden. Kurz gesagt: Wenn der erste Operand ist true, geben wir den ersten Operanden zurück, andernfalls geben wir den zweiten Operanden zurück:

const orr = (a, b) => iff(a, () => a, () => b);

Lassen Sie uns herausfinden, dass es funktioniert:

orr(tru,tru);
// => tru(thn, _) {}

orr(tru,fls);
// => tru(thn, _) {}

orr(fls,tru);
// => tru(thn, _) {}

orr(fls,fls);
// => fls(_, els) {}

Groß! Diese Definition sieht jedoch etwas hässlich aus. Denken Sie daran, truund flshandeln Sie bereits wie eine Bedingung für sich, so dass wirklich keine Notwendigkeit besteht iff, und daher all diese Funktionen überhaupt zu umschließen:

const orr = (a, b) => a(a, b);

Da haben Sie es: or(plus andere boolesche Operatoren) definiert mit nichts als Funktionsdefinitionen und Funktionsaufrufen in nur wenigen Zeilen:

const tru = (thn, _  ) => thn,
      fls = (_  , els) => els,
      orr = (a  , b  ) => a(a, b),
      nnd = (a  , b  ) => a(b, a),
      ntt = a          => a(fls, tru),
      xor = (a  , b  ) => a(ntt(b), b),
      iff = (cnd, thn, els) => cnd(thn, els)();

Leider ist diese Implementierung ziemlich nutzlos: Es gibt keine Funktionen oder Operatoren in ECMAScript, die zurückgeben truoder flsalle zurückgeben trueoder false, daher können wir sie nicht mit unseren Funktionen verwenden. Aber wir können noch viel tun. Dies ist beispielsweise eine Implementierung einer einfach verknüpften Liste:

const cons = (hd, tl) => which => which(hd, tl),
      car  = l => l(tru),
      cdr  = l => l(fls);

Gegenstände (Scala)

Sie haben vielleicht bemerkt etwas Besonderes: truund flseine doppelte Rolle spielen, wirken sie sowohl als die Datenwerte trueund false, aber zur gleichen Zeit, sie auch als bedingter Ausdruck handeln. Sie sind Daten und Verhalten , gebündelt in einem ... ähm ... "Ding" ... oder (wage ich zu sagen) Objekt !

In der Tat truund flssind Objekte. Und wenn Sie jemals Smalltalk, Self, Newspeak oder andere objektorientierte Sprachen verwendet haben, werden Sie feststellen, dass sie Boolesche Werte genauso implementieren. Ich werde eine solche Implementierung hier in Scala demonstrieren:

sealed abstract trait Buul {
  def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): T
  def &&&(other:Buul): Buul
  def |||(other:Buul): Buul
  def ntt: Buul
}

case object Tru extends Buul {
  override def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): U = thn
  override def &&&(other:Buul) = other
  override def |||(other:Buul): this.type = this
  override def ntt = Fls
}

case object Fls extends Buul {
  override def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): V = els
  override def &&&(other:Buul): this.type = this
  override def |||(other:Buul) = other
  override def ntt = Tru
}

object BuulExtension {
  import scala.language.implicitConversions
  implicit def boolean2Buul(b:Boolean) = if (b) Tru else Fls
}

import BuulExtension._

(2 < 3) { println("2 is less than 3") } { println("2 is greater than 3") }
// 2 is less than 3

Dies ist übrigens der Grund, warum das Refactoring "Bedingt durch Polymorphismus ersetzen" immer funktioniert: Sie können immer alle Bedingungen in Ihrem Programm durch polymorphen Nachrichtenversand ersetzen, da der polymorphe Nachrichtenversand, wie wir gerade gezeigt haben, Bedingungen durch einfaches Implementieren ersetzen kann. Sprachen wie Smalltalk, Self und Newspeak sind der Existenzbeweis dafür, weil diese Sprachen nicht einmal Bedingungen haben. (Sie haben auch keine Schleifen, BTW oder wirklich irgendeine Art von in die Sprache eingebauten Kontrollstrukturen, außer für den polymorphen Nachrichtenversand, auch bekannt als virtuelle Methodenaufrufe.)


Mustervergleich (Haskell)

Sie können auch ormithilfe des Mustervergleichs oder so etwas wie den Definitionen der Teilfunktionen von Haskell definieren:

True ||| _ = True
_    ||| b = b

Natürlich ist der Mustervergleich eine Form der bedingten Ausführung, aber auch der objektorientierte Nachrichtenversand.

Jörg W. Mittag
quelle
2
Wie wäre es False ||| False = Falseund _ ||| _ = Truestattdessen? :)
Fredoverflow
3
@FredOverflow: Dazu müsste immer der richtige Operand ausgewertet werden. Normalerweise wird von booleschen Operatoren erwartet, dass sie in ihrem richtigen Argument, auch "Kurzschließen" genannt, nicht streng sind.
Jörg W Mittag
Ah, natürlich. Ich wusste, dass es einen tieferen Grund geben musste :)
Fredoverflow
Der erste Teil erinnerte mich sofort an Eric Lipperts großartige Serie über Continuation Passing . Rein zufällig, aber immer noch lustig :)
Voo
1
@ JörgWMittag FredOverflows Definition ist ein angemessener Kurzschluss. Versuchen True ||| undefinedSie sich in Ghci zu sehen!
Daniel Wagner
3

Hier ist eine andere Möglichkeit, OR oder einen beliebigen logischen Operator auf die traditionellste Weise zu definieren: Verwenden Sie eine Wahrheitstabelle.

Dies ist natürlich in höheren Sprachen wie Javascript oder Perl ziemlich trivial, aber ich schreibe dieses Beispiel in C, um zu zeigen, dass die Technik nicht von höheren Sprachfunktionen abhängt:

#include <stdio.h>

int main (void) {
    // Define truth table for OR:
    int OR[2][2] = {
        {0,   // false, false
         1},  // false, true
        {1,   // true, false
         1}   // true, true
    }

    // Let's test the definition
    printf("false || false = %d\n",OR[1==2]['b'=='a']);
    printf("true || false = %d\n",OR[10==10]['b'=='a']);

    // Usage:
    if (OR[ 1==2 ][ 3==4 ]) {
        printf("at least one is true\n");
    }
    else {
        printf("both are false\n");
    }
}

Sie können dasselbe mit AND, NOR, NAND, NOT und XOR tun. Der Code ist so sauber, dass er wie eine Syntax aussieht, sodass Sie folgende Aufgaben ausführen können:

if (OR[ a ][ AND[ b ][ c ] ]) { /* ... */ }
Slebetman
quelle
Ich denke, dies ist der "reinste" Ansatz in gewissem mathematischen Sinne. Der OR-Operator ist schließlich eine Funktion, und die Wahrheitstabelle ist wirklich die Essenz dieser Funktion als Relation und Menge. Natürlich könnte dies auch auf amüsante Weise geschrieben werden:BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
KOMMEN SIE VOM
3

Eine andere Möglichkeit, die logischen Operatoren als ganzzahlige arithmetische Ausdrücke auszudrücken (sofern möglich). Auf diese Weise können viele Verzweigungen für einen größeren Ausdruck vieler Prädikate vermieden werden.

Sei Wahr 1 Sei Falsch 0

Wenn die Summe von beiden größer als 1 ist, ist es wahr oder falsch, zurückgegeben zu werden.

boolean isOR(boolean arg1, boolean arg2){

   int L = arg1 ? 1 : 0;
   int R = arg2 ? 1 : 0;

   return (L+R) > 0;

}
Senthu Sivasambu
quelle
6
booleanExpression ? true : falseist trivial gleich booleanExpression.
Keen
Ich mag Ihre Methodik, aber ein einfacher Fehler ist, dass die Summe beider Argumente größer als NULL sein muss, um wahr zu sein, und nicht größer als EINS.
Grantly
1
return (arga+argb)>0
Grantly
1
Ich habe nur Ihren Text korrigiert. Ihr Code ist perfekt, könnte aber in einer Zeile stehen: return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0); :)
Grantly
1
@SenthuSivasambu Ich habe keine Einwände gegen Ihre Verwendung von arg1 ? 1 : 0;. Das sind zuverlässige Ausdrücke, um einen Booleschen Wert in eine Zahl umzuwandeln. Es ist nur die return-Anweisung, die trivial überarbeitet werden kann.
Keen
1

Die zwei Formen:

OR(arg1, arg2)
  if arg1
     return True
  else:
     return arg2

ODER

OR(arg1, arg2)
  if arg1
     return arg1
  else:
     return arg2

Haben neben dem Code golf-ähnlichen Vorteil, etwas kleiner als die anderen Vorschläge bisher zu sein, einen Zweig weniger. Es ist nicht einmal so dumm, die Anzahl der Zweige mit einem Mikro-Opt zu reduzieren, wenn wir über die Schaffung eines Grundelements nachdenken, das daher sehr häufig verwendet wird.

Die Definition von Javascript ||ist ähnlich, was zusammen mit der losen Schreibweise bedeutet, dass der Ausdruck false || "abc"den Wert "abc"und 42 || "abc"den Wert hat 42.

Wenn Sie bereits andere logische Operatoren haben, haben solche nand(not(arg1), not(arg2))möglicherweise den Vorteil, dass überhaupt keine Verzweigung erfolgt.

Jon Hanna
quelle
Was nützt es, die vorherige Antwort zu wiederholen ( wie Sie zugegeben haben )?
gnat
@gnat es ist nah genug, dass ich mich nicht darum gekümmert hätte, wenn ich diese Antwort gesehen hätte, aber es hat immer noch etwas, das in keinem von ihnen gefunden wurde, also lasse ich es.
Jon Hanna
@gnat, eigentlich überlegend: "Wir suchen nach langen Antworten, die eine Erklärung und einen Kontext liefern." Mit dieser Antwort bin ich jetzt glücklicher.
Jon Hanna
1

Zusätzlich zu allen programmierten Lösungen, die das if-Konstrukt verwenden, ist es möglich, ein ODER-Gatter durch Kombinieren von drei NAND-Gattern zu konstruieren. Wenn Sie sehen möchten, wie es in Wikipedia gemacht wird, klicken Sie hier .

Daraus ergibt sich der Ausdruck,

NICHT [NICHT (A UND A) UND NICHT (B UND B)]

die NOT und AND verwendet, gibt die gleiche Antwort wie OR. Beachten Sie, dass die Verwendung von NOT und AND nur eine unklare Möglichkeit ist, NAND auszudrücken.

Walter Mitty
quelle
NICHT (A UND A) == NICHT (A)?
Charlie
Ja genau. In demselben Wikipedia-Artikel können Sie sehen, wie sie ein NOT-Gatter auf NAND-Gatter reduzieren. Gleiches gilt für ein UND-Gatter. Ich habe mich dafür entschieden, die Formel, die sie für das OP-Gatter vorgelegt haben, nicht zu bearbeiten.
Walter Mitty
1

Alle guten Antworten wurden bereits gegeben. Aber das wird mich nicht aufhalten.

// This will break when the arguments are additive inverses.
// It is "cleverness" like this that's behind all the most amazing program errors.
or(arg1, arg2)
    return arg1 + arg2
    // Or if you need explicit conversions:
    // return (bool)((short)arg1 + (short)arg2)

Alternative:

// Since `0 > -1`, negative numbers will cause weirdness.
or(arg1, arg2)
    return max(arg1, arg2)

Ich hoffe, niemand würde jemals solche Ansätze anwenden. Sie sind nur hier, um das Bewusstsein für Alternativen zu fördern.

Aktualisieren:

Da negative Zahlen beide oben genannten Ansätze unterbrechen können, ist hier ein weiterer schrecklicher Vorschlag:

or(arg1, arg2)
    return !(!arg1 * !arg2)

Dies nutzt einfach DeMorgans Gesetze und Missbrauch der Tatsache , dass *die ähnlich ist , &&wenn trueund falsewie behandelt werden 1und 0jeweils. (Warten Sie, Sie sagen, das ist kein Code Golf?)

Hier ist eine anständige Antwort:

or(arg1, arg2)
    return arg1 ? arg1 : arg2

Aber das ist im Wesentlichen identisch mit anderen bereits gegebenen Antworten.

Daran interessiert
quelle
3
Diese Ansätze sind grundsätzlich fehlerhaft. Betrachten Sie -1 + 1 für arg1+arg2, -1 und 0 für max(arg1,arg2)usw.
flauschige
@fluffy Bei diesem Ansatz werden boolesche Argumente vorausgesetzt, und dann funktioniert es bei den meisten Arten von Garbage-Eingaben nur ordnungsgemäß. Gut, dass Sie darauf hinweisen, dass es immer noch Müll gibt, der Probleme verursacht. Genau aus diesem Grund sollten wir uns bemühen, den tatsächlichen Problembereich so direkt wie möglich zu modellieren (und zu vermeiden, von unserer eigenen Klugheit mitgerissen zu werden).
Keen
Wenn Sie Boolesche Werte reine 1-Bit tun, dann zusätzlich immer noch nicht funktioniert, da 1 + 1 = 0. :)
flauschiger
@fluffy Hier kommen die expliziten Konvertierungen ins Spiel. Ob sie benötigt werden oder nicht, hängt von den Details der Implementierung ab (genau aus diesem Grund ist dies eine dumme Idee).
Keen
0

Eine Möglichkeit zum Definieren orbesteht in einer Nachschlagetabelle. Wir können dies explizit machen:

bool Or( bool a, bool b } {
  bool retval[] = {b,true}; // or {b,a};
  return retval[a];
}

Wir erstellen ein Array mit den Werten, die der Rückgabewert haben sollte, je nachdem, was aist. Dann machen wir eine Suche. Befördert in C ++ - ähnlichen Sprachen boolzu einem Wert, der als Array-Index mit trueSein 1und falseSein verwendet werden kann 0.

Wir können dies dann auf andere logische Operationen ausweiten:

bool And( bool a, bool b } {
  bool retval[] = {false,b}; // or {a,b};
  return retval[a];
}
bool Xor( bool a, bool b } {
  bool retval[] = {b,!b};
  return retval[a];
}

Nun ist ein Nachteil von all diesen, dass es Präfixnotation erfordert.

namespace operators {
  namespace details {
    template<class T> struct is_operator {};
    template<class Lhs, Op> struct half_expression { Lhs&& lhs; };
    template<class Lhs, class Op>
    half_expression< Lhs, Op > operator*( Lhs&&lhs, is_operator<Op> ) {
      return {std::forward<Lhs>(lhs)};
    }
    template<class Lhs, class Op, class Rhs>
    auto operator*( half_expression<Lhs, Op>&& lhs, Rhs&& rhs ) {
    return invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
    }
  }
  using details::is_operator;
}

struct or_tag {};
static const operators::is_operator<or_tag> OR;

bool invoke( bool a, or_tag, bool b ) {
  bool retval[] = {b,true};
  return retval[a];
}

und jetzt kannst du tippen true *OR* falseund es funktioniert.

Die obige Technik erfordert eine Sprache, die die argumentabhängige Suche und Vorlagen unterstützt. Sie könnten es wahrscheinlich in einer Sprache mit Generika und ADL tun.

Nebenbei können Sie das *OR*Obige erweitern, um mit Sets zu arbeiten. Erstellen Sie einfach eine freie Funktion invokeim gleichen Namespace wie or_tag:

template<class...Ts>
std::set<Ts...> invoke( std::set<Ts...> lhs, or_tag, std::set<Ts...> const& rhs ) {
  lhs.insert( rhs.begin(), rhs.end() );
  return lhs;
}

und set *OR* setkehrt nun die Vereinigung der beiden zurück.

Yakk
quelle
0

Dieser erinnert mich an die charakteristischen Funktionen:

or(a, b)
    return a + b - a*b

Dies gilt nur für Sprachen, die Boolesche Werte als (1, 0) behandeln können. Gilt nicht für Smalltalk oder Python, da Boolean eine Klasse ist. In Smalltalk gehen sie noch weiter (dies wird in Art eines Pseudocodes geschrieben):

False::or(a)
    return a

True::or(a)
    return self

Und die dualen Methoden existieren für und:

False::and(a)
    return self

True::and(a)
    return a

Die "Logik" ist also in der OP-Anweisung vollkommen gültig, obwohl sie ausführlich ist. Vorsicht, es ist nicht schlecht. Es ist perfekt, wenn Sie eine Funktion benötigen, die sich wie ein mathematischer Operator verhält, der beispielsweise auf einer Art Matrix basiert. Andere implementieren einen tatsächlichen Cube (wie eine Quine-McCluskey-Anweisung):

or = array[2][2] {
    {0, 1},
    {1, 1}
}

Und Sie werden bewerten oder [a] [b]

Also ja, jede Logik hier ist gültig (mit Ausnahme derjenigen, bei der der in der Sprache verwendete OR-Operator xDDDDDDD verwendet wird).

Aber mein Lieblingsgesetz ist das von DeMorgan: !(!a && !b)

Luis Masuelli
quelle
0

Schauen Sie sich die Swift-Standardbibliothek an und sehen Sie sich die Implementierung der Verknüpfungsoperationen OR und AND an, bei denen die zweiten Operanden nicht ausgewertet werden, wenn sie nicht benötigt / zugelassen werden.

gnasher729
quelle
-2

Die Logik ist vollkommen richtig, kann aber vereinfacht werden:

or(arg1, arg2)
  if arg1 = True
     return True
  else if arg2 = True
     return True
  else
     return False

Und vermutlich hat Ihre Sprache einen OR-Operator. Wenn dies nicht dem Sinn der Frage widerspricht, warum nicht?

or(arg1, arg2)
  if arg1 = True or arg2 = True
     return True
  else
     return False
Julia Hayward
quelle
if arg1 = True or arg2 = True { return true } else { return false }Besser noch return arg1 = True or arg2 = True. if condition then true else falseist überflüssig.
Doval
4
Der Fragesteller wies ausdrücklich darauf hin, dass ihre Anforderung "ohne Verwendung des Operators selbst" sei
gnat
2
Ähm, ich habe nichts dergleichen gesagt. Es war eine Art von dem, was ich meinte, aber die Frage sagte es nicht, bis sie bearbeitet wurde, und sie antwortete als solche, was meine Schuld daran war.
LogicNoob