Как написать следующее логическое выражение?

StackOverflow https://stackoverflow.com/questions/1097487

  •  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

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top