Comment définir logiquement "ou"

36

Récemment, j'ai rencontré un problème qui m'a obligé à définir l'opérateur logique "OU" par programme, mais sans utiliser l'opérateur lui-même.

Voici ce que j'ai trouvé:

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

Cette logique est-elle correcte ou ai-je oublié quelque chose?

logicNoob
la source
10
@gnat: Pour être juste, une table de vérité répertorie les sorties pour chaque combinaison d'entrées et l'article Wikipedia donne une description de la fonction. Je pense que ce que le PO demande vraiment, c'est comment définir un OU logique par programme sans utiliser l'opérateur lui-même.
Blrfl
6
@ user3687688 Pouvez-vous clarifier les primitives que nous sommes autorisés à utiliser?
fredoverflow
4
cette question a déclenché un spasme collectif de micro-optimisation;)
Rob
8
Vous pouvez utiliser l'opérateur ternairereturn arg1 ? arg1 : arg2;
Matthew
4
Je dois savoir pourquoi vous avez besoin de redéfinir l' oropérateur.
Kyle Strand

Réponses:

102

Je dirais que c'est correct, mais ne pourriez-vous pas le condenser en quelque chose de ce genre?

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

    return false

Puisque vous faites une comparaison ou une comparaison, je ne pense pas que vous ayez vraiment besoin de vérifier la combinaison. Il importe simplement que l’un d’eux soit vrai pour revenir vrai. Sinon, nous voulons retourner false.

Si vous recherchez une version plus courte et moins détaillée, cela fonctionnera également:

or(arg1, arg2)
    if arg1
        return arg1
    return arg2
Elliot Blackburn
la source
6
Vous pouvez également supprimer le "else" de la ligne 4 (en laissant simplement if arg2 == true).
Dawson Toth
1
@ DawsonToth Il y a beaucoup de façons de faire tourner les choses, cela dépend si vous voulez être vraiment bavard ou condensé. Je serais heureux avec le reste si, mais cela ressemble à une question de pseudo-code, je le laisserais probablement ainsi pour plus de clarté. Très vrai cependant!
Elliot Blackburn
@BlueHat Il semble légèrement incohérent d'utiliser un autre si, mais pas un autre à la fin.
SBoss
1
@Mehrdad Merci! J'ai repris l'ancienne réponse parce que j'estime qu'elle est un peu plus détaillée et que la solution est un peu plus claire. Mais votre solution est beaucoup plus petite et fait le même travail.
Elliot Blackburn
1
encore mieux (pire):or(a, b): a ? a : b
Sara
149

Voici une solution sans ou, et non, comparaisons et littéraux booléens:

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

Ça ne devient probablement pas plus fondamental que ça;)

fredoverflow
la source
32
+1 pour une réponse légèrement plus courte que la mienne. Cependant, je serais tenté de laisser tomber le "else" pour des raisons d'élégance.
Elliot Blackburn
10
@BlueHat Mais alors les deux retours seraient mis en retrait différemment;)
fredoverflow
5
Je voudrais obtenir un euro chaque fois que quelqu'un compare quelque chose contre trueou false.
JensG
1
@JensG Eh bien, selon vous, d'où provient le revenu de Bill Gates?
Kroltan
1
||Opérateur JavaScript en un mot (lorsqu'il est implémenté dans un langage typé dynamiquement).
rhino
108

Une ligne de code:

return not (not arg1 and not arg2)

Pas de branchement, pas de OU.

Dans un langage basé sur C, ce serait:

return !(!arg1 && !arg2);

Ceci est simplement une application des lois de De Morgan :(A || B) == !(!A && !B)


la source
6
Je pense que cette approche est la meilleure solution car (à mon avis) une if/elseconstruction est la même chose que d’utiliser OR, juste avec un nom différent.
Nick
2
Utiliser @Nick iféquivaut à l'égalité. Normalement, dans le code machine, an ifest implémenté sous forme arithmétique suivie d'une comparaison à zéro avec un saut.
6
Pour référence: en.wikipedia.org/wiki/De_Morgan%27s_laws
Mephy
1
J'aime cette approche car elle court-circuite les courts-circuits IFF and, assurant ainsi la cohérence entre les opérateurs.
Kyle Strand
1
@Snowman C'est vrai. Je voulais dire que cela if (a) return true; else if (b) return true;semble plus ou moins moralement équivalent if (a OR b) return true;, mais ce point de vue peut être sujet à controverse.
Nick
13

Si vous avez seulement andet not, vous pouvez utiliser la loi de DeMorgan pour retourner and:

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

... ou (encore plus simplement)

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

...

Et comme nous avons tous apparemment tendance à vouloir optimiser quelque chose qui est presque toujours disponible en tant qu'instruction machine, cela revient à:

return not(not arg1 and not arg2)

return arg1 ? true : arg2

etc. etc. etc. etc.

Étant donné que la plupart des langues fournissent un conditionnel et, les chances sont que l'opérateur "et" implique de toute façon une branche.

...

Si tout ce que vous avez est nand(voir wikipedia ):

renvoyer nand (nand (arg1, arg1), nand (arg2, arg2))

Rob
la source
7
Simplifiez:return not (not arg1 and not arg2)
@ Snowman, vous devriez vraiment en faire une réponse pour que je puisse la revigorer. Vous êtes (actuellement) le seul ici à ne pas utiliser de branche.
Lawtonfogle
4
J'allais ajouter la solution NAND, mais vous m'avez battu. Tout devrait être mis en œuvre en termes de NAND.
Andy
2
@Andy: En fait, tout devrait être défini en termes de NOR. ;-)
Pieter Geerkens
1
Bon travail avec la nandsolution pure .
AAT
13

