Como escrever a seguinte expressão booleana?
-
11-09-2019 - |
Pergunta
Eu tenho três valores booleanos A, B e C. Eu preciso escrever uma instrução IF que irá executar se e somente se não mais do que um desses valores é True. Em outras palavras, aqui está a tabela verdade:
A | B | C | Result
---+---+---+--------
0 | 0 | 0 | 1
0 | 0 | 1 | 1
0 | 1 | 0 | 1
0 | 1 | 1 | 0
1 | 0 | 0 | 1
1 | 0 | 1 | 0
1 | 1 | 0 | 0
1 | 1 | 1 | 0
Qual é a melhor maneira de escrever isso? Eu sei que posso enumerar todas as possibilidades, mas que parece ... muito detalhado. : P
Adicionado: Apenas teve uma idéia:
! (A && B) &&! (B && C) &&! (A && C)
Isto verifica que não há dois valores são definidos. A sugestão sobre somas é OK também. Ainda mais legível talvez ...
(a 1:? 0) + (B 1:? 0) + (C 1?: 0) <= 1
P.S. Isto é para o código de produção, então eu vou mais para facilitar a leitura de código de desempenho.
Adicionado 2: resposta já aceito, mas para os curiosos - é C #. :) A questão é muito bonito embora a linguagem-agnóstico.
Solução
Como cerca de tratá-los como número inteiro 1 e 0, e verificando que a sua soma é igual a 1?
Editar :
Agora que sabemos que é c # .net, eu acho que a solução mais legível ficaria um pouco como
public static class Extensions
{
public static int ToInt(this bool b)
{
return b ? 1 : 0;
}
}
acima escondido em uma biblioteca de classe (? Appcode), onde não temos para vê-lo, mas facilmente pode acessá-lo (ctrl + clique no r #, por exemplo) e, em seguida, a implementação será simplesmente:
public bool noMoreThanOne(params bool[] bools)
{
return bools.ToList().Sum(b => b.ToInt()) <= 1;
}
...
bool check = noMoreThanOne(true, true, false, any, amount, of, bools);
Outras dicas
Você shold familiarizar com Karnaugh mapeia . Concept é mais frequentemente aplicada a eletrônica, mas é muito útil aqui também. É muito fácil (pensou Wikipedia explicação faz olhar longo - é completa).
(A XOR B XOR C) ou não (A ou B ou C)
Edit:. Como apontado por Vilx, isso não está certo
Se A e B são ambos 1, e C é 0, A XOR B será de 0, o resultado global será 0.
Como sobre: NÃO (A e B) e NOT (A e C) e NOT (B e C)
Se você virar a lógica ao redor, você quer a condição de ser falso, se você tem qualquer par de booleans que são ambos true:
if (! ((a && b) || (a && c) || (b && c))) { ... }
Para algo completamente diferente, você pode colocar os booleans em uma matriz e contar quantos valores verdade que são:
if ((new bool[] { a, b, c }).Where(x => x).Count() <= 1) { ... }
Eu iria para manutenção máxima e legibilidade.
static bool ZeroOrOneAreTrue(params bool[] bools)
{
return NumThatAreTrue(bools) <= 1;
}
static int NumThatAreTrue(params bool[] bools)
{
return bools.Where(b => b).Count();
}
Existem muitas respostas aqui, mas eu tenho uma outra!
a ^ b ^ c ^ (a == b && b == c)
Uma forma geral de encontrar uma expressão booleana mínimo para uma determinada tabela verdade é usar um mapa de Karnaugh:
http://babbage.cs.qc.edu/courses/Minimize/
Existem várias minimizadores online na web. A um aqui (ligada à do artigo, é em alemão, embora) encontra a seguinte expressão:
(! A &&! B) || (! A &&! C) || (! B &&! C)
Se você estiver indo para a legibilidade do código, porém, eu provavelmente ir com a ideia de "sum <= 1". Tome cuidado para que nem todos os idiomas garante que falsa == 0 e verdadeiro == 1 - mas provavelmente você está ciente disso, uma vez que você tenha tomado o cuidado de que em sua própria solução.
Boa ol' lógica:
+ = OR
. = AND
R = Abar.Bbar.Cbar + Abar.Bbar.C + Abar.B.Cbar + A.Bbar.Cbar
= Abar.Bbar.(Cbar + C) + Abar.B.Cbar + A.Bbar.Cbar
= Abar.Bbar + Abar.B.Cbar + A.Bbar.Cbar
= Abar.Bbar + CBar(A XOR B)
= NOT(A OR B) OR (NOT C AND (A XOR B))
Tome a dica e simplificar ainda mais se quiser.
E sim, obter a sua auto familiarizar com Karnaugh mapas
Depende se você quer algo que é fácil de entender o que você está tentando fazer, ou algo que é tão logicamente simples quanto pode ser. Outras pessoas estão postando respostas logicamente simples, então aqui está uma em que é mais claro o que está acontecendo (e que o resultado será para diferentes inputs):
def only1st(a, b, c):
return a and not b and not c
if only1st(a, b, c) or only1st(b, a, c) or only1st(c, a, b):
print "Yes"
else:
print "No"
Eu gosto da solução disso, mas aqui é um hack para fazer isso com campos de bits também.
inline bool OnlyOneBitSet(int x)
{
// removes the leftmost bit, if zero, there was only one set.
return x & (x-1) == 0;
}
// macro for int conversion
#define BOOLASINT(x) ((x)?1:0)
// turn bools a, b, c into the bit field cba
int i = (BOOLASINT(a) << 0) | BOOLASINT(b) << 1 | BOOLASINT(c) << 2;
if (OnlyOneBitSet(i)) { /* tada */ }
Código demonstração da solução d's:
int total=0;
if (A) total++;
if (B) total++;
if (C) total++;
if (total<=1) // iff no more than one is true.
{
// execute
}