逻辑测试4个中的3个为真

我想返回 True当且仅当4个布尔值中有3个为真。

最接近的是 (x ^ y) ^ (a ^ b):

我该怎么办?

13786 次浏览

冗长但非常简单的(析取)正常形式:

 (~a & b & c & d) | (a & ~b & c & d) | (a & b & ~c & d) | (a & b & c & ~d)

它可能被简化了,但是需要更多的思考

不知道是不是更简单,但也许吧。

((x xor y) and (a and b)) or ((x and y) and (a xor b))

# 1: 使用分支? : 3或4个操作

A ^ B ? C & D : ( C ^ D ) & A

2非分支机构,7项业务

(A ^ B ^ C ^ D) & ((A & B) | (C & D))

回到我使用剖析一切的时候,我发现 没有分支解决方案是相当快的操作对操作,因为 CPU 可以更好地预测代码路径,并执行更多的操作。不过,这里的分支语句的工作量减少了大约50% 。

这个答案取决于表示系统,但是如果0是唯一被解释为 false 的值,并且 not(false)总是返回相同的数值,那么 not(a) + not(b) + not(c) + not(d) = not(0)应该可以做到这一点。

如果你追求的是纸上(非编程)解决方案,那么 k-map 和 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个值为真,那么3出现在某个地方对我来说似乎很自然。

例如,在 C++中:

if ((int)a + (int)b + (int)c + (int)d == 3)
...

这在 C++中得到了很好的定义: standard (§4.7/4)表明将 bool转换为 int会得到预期的值0或1。

在 Java 和 C # 中,可以使用以下构造:

if ((a?1:0) + (b?1:0) + (c?1:0) + (d?1:0) == 3)
...

请记住,如果对于编程问题,而不仅仅是逻辑问题,答案显然取决于编程语言的选择。有些语言支持其他语言所不具备的特性。

例如,在 C + + 中,您可以使用以下方法测试您的条件:

(a + b + c + d) == 3

这应该是在支持从布尔类型到整数类型的自动(低级)转换的语言中执行检查的最快方法。但是,这个问题没有一般的答案。

要检查所有 Boolean中至少有 n为真,(n 必须小于或等于 Boolean的总数: p)

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) >= n) {
// do the rest
}

编辑 : 在@Cruncher 的评论之后

检查4个中的3个 boolean

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) == 3) {
// do the rest
}

还有一个:

((c & d) & (a ^ b)) | ((a & b) & (c ^ d)) (细节)

如果您想在编程语言中使用这种逻辑,我的建议是

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

如果这是 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:

所有这些都可以工作,因为布尔值是 Python 中整数的子类。

if len(filter(bool, [a, b, c, d])) == 3:

或者,受这个 这招不错的启发,

data = iter([a, b, c, d])
if not all(data) and all(data):
((a xor b) xor (c xor d)) and ((a or b) and (c or d))

第一个表达式搜索4个 true中的1个或3个。第二个排除了4个中的0或1(有时是2)个 true

(a && b && (c xor d)) || (c && d && (a xor b))

从纯逻辑的角度来看,这就是我想到的。

根据鸽子洞原理,如果3为真,那么 a 和 b 为真,或者 c 和 d 为真。接下来就是把这些案子和另外两个案子中的一个放在一起。

Wolfram 真相表

我想返回 true 当且仅当4个布尔值中有3个为 true。

给定4个布尔值 a,b,x,y,这个任务转换为以下 C 语句:

return (a+b+x+y) == 3;

如果你使用逻辑可视化工具,比如卡诺地图,你会发现这是一个问题,如果你想用 If (...)行写一个完整的逻辑术语,你就无法避免它。Lopina 已经展示过了,不可能再写得更简单了。您可以略微修改一下,但是对于您和机器来说,它仍然很难阅读。

计算解决方案并不坏,它们表明你真正想要的是什么。如何有效地进行计数取决于您的编程语言。使用 Python 或 LinQ 的数组解决方案看起来不错,但是要注意,这是缓慢的。Wolf 的(a + b + x + y) = = 3将很好很快地工作,但是只有在你的语言将“ true”等同于1的情况下。如果“ true”由 -1表示,则必须测试 -3:)

如果您的语言使用真布尔值,您可以尝试显式地对它进行编程(我使用! = 作为 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”!只有当 x,y 是布尔类型时,= y”才有效。如果它们是其他类型,其中0为 false,其他所有类型都为 true,则此操作可能失败。然后使用一个布尔异或,或((布尔) 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个月后你就不会理解它了:)

这里有一个用 LINQ 在 C # 中解决这个问题的方法:

bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;

与第一个答案类似,但是纯 Java:

int t(boolean b) {
return (b) ? 1 : 0;
}


if (t(x) + t(y) + t(a) + t(b) == 3) return true;
return false;

我更喜欢将它们计数为整数,因为这样可以使代码更具可读性。

这里有很多很好的答案,这里有一个其他人还没有发表的替代公式:

 a ? (b ? (c ^ d) : (c && d)) : (b && c && d)

Java8,过滤掉假值,并计算剩余的真值:

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

很容易推广到检查 m项的 n是否为真。

巨蟒中,要查看一个可迭代的元素中有多少是 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
((a^b)^(x^y))&((a|b)&(x|y))

就是你想要的。基本上,我把你的代码,并添加检查,如果实际上3是真的,而不是3是假的。

因为可读性是一个很大的问题,所以您可以使用描述性函数调用(包装所建议的任何实现)。如果需要在多个地方进行这种计算,那么函数调用是实现重用的最佳方式,它可以清楚地表明您正在做什么。

bool exactly_three_true_from(bool cond1, bool cond2, bool cond3, bool cond4)
{
//...
}

一个没有涉及递归的答案的编程问题

有足够多的“正好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(因为8个值中有5个为 true,正如预期的那样)。对“真”和“假”这两个词不太满意,但现在想不出更好的名字了... ..。注意,当找到的 true 或者值太多时,递归停止。

在 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";

这是对称的布尔函数。对称布尔函数是一种布尔函数,它只取决于输入集的数量,而不取决于它们是哪些输入。Knuth 在《计算机编程艺术》第四卷的7.1.2节中提到了这种类型的函数。

S₃(4)可通过以下7种操作计算:

(x && y && (a || b)) ^ ((x || y) && a && b)

Knuth 显示这是最佳的,这意味着您不能使用常规操作符 &&, || , ^, <,>在少于7个操作中完成此操作。

然而,如果你想在使用 1表示 true,使用 0表示 false 的语言中使用它,你也可以很容易地使用加法:

x + y + a + b == 3

这说明你的意图很明确。

(((a AND b) OR (x AND y)) AND ((a XOR b) OR (x XOR y)))

虽然我可以证明这是一个很好的解决方案,但 Sam Hocevar 的答案很容易写,也很容易理解。在我的书里,这样更好。

下面是我写的一些 c # 代码,因为你启发了我:

它需要任意数量的参数,并且会告诉你它们中的 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。