Fonctions (ECMAScript)

Vous n'avez besoin que de définitions de fonctions et d'appels de fonctions. Vous n'avez pas besoin de branches, de conditions, d'opérateurs ou de fonctions intégrées. Je vais démontrer une implémentation en utilisant ECMAScript.

Premièrement, définissons deux fonctions appelées trueet false. Nous pouvons les définir comme bon nous semble, ils sont complètement arbitraires, mais nous les définirons de manière très spéciale, ce qui présente certains avantages, comme nous le verrons plus tard:

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

truest une fonction à deux paramètres qui ignore simplement son deuxième argument et renvoie le premier. flsest également une fonction à deux paramètres qui ignore simplement son premier argument et renvoie le second.

Pourquoi avons-nous encodé truet de flscette façon? Eh bien, de cette façon, les deux fonctions ne représentent pas seulement les deux concepts de trueet false, en même temps, elles représentent également le concept de "choix", en d’autres termes, elles sont aussi une expression if/ then/ else! Nous évaluons la ifcondition et lui passons le thenbloc et le elsebloc comme arguments. Si la condition est évaluée à tru, elle retournera le thenbloc. Si elle évaluera à fls, elle retournera le elsebloc. Voici un exemple:

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

Ceci retourne 23et ceci:

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

retourne 42, comme on peut s'y attendre.

Il y a une ride, cependant:

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

Cela imprime à la fois then branch et else branch! Pourquoi?

Eh bien, il renvoie la valeur de retour du premier argument, mais il évalue les deux arguments, car ECMAScript est strict et évalue toujours tous les arguments d'une fonction avant d'appeler la fonction. IOW: il évalue le premier argument qui est console.log("then branch"), qui retourne simplement undefinedet a l’effet secondaire d’imprimer then branchsur la console, et le deuxième argument, qui retourne également undefinedet est imprimé sur la console en tant qu’effet secondaire. Ensuite, il retourne le premier undefined.

Dans le λ-calcul, où ce codage a été inventé, ce n'est pas un problème: le λ-calcul est pur , ce qui signifie qu'il n'a pas d'effets secondaires; par conséquent, vous ne remarquerez jamais que le deuxième argument est également évalué. De plus, le λ-calcul est paresseux (ou du moins, il est souvent évalué dans un ordre normal), ce qui signifie qu'il n'évalue pas les arguments inutiles. Donc, IOW: dans le λ-calcul, le deuxième argument ne serait jamais évalué, et si c'était le cas, nous ne le remarquerions pas.

ECMAScript, cependant, est strict , c’est-à-dire qu’il évalue toujours tous les arguments. En fait, pas toujours: le if/ then/ else, par exemple, n’évalue la thenbranche que si la condition est trueet n’évalue que la elsebranche si la condition est false. Et nous voulons reproduire ce comportement avec notre iff. Heureusement, même si ECMAScript n’est pas paresseux, il a le moyen de retarder l’évaluation d’un morceau de code, comme presque toutes les autres langues: encapsulez-le dans une fonction et si vous n’appelez jamais cette fonction, le code ne jamais être exécuté.

Donc, nous encapsulons les deux blocs dans une fonction et, à la fin, appelons la fonction renvoyée:

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

