Я хочу вернуть True
тогда и только тогда, когда истинно 3 из 4 логических значений.
Ближайший я получил (x ^ y) ^ (a ^ b)
:
Что мне делать?
Я хочу вернуть True
тогда и только тогда, когда истинно 3 из 4 логических значений.
Ближайший я получил (x ^ y) ^ (a ^ b)
:
Что мне делать?
Я предлагаю написать код таким образом, чтобы это означало. Если вы хотите, чтобы 3 значения были истинными, мне кажется естественным, что значение 3 появляется где-то.
Например, в C++
:
if ((int)a + (int)b + (int)c + (int)d == 3)
...
Это хорошо определено в C++
: standard (§4.7/4)
указывает, что преобразование bool
в int
дает ожидаемые значения 0 или 1.
В Java и С# вы можете использовать следующую конструкцию:
if ((a?1:0) + (b?1:0) + (c?1:0) + (d?1:0) == 3)
...
# 1: Использование ветвления?: 3 или 4 операции
A ^ B ? C & D : ( C ^ D ) & A
# 2 Неразветвление, 7 операций
(A ^ B ^ C ^ D) & ((A & B) | (C & D))
Назад, когда я использую для профилирования все, я обнаружил, что не ветвящиеся решения были довольно быстрой операцией для работы, поскольку ЦП мог предсказать путь кода лучше, и выполнять больше операций в тандеме. Однако здесь в инструкции ветвления примерно на 50% меньше.
Если бы это был Python, я бы написал
if [a, b, c, d].count(True) == 3:
или
if [a, b, c, d].count(False) == 1:
или
if [a, b, c, d].count(False) == True:
# In Python True == 1 and False == 0
или
print [a, b, c, d].count(0) == 1
или
print [a, b, c, d].count(1) == 3
или
if a + b + c + d == 3:
или
if sum([a, b, c, d]) == 3:
Все эти работы, поскольку Booleans являются подклассами целых чисел в Python.
if len(filter(bool, [a, b, c, d])) == 3:
Или, вдохновленный этим опрятным трюком,
data = iter([a, b, c, d])
if not all(data) and all(data):
Длинная, но очень простая, (disjuntive) нормальная форма:
(~a & b & c & d) | (a & ~b & c & d) | (a & b & ~c & d) | (a & b & c & ~d)
Это может быть упрощено, но это требует большего мышления: P
Не уверен, что это проще, но, может быть.
Если вы хотите использовать эту логику на языке программирования, мое предложение
bool test(bool a, bool b, bool c, bool d){
int n1 = a ? 1 : 0;
int n2 = b ? 1 : 0;
int n3 = c ? 1 : 0;
int n4 = d ? 1 : 0;
return n1 + n2 + n3 + n4 == 3;
}
Или, если хотите, вы можете поместить все это в одну строку:
return (a ? 1 : 0) + (b ? 1 : 0) + (C ? 1 : 0) + (d ? 1 : 0) == 3;
Также вы можете обобщить эту проблему на n of m
:
bool test(bool *values, int n, int m){
int sum = 0;
for(int i = 0; i < m; i += 1){
sum += values[i] ? 1 : 0;
}
return sum == n;
}
Этот ответ зависит от системы представления, но если 0 - единственное значение, которое интерпретируется как false, а not(false)
всегда возвращает одно и то же числовое значение, тогда not(a) + not(b) + not(c) + not(d) = not(0)
должен делать трюк.
Имея в виду, что SO, если для вопросов программирования, а не просто логических проблем, ответ, очевидно, зависит от выбора языка программирования. Некоторые языки поддерживают функции, которые необычны для других.
Например, на С++ вы можете проверить свои условия с помощью:
(a + b + c + d) == 3
Это должен быть самый быстрый способ выполнить проверку на языках, поддерживающих автоматическое (низкоуровневое) преобразование с булевых на целые типы. Но опять же, нет общего ответа на эту проблему.
Лучшее, что я могу сделать, это ((x ^ y) ^ (a ^ b)) && ((a || x) && (b || y))
Чтобы проверить как минимум n
из всех Boolean
, истинны, (n должно быть меньше или равно общему числу Boolean
: p)
if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) >= n) {
// do the rest
}
Изменить: после комментария @Cruncher
Чтобы проверить 3 Boolean
из 4
if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) == 3) {
// do the rest
}
Другой:
((a xor b) xor (c xor d)) and ((a or b) and (c or d))
Первое выражение ищет 1 или 3 true
из 4. Второй исключает 0 или 1 (а иногда и 2) true
из 4.
Java 8, отфильтруйте ложные значения и подсчитайте оставшиеся истинные значения:
public static long count(Boolean... values) {
return Arrays.stream(values).filter(t -> t).count();
}
Затем вы можете использовать его следующим образом:
if (3 == count(a, b, c, d)) {
System.out.println("There... are... THREE... lights!");
}
Легко обобщается на проверку для n
элементов m
, являющихся истинными.
Здесь вы можете решить его в С# с помощью LINQ:
bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;
Это симметричная булева функция S₃(4)
. Симметричная булева функция - это булева функция, которая зависит только от количества входов, но не зависит от того, какие входные данные они есть. Кнут упоминает функции этого типа в разделе 7.1.2 в томе 4 "Искусство программирования".
S₃(4)
можно вычислить с помощью 7 операций следующим образом:
(x && y && (a || b)) ^ ((x || y) && a && b)
Кнут показывает, что это оптимально, а это означает, что вы не можете сделать это менее чем за 7 операций с помощью обычных операторов: &&, || , ^, <,
и >
.
Однако, если вы хотите использовать это на языке, который использует 1
для true и 0
для false, вы также можете легко скомпилировать добавление:
x + y + a + b == 3
что делает ваше намерение совершенно ясным.
(a && b && (c xor d)) || (c && d && (a xor b))
С чистой логической точки зрения это то, что я придумал.
По принципу голубины, если ровно 3 истинны, то либо a, либо b истинны, либо c и d истинны. Тогда это просто вопрос каждого из этих случаев с одним из двух других.
Если вы используете инструмент логической визуализации, такой как Karnaugh Maps, вы видите, что это проблема, когда вы не можете избежать полномасштабного логического термина, если хотите записать его в одну строку if (...). Лопина показала это уже, это невозможно сделать проще. Вы можете немного отмерить, но он будет трудно читать для вас И для машины.
Подсчет решений не плох, и они показывают, что вы на самом деле после. Эффективность подсчета зависит от вашего языка программирования. Решения массива с Python или LinQ приятно смотреть, но будьте осторожны, это SLOW. Wolf (a + b + x + y) == 3 будет работать красиво и быстро, но только если ваш язык равен "true" с 1. Если "true" представлен -1, вам нужно будет проверить на -3: )
Если ваш язык использует true booleans, вы можете попытаться его явно запрограммировать (я использую!= как тест XOR):
if (a)
{
if (b)
return (x != y); // a,b=true, so either x or y must be true
else
return (x && y); // a=true, b=false, so x AND y must be true
}
else
{
if (b)
return (x && y); // a=false, b=true, so x and y must be true
else
return false; // a,b false, can't get 3 of 4
}
"x!= y" работает только в том случае, если x, y имеют булевский тип. Если это какой-то другой тип, где 0 - false, а все остальное - true, это может завершиться неудачно. Затем используйте boolean XOR или ((bool) x!= (Bool) y) или напишите "if (x) return (y == false) else return (y == true)", что немного больше работайте на компьютере.
Если ваш язык программирования предоставляет трехмерный оператор: вы можете сократить его до
if (a)
return b ? (x != y) : (x && y);
else
return b ? (x && y) : false;
который сохраняет некоторую удобочитаемость или агрессивно разрезает его на
return a ? (b ? (x != y) : (x && y)) : (b ? (x && y) : false);
Этот код выполняет ровно три логических теста (состояние a, состояние b, сравнение x и y) и должно быть быстрее большинства других ответов здесь. Но вам нужно прокомментировать это, или вы не поймете его через 3 месяца:)
Здесь есть много хороших ответов; вот альтернативная формулировка, которую никто еще не опубликовал:
a ? (b ? (c ^ d) : (c && d)) : (b && c && d)
Как и в первом ответе, но чистая Java:
int t(boolean b) {
return (b) ? 1 : 0;
}
if (t(x) + t(y) + t(a) + t(b) == 3) return true;
return false;
Я предпочитаю считать их целыми, потому что он делает более читаемый код.
В Python, чтобы увидеть, сколько из итерируемых элементов True, используйте sum
(это довольно просто):
Настройка
import itertools
arrays = list(itertools.product(*[[True, False]]*4))
Фактический тест
for array in arrays:
print(array, sum(array)==3)
Выход
(True, True, True, True) False
(True, True, True, False) True
(True, True, False, True) True
(True, True, False, False) False
(True, False, True, True) True
(True, False, True, False) False
(True, False, False, True) False
(True, False, False, False) False
(False, True, True, True) True
(False, True, True, False) False
(False, True, False, True) False
(False, True, False, False) False
(False, False, True, True) False
(False, False, True, False) False
(False, False, False, True) False
(False, False, False, False) False
Если вы после решения на бумаге (без программирования), то K-карты и алгоритмы Quine-McCluskey - это то, что вам нужно, они помогают вам минимизировать вашу логическую функцию.
В вашем случае результат
y = (x̄3 ^ x2 ^ x1 ^ x0) ∨ (x3 ^ x̄2 ^ x1 ^ x0) ∨ (x3 ^ x2 ^ x̄1 ^ x0) ∨ (x3 ^ x2 ^ x1 ^ x̄0)
Если вы хотите сделать это программно, нефиксированное количество переменных и пользовательский "порог", а затем просто перебирать список логических значений и подсчитывать вхождения "истина", это довольно просто и просто.
Я хочу вернуть true тогда и только тогда, когда 3 из 4 булевых значений истинны.
Учитывая 4 булевых значения, a, b, x, y, эта задача переводится в следующий оператор C:
return (a+b+x+y) == 3;
((a^b)^(x^y))&((a|b)&(x|y))
- это то, что вы хотите. В основном я взял ваш код и добавил проверку, если на самом деле 3 являются истинными, а не 3 являются ложными.
Вопрос программирования без ответа с рекурсией? Непостижимо!
Есть достаточно "точно 3 из 4 прав", но здесь обобщенная (Java) версия для "точно m из n истин" (иначе рекурсия на самом деле не стоит того), потому что вы можете:
public static boolean containsTrues(boolean[] someBooleans,
int anIndex, int truesExpected, int truesFoundSoFar) {
if (anIndex >= someBooleans.length) {
return truesExpected == truesFoundSoFar; // reached end
}
int falsesExpected = someBooleans.length - truesExpected;
boolean currentBoolean = someBooleans[anIndex];
int truesFound = truesFoundSoFar + (currentBoolean ? 1 : 0);
if (truesFound > truesExpected) {
return false;
}
if (anIndex - truesFound > falsesExpected) {
return false; // too many falses
}
return containsTrues(someBooleans, anIndex + 1, truesExpected,
truesFound);
}
Это можно было бы вызвать с помощью:
boolean[] booleans = { true, false, true, true, false, true, true, false };
containsTrues(booleans, 0, 5, 0);
который должен возвращать true
(потому что 5 из 8 значений были истинными, как и ожидалось). Не совсем доволен словами "истины" и "фальши", но теперь не могу думать о лучшем имени... Обратите внимание, что рекурсия прекращается, когда слишком много значений true
или слишком много false
.
Поскольку читаемость является большой проблемой, вы можете использовать вызов описательной функции (обертывание любой из предложенных реализаций). Если этот расчет необходимо выполнить в нескольких местах, вызов функции является наилучшим способом для повторного использования и дает четкое представление о том, что вы делаете.
bool exactly_three_true_from(bool cond1, bool cond2, bool cond3, bool cond4)
{
//...
}
В PHP, делая его более динамичным (на всякий случай, если вы измените количество условий и т.д.):
$min = 6;
$total = 10;
// create our boolean array values
$arr = array_map(function($a){return mt_rand(0,1)>0;},range(1,$total));
// the 'check'
$arrbools = array_map(function($a){return (int)$a;},$arr);
$conditionMet = array_sum($arrbools)>=$min;
echo $conditionMet ? "Passed" : "Failed";
(((a AND b) OR (x AND y)) AND ((a XOR b) OR (x XOR y)))
Пока я мог показать, что это хорошее решение, ответ Сэма Хосевара легко написать и понять позже. В моей книге это делает лучше.
Вот код С#, который я только что написал, потому что вы вдохновили меня:
Требуется любое количество аргументов и скажет вам, если n из них истинно.
static bool boolTester(int n, params bool[] values)
{
int sum = 0;
for (int i = 0; i < values.Length; i++)
{
if (values[i] == true)
{
sum += 1;
}
}
if( sum == n)
{
return true;
}
return false;
}
и вы вызываете его так:
bool a = true;
bool b = true;
bool c = true;
bool d = false;
bool test = false;
test = boolTester(3, a, b, c, d);
Итак, теперь вы можете протестировать 7/9 или 15/100, как вы.