Как написать следующее логическое выражение?
-
11-09-2019 - |
Вопрос
У меня есть три логических значения A, B и C.Мне нужно написать оператор IF, который будет выполняться тогда и только тогда, когда не более одного из этих значений истинно.Другими словами, вот таблица истинности:
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
Как лучше всего это написать?Я знаю, что могу перечислить все возможности, но кажется...слишком многословно.:П
Добавлен: Была только одна идея:
!(A && B) && !(B && C) && !(A && C)
Это проверяет, что не установлены никакие два значения.Предложение о суммах тоже нормально.Возможно, даже читабельнее...
(A?1:0) + (B?1:0) + (C?1:0) <= 1
P.S.Это для производственного кода, поэтому я больше ориентируюсь на читаемость кода, чем на производительность.
Добавлено 2: Ответ уже принят, но для любопытных - это C#.:) Хотя вопрос в значительной степени не зависит от языка.
Решение
как насчет того, чтобы рассматривать их как целые числа 1 и 0 и проверять, равна ли их сумма 1?
РЕДАКТИРОВАТЬ:
теперь, когда мы знаем, что это C#.net, я думаю, что наиболее читаемое решение будет выглядеть примерно так:
public static class Extensions
{
public static int ToInt(this bool b)
{
return b ? 1 : 0;
}
}
приведенное выше спрятано в библиотеке классов (код приложения?), где нам не нужно его видеть, но мы можем легко получить к нему доступ (например, ctrl+click в r#), и тогда реализация будет просто:
public bool noMoreThanOne(params bool[] bools)
{
return bools.ToList().Sum(b => b.ToInt()) <= 1;
}
...
bool check = noMoreThanOne(true, true, false, any, amount, of, bools);
Другие советы
Вам следует ознакомиться с Карты Карно.Концепция чаще всего применяется к электронике, но и здесь она очень полезна.Это очень просто (хотя объяснение в Википедии выглядит длинным — оно подробное).
(A XOR B XOR C) ИЛИ НЕ (A OR B OR C)
Редактировать:Как отметил Вилкс, это неправильно.
Если A и B оба равны 1, а C равен 0, A XOR B будет равно 0, общий результат будет 0.
Как насчет:НЕ (А И Б) И НЕ (А И С) И НЕ (Б И С)
Если вы перевернете логику, вы захотите, чтобы условие было ложным, если у вас есть пара логических значений, которые оба являются истинными:
if (! ((a && b) || (a && c) || (b && c))) { ... }
Для чего-то совершенно другого вы можете поместить логические значения в массив и подсчитать, сколько там истинных значений:
if ((new bool[] { a, b, c }).Where(x => x).Count() <= 1) { ... }
Я бы выбрал максимальную ремонтопригодность и читабельность.
static bool ZeroOrOneAreTrue(params bool[] bools)
{
return NumThatAreTrue(bools) <= 1;
}
static int NumThatAreTrue(params bool[] bools)
{
return bools.Where(b => b).Count();
}
Здесь много ответов, но у меня есть еще один!
a ^ b ^ c ^ (a == b && b == c)
Общий способ найти минимальное логическое выражение для данной таблицы истинности — использовать карту Карно:
http://babbage.cs.qc.edu/courses/Minimize/
В сети есть несколько онлайн-минимайзеров.Тот, что здесь (ссылка на него из статьи, хотя он на немецком языке), находит следующее выражение:
(! A && ! Б) || (! A && ! С) || (! B && ! C)
Однако если вы стремитесь к читабельности кода, я бы, вероятно, выбрал идею «sum<=1».Обратите внимание, что не все языки гарантируют, что false==0 и true==1, но вы, вероятно, знаете об этом, поскольку позаботились об этом в своем собственном решении.
Старая добрая логика:
+ = 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))
Возьмите подсказку и упростите дальше, если хотите.
И да, познакомьтесь с Картами Карно.
Зависит от того, хотите ли вы чего-то, что легко понять, что вы пытаетесь сделать, или чего-то настолько логически простого, насколько это возможно.Другие люди публикуют логически простые ответы, поэтому здесь более понятно, что происходит (и каков будет результат для разных входных данных):
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"
Мне нравится решение сложения, но вот способ сделать это и с битовыми полями.
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 */ }
Демонстрация кода решения d:
int total=0;
if (A) total++;
if (B) total++;
if (C) total++;
if (total<=1) // iff no more than one is true.
{
// execute
}