estampes then branchet

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

impressions else branch.

Nous pourrions mettre en œuvre le traditionnel if/ then/ de elsecette façon:

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

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

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

Encore une fois, nous avons besoin de fonctions supplémentaires lors de l'appel de la ifffonction et de l'appel de fonction supplémentaire entre parenthèses dans la définition de iff, pour la même raison que ci-dessus:

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

Maintenant que nous avons ces deux définitions, nous pouvons les appliquer or. Premièrement, nous examinons la table de vérité pour or: si le premier opérande est la vérité, le résultat de l'expression est identique à celui du premier opérande. Sinon, le résultat de l'expression est le résultat du deuxième opérande. En bref: si le premier opérande est true, nous retournons le premier opérande, sinon nous retournons le deuxième opérande:

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

Voyons si cela fonctionne:

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

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

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

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

Génial! Cependant, cette définition est un peu moche. Rappelez-vous, truet flsagissez déjà comme un conditionnel tout seul, donc il n'y a vraiment pas besoin de iff, et donc de toute cette fonction encapsulant du tout:

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

Voilà ce que vous avez: or(plus d’autres opérateurs booléens) défini avec seulement des définitions de fonctions et des appels de fonctions en seulement quelques lignes:

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)();

Malheureusement, cette implémentation est plutôt inutile: il n'y a pas de fonctions ou d'opérateurs dans ECMAScript qui retournent truou qui reviennent flstous trueou false, nous ne pouvons donc pas les utiliser avec nos fonctions. Mais il y a encore beaucoup à faire. Par exemple, il s’agit d’une implémentation d’une liste à lien unique:

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

Objets (Scala)

Vous avez peut-être remarqué quelque chose de particulier: truet flsjouant un double rôle, ils agissent à la fois comme valeurs de données trueet false, mais en même temps, ils agissent également comme une expression conditionnelle. Ce sont des données et des comportements , regroupés dans un… euh… «chose»… ou (oserais-je dire) objet !

En effet, truet flssont des objets. Et si vous avez déjà utilisé Smalltalk, Self, Newspeak ou d’autres langages orientés objet, vous aurez remarqué qu’ils implémentent les booléens exactement de la même manière. Je démontrerai une telle implémentation ici à Scala:

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

C’est la raison pour laquelle le refactoring Remplacer conditionnel par polymorphisme fonctionne toujours: vous pouvez toujours remplacer n’importe quelle condition de votre programme par une distribution de messages polymorphes, car, comme nous venons de le montrer, la distribution de messages polymorphes peut remplacer des conditions en les implémentant simplement. Des langages comme Smalltalk, Self et Newspeak en sont la preuve, car ils n’ont même pas de condition. (Ils ne sont pas aussi des boucles, BTW, ou vraiment une sorte de structures de contrôle intégré langue sauf pour l' expédition des messages polymorphes appels de méthode alias virtuels.)


Correspondance de modèle (Haskell)

Vous pouvez également définir en orutilisant un filtrage par motif, ou quelque chose comme les définitions de fonctions partielles de Haskell:

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

Bien entendu, la mise en correspondance de modèles est une forme d'exécution conditionnelle, mais il en va de même pour l'envoi de messages orientés objet.

Jörg W Mittag
la source
2
Que diriez-vous False ||| False = Falseet à la _ ||| _ = Trueplace? :)
fredoverflow
3
@FredOverflow: Cela nécessiterait de toujours évaluer le bon opérande. Habituellement, les opérateurs booléens sont censés être non-stricts dans leur argument correct, également appelé "court-circuit".
Jörg W Mittag
Ah bien sur. Je savais qu'il devait y avoir une raison plus profonde :)
fredoverflow
La première partie m'a rappelé immédiatement la grande série d'Eric Lippert sur le style de passage continu . Une pure coïncidence mais toujours amusant :)
Voo
1
@ JörgWMittag La définition de FredOverflow est un court-circuit approprié. Essayez- True ||| undefinedvous dans ghci pour voir!
Daniel Wagner
3

Voici une autre façon de définir OR, ou même n'importe quel opérateur logique, en utilisant la méthode la plus traditionnelle: définissez une table de vérité.

Ceci est bien sûr assez simple à faire dans les langages de niveau supérieur tels que Javascript ou Perl, mais j'écris cet exemple en C pour montrer que la technique ne dépend pas des fonctionnalités de langage de haut niveau:

#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");
    }
}

Vous pouvez faire la même chose avec AND, NOR, NAND, NOT et XOR. Le code est suffisamment propre pour ressembler à la syntaxe, ce qui vous permet de faire des choses comme ceci:

if (OR[ a ][ AND[ b ][ c ] ]) { /* ... */ }
bûcheron
la source
Je pense que c'est l'approche la plus «pure» dans un certain sens mathématique. L'opérateur OR est une fonction après tout, et la table de vérité est vraiment l'essence de cette fonction en tant que relation et ensemble. Bien sûr, cela pourrait être écrit d'une manière amusante OO aussi:BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
VENEZ DU
3

Une autre façon d'exprimer les opérateurs logiques sous forme d'expressions arithmétiques entières (lorsque cela est possible). De cette façon, vous évitez beaucoup de ramifications pour une expression plus large de nombreux prédicats.

Let True soit 1 Let False est 0

si la somme des deux est supérieure à 1, il est alors vrai ou faux d'être renvoyé.

boolean isOR(boolean arg1, boolean arg2){

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

   return (L+R) > 0;

}
Senthu Sivasambu
la source
6
booleanExpression ? true : falseest trivialement égal à booleanExpression.
Keen
J'aime votre méthodologie, mais une erreur simple est que la somme des deux arguments doit être supérieure à ZERO pour être vraie, pas supérieure à ONE.
Grantly
1
return (arga+argb)>0
Grantly
1
Je ne faisais que corriger votre texte. Votre code est parfait, mais pourrait être en une ligne: return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0); :)
Grantly
1
@ SenthuSivasambu Je n'ai aucune objection à votre utilisation de arg1 ? 1 : 0;. Ce sont des expressions fiables pour transformer un booléen en nombre. C'est seulement la déclaration de retour qui peut être trivialement refactorisée.
Keen
1

Les deux formes:

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

OU

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

Avoir l’avantage, au même titre que le code golf, d’être un peu plus petit que les autres suggestions faites jusqu’à présent, une branche de moins. Ce n’est même pas aussi ridicule que le micro-choix de réduire le nombre de branches si nous envisageons la création d’un primitif qui serait donc très utilisé.

La définition de Javascript ||s'apparente à celle-ci, ce qui, combiné à sa frappe lâche, signifie que l'expression false || "abc"a la valeur "abc"et 42 || "abc"a la valeur 42.

Cependant, si vous avez déjà d'autres opérateurs logiques, ceux-ci nand(not(arg1), not(arg2))pourraient ne pas avoir de branche du tout.

Jon Hanna
la source
à quoi sert de répéter la réponse précédente ( comme vous l'avez admis )?
Gnat
@gnat, c'est assez proche pour que je ne l'aurais pas dérangé si j'avais vu cette réponse, mais il y a toujours quelque chose qui ne se trouve dans aucune d'entre elles, alors je la laisse.
Jon Hanna
@gnat, considérant en fait "Nous recherchons des réponses longues qui fournissent des explications et un contexte." Je suis plus heureux avec cette réponse maintenant.
Jon Hanna
1

En plus de toutes les solutions programmées utilisant la construction if, il est possible de construire une porte OU en combinant trois portes NAND. Si vous voulez voir comment cela fonctionne dans wikipedia, cliquez ici .

A partir de là, l'expression,

PAS [PAS (A ET A) ET PAS (B ET B)]

qui utilise NOT et AND donne la même réponse que OR. Notez que l’utilisation de NOT et AND n’est qu’une manière obscure d’exprimer NAND.

Walter Mitty
la source
PAS (A ET A) == PAS (A)?
Charlie
Oui, exactement. Dans le même article de Wikipédia, vous pouvez voir comment ils réduisent une porte NOT à une porte NAND. Même chose pour une porte AND. J'ai choisi de ne pas modifier la formule présentée pour la porte OU.
Walter Mitty
1

Toutes les bonnes réponses ont déjà été données. Mais je ne laisserai pas cela m'arrêter.

// 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)

Alternativement:

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

J'espère que personne n'utilisera jamais de telles approches. Ils ne sont là que pour promouvoir la connaissance des alternatives.

Mise à jour:

Puisque les nombres négatifs peuvent casser les deux approches ci-dessus, voici une autre suggestion affreuse:

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

Cela utilise simplement les lois de DeMorgan et abuse du fait que *c'est semblable à &&quand trueet falsesont traités comme 1et 0respectivement. (Attendez, vous dites que ce n'est pas du code golf?)

Voici une réponse décente:

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

Mais c'est essentiellement identique aux autres réponses déjà données.

Enthousiaste
la source
3
Ces approches sont fondamentalement imparfaites. Considérez -1 + 1 pour arg1+arg2, -1 et 0 pour max(arg1,arg2), etc.
moelleux
@fluffy Cette approche suppose des arguments booléens, puis elle fonctionne correctement avec la plupart des types d'entrées parasites. Merci à vous de signaler qu'il reste encore des déchets qui génèrent des problèmes. C’est précisément pour cette raison que nous devrions chercher à modéliser le plus concrètement possible le problème réel (et à éviter de nous laisser entraîner par notre propre intelligence) dans la pratique.
Keen
Si vous faites des valeurs booléennes 1 bit pures, alors l'addition ne fonctionne toujours pas, puisque 1 + 1 = 0. :)
duveteux
@fluffy C'est là que les conversions explicites entrent en jeu. Leur besoin ou non dépend des détails de la mise en œuvre (c'est précisément pourquoi il s'agit d'une idée idiote).
Keen
0

Une façon de définir orconsiste à utiliser une table de correspondance. Nous pouvons rendre ceci explicite:

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

nous créons un tableau avec les valeurs que la valeur de retour doit avoir en fonction de ce qui aest. Ensuite, nous faisons une recherche. En C ++, comme les langages, boolpromeut une valeur utilisable comme index de tableau, avec trueêtre 1et falseêtre 0.

Nous pouvons ensuite l'étendre à d'autres opérations logiques:

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];
}

Maintenant, l’un des inconvénients de tout cela est qu’il nécessite une notation par préfixe.

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];
}

et maintenant vous pouvez taper true *OR* falseet ça marche.

La technique ci-dessus nécessite un langage prenant en charge la recherche dépendante d'arguments et les modèles. Vous pourriez probablement le faire dans un langage avec des génériques et ADL.

En passant, vous pouvez étendre ce qui *OR*précède pour travailler avec des ensembles. Créez simplement une fonction libre invokedans le même espace de noms que 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;
}

et set *OR* setretourne maintenant l'union des deux.

Yakk
la source
0

Celui-ci me rappelle les fonctions charasteristiques:

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

Ceci ne s'applique qu'aux langues pouvant traiter les booléens comme (1, 0). Ne s'applique pas à Smalltalk ou à Python car boolean est une classe. En smalltalk, ils vont encore plus loin (cela sera écrit dans une sorte de pseudocode):

False::or(a)
    return a

True::or(a)
    return self

Et les doubles méthodes existent pour et:

False::and(a)
    return self

True::and(a)
    return a

La "logique" est donc parfaitement valable dans la déclaration OP, même si elle est verbeuse. Attention, c'est pas mal. C'est parfait si vous avez besoin d'une fonction qui agit comme un opérateur mathématique basé sur, par exemple, une sorte de matrice. D'autres implémenteraient un cube réel (comme une instruction Quine-McCluskey):

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

Et vous évaluerez ou [a] [b]

Donc, oui, chaque logique ici est valide (sauf celle qui est publiée comme utilisant l'opérateur xDDDDDDDD en langage OU).

Mais mon préféré est la loi de DeMorgan: !(!a && !b)

Luis Masuelli
la source
0

Examinez la bibliothèque standard Swift et vérifiez son implémentation des opérations de raccourci OU et de raccourci AND, qui n'évaluent pas les seconds opérandes si elles ne sont pas nécessaires / autorisées.

gnasher729
la source
-2

La logique est parfaitement correcte, mais peut être simplifiée:

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

Et vraisemblablement, votre langue a un opérateur OU alors - à moins que cela ne soit contraire à l'esprit de la question - pourquoi pas

or(arg1, arg2)
  if arg1 = True or arg2 = True
     return True
  else
     return False
Julia Hayward
la source
if arg1 = True or arg2 = True { return true } else { return false }Mieux encore return arg1 = True or arg2 = True. if condition then true else falseest redondant.
Doval
4
a expressément que asker leur exigence était « sans utiliser l'opérateur lui - même »
moucheron
2
Euh, je n'ai rien dit de la sorte. C’était un peu ce que je voulais dire, mais la question ne l’a pas dit jusqu’à ce qu’elle soit modifiée, et elle y a répondu comme telle, avec la gentillesse de ma faute.
logicNoob