测试 3 个(共 4 个)为真的逻辑

Logic to test that 3 of 4 are True

提问人:Simon Kuang 提问时间:3/7/2014 最后编辑:thefourtheyeSimon Kuang 更新时间:5/17/2014 访问量:14650

问:

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

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

我该怎么办?

布尔逻辑

评论

10赞 I am Cavic 3/7/2014
嗯,我能想到的没有数学公式的唯一方法是使用计数。问得好!:)
10赞 Ingo 3/7/2014
你的想法还不错,但你必须接受否定:当一个否定值为真时,它是真的。这意味着,从原始值来看,只有一个是错误的。not a ^ not b ^ not c ^ not d
23赞 Wolf 3/7/2014
你在这个细节背后的实际问题是什么?
5赞 NameSpace 3/7/2014
@Ingo 不是 a ^ 不是 b ^ 不是 c ^ 不是 d 返回 true,其中只有一个是假的,而 3 个是假的。
10赞 Jason C 3/10/2014
明显的非计数解决方案是 。(!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d)

答:

53赞 Gastón Bengolea 3/7/2014 #1

很长但非常简单,(析取)正态形式:

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

它可能会被简化,但这需要更多的思考:P

评论

2赞 Riking 3/7/2014
@Ben这只是给你各种正常形式,这已经在(DNF)中了。
8赞 user253751 3/8/2014
怎么样 ?(a & b & (c ^ d)) | ((a ^ b) & c & d)
2赞 Gastón Bengolea 3/8/2014
是的,@immibis,根据 Wolfram Alpha 的说法,它的 DNF 是我写的公式,所以它是相同的布尔函数。
2赞 Boluc Papuccuoglu 3/10/2014
+1,因为我认为阅读代码的人会比其他答案更快地理解正在尝试的内容。
12赞 Simon Kuang 3/7/2014 #2

我能做的最好的是 ((x ^ y) ^ (a ^ b)) && ((a || x) && (b || y))

评论

0赞 Wolf 3/7/2014
什么对你来说最好
0赞 Cruncher 3/7/2014
有趣。采取了手术的解决方案,只是剃掉了坏情况
34赞 Karl Kieninger 3/7/2014 #3

不确定它是否更简单,但也许。

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

评论

1赞 Durai Amuthan.H 3/21/2014
该死的!他们应该给选项多点投票一个答案!特别是使用 wolfram alpha 来证明你的答案是正确的,这是一件非常好的事情!
90赞 NameSpace 3/7/2014 #4

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

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

#2 非分支,7 个操作

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

当我过去分析所有内容时,我发现非分支解决方案的操作速度要快得多,因为 CPU 可以更好地预测代码路径,并同时执行更多操作。不过,这里的分支语句中的工作量减少了大约 50%。

评论

18赞 Brilliand 3/8/2014
+1 - 虽然其他答案更适合大多数编程语言,但您的 #2 是纯布尔逻辑中的最佳答案。
2赞 Sawny 3/9/2014
#2 的 Wolframalpha 真值表
20赞 MattClarke 3/7/2014 #5

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

5赞 ioreskovic 3/7/2014 #6

如果你追求的是纸上(非编程)解决方案,那么 K-maps 和 Quine-McCluskey 算法就是你所追求的,它们可以帮助你缩小布尔函数。

就您而言,结果是

y = (x̄3 ^ x2 ^ x1 ^ x0) ∨ (x3 ^ x̄2 ^ x1 ^ x0) ∨ (x3 ^ x2 ^ x̄1 ^ x0) ∨ (x3 ^ x2 ^ x1 ^ x̄0)

如果你想以编程方式做到这一点,非固定数量的变量和自定义的“阈值”,那么只需遍历布尔值列表并计算“true”的出现次数就非常简单明了。

评论

1赞 NameSpace 3/7/2014
bar overhead 是什么意思?我注意到它在列表中向下移动。
3赞 3/7/2014
@NameSpace 这是人们用来表达“不”的太多符号之一。
248赞 sam hocevar 3/7/2014 #7

我建议以一种表明你的意思的方式编写代码。如果您希望 3 个值为真,那么在我看来,值 3 出现在某个地方似乎很自然。

例如,在:C++

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

这在 : the 中得到了很好的定义,表示转换为会给出预期值 0 或 1。C++standard (§4.7/4)boolint

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

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

评论

23赞 NothingsImpossible 3/8/2014
这是一个很好的答案。这看起来像是那个 X/Y 事情的一个案例。“他想用Y做X,但不知道怎么做Y。他没有问X,而是问Y。除非他正在设计一个逻辑电路或类似的东西(然后他会在错误的地点),否则最好的方法是以一种可读的方式做到这一点。
2赞 Ярослав Рахматуллин 3/10/2014
@NothingsImpossible 这个问题没有什么XY的。这是一个关于解决编程中一个相当普遍的问题的清晰而直接的问题。Y 无关紧要。
0赞 Simon Kuang 3/10/2014
谢谢!这确实是我想要做的,但我的想法太笨拙了,以至于我使用了布尔逻辑。
3赞 phuclv 3/10/2014
if (!!a + !!b + !!c + !!d == 3)更容易写,虽然我不知道编译器是否优化了这一点
2赞 PlasmaHH 3/11/2014
请注意,在 c++ 中,不需要从 bool 转换为 int。
18赞 GOTO 0 3/7/2014 #8

请记住,对于编程问题,而不是仅仅是逻辑问题,答案显然取决于编程语言的选择。某些语言支持其他语言不常见的功能。

例如,在 C++ 中,您可以使用以下命令测试条件:

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

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

评论

2赞 Tom Collins 3/12/2014
这是我要发布的答案。不过要补充一点,根据所使用的编程语言,您想要的答案是 -3。在 VB 中,True = -1。
11赞 Not a bug 3/7/2014 #9

要检查至少全部为真,(n 必须小于或等于:p总数)nBooleanBoolean

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

编辑:在@Cruncher的评论之后

检查 3 分中的第 4 分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))详情)

评论

0赞 Cruncher 3/7/2014
OP 正好想要 n,至少不想要 n。但与此解决方案相比,这是一个简单的更改
2赞 Not a bug 3/10/2014
@Wolf这个问题属于 StackUnderflow.com :p
23赞 frogatto 3/7/2014 #10

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

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

评论

12赞 User1000547 3/7/2014
打败我。可读性胜过聪明,每一次都是如此。+1
69赞 thefourtheye 3/7/2014 #11

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

评论

17赞 Wolf 3/7/2014
+1 这通过正确地将其翻译成 Python 来解决问题。
0赞 Voo 3/8/2014
这有点危险,因为人们可能会在 python 的布尔上下文中返回任何非零整数。旧的 C 技巧在 python 中也有效:.没有真正的布尔类型的缺点。a=5;not not a == 1
0赞 thefourtheye 3/8/2014
@Voo 我们也有布尔:)
0赞 Voo 3/8/2014
@thefourtheye啊,是的,真的,比双重否定技巧/黑客要好得多。
1赞 rz. 3/13/2014
或。。。或。。。。或。。。。应该有一种——最好只有一种——显而易见的方法来做到这一点。:-/ :-)
11赞 durum 3/7/2014 #12
((a xor b) xor (c xor d)) and ((a or b) and (c or d))

拳头表达式在 4 个中搜索 1 或 3 个。第二个消除 0 或 1(有时是 2)中的 4。truetrue

9赞 Cruncher 3/7/2014 #13
(a && b && (c xor d)) || (c && d && (a xor b))

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

根据鸽子洞原理,如果正好 3 为真,则 a 和 b 为真,或者 c 和 d 为真。然后,只需将这些案例中的每一个与另外 2 个案例中的一个进行处理即可。

Wolfram 真值表

评论

0赞 Brilliand 3/8/2014
这相当于 NameSpace 的第二个解决方案。
0赞 Cruncher 3/8/2014
@Brilliand 对我来说似乎不同。他的 xor 一起得到所有 3 或 1,然后通过要求 2 个不同组中的至少一个来排除具有 1 的那些。(总结为 1 或 3 和至少 2)。我的需要来自其中一个不同组,然后恰好来自另一个组。
0赞 Cruncher 3/8/2014
如果你的意思在某种意义上是等价的,那么我不知道该说什么,因为这是意料之中的。mine <=> his
0赞 Brilliand 3/8/2014
我想我的意思是这个答案很好,就像 NameSpace 的第二个解决方案一样好,没有添加任何 NameSpace(早期)答案没有涵盖的新内容。好吧,无论如何我都会投赞成票。
5赞 Wolf 3/7/2014 #14

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

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

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

评论

1赞 JensG 3/8/2014
不错的陷阱。这假设等于 1。并非所有语言/案例都是如此(没有双关语)。blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspxtrue
0赞 Wolf 3/8/2014
@JensG 你是对的:我把这个假设说得很明确。谢谢:)
8赞 Rolf 3/7/2014 #15

如果你使用像 Karnaugh Maps 这样的逻辑可视化工具,你会看到这是一个问题,如果你想用一行 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 != y”仅在 x,y 为布尔类型时才有效。如果它们是 0 为 false 而其他所有内容为 true 的其他类型的类型,则可能会失败。然后使用布尔异或,或 ( (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个月后你不会理解它:)

10赞 Tim S. 3/7/2014 #16

下面是使用 LINQ 在 C# 中解决该问题的方法:

bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;
7赞 La-comadreja 3/8/2014 #17

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

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

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

我更喜欢将它们算作整数,因为它使代码更具可读性。

8赞 Alex D 3/8/2014 #18

这里有很多好的答案;这是其他人尚未发布的替代公式:

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

评论

0赞 Deanna 3/14/2014
感谢您的回答,但您能否添加一些关于其工作原理的评论?谢谢。
0赞 Deanna 3/14/2014
(很抱歉挑剔你,我把它作为审查审计。至少我通过了......:))
11赞 David Conrad 3/8/2014 #19

Java 8,过滤掉 false 值,并计算剩余的 true 值:

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

轻松推广到检查项目是否为真。nm

7赞 Russia Must Remove Putin 3/8/2014 #20

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
4赞 Shujal 3/9/2014 #21
((a^b)^(x^y))&((a|b)&(x|y))

是你想要的。基本上,我拿走了你的代码并添加了检查是否真的 3 是真的而不是 3 是假的。

3赞 Graham Griffiths 3/11/2014 #22

由于可读性是一个大问题,因此您可以使用描述性函数调用(包装任何建议的实现)。如果需要在多个地方进行此计算,则函数调用是实现重用的最佳方式,并明确说明您正在做什么。

bool exactly_three_true_from(bool cond1, bool cond2, bool cond3, bool cond4)
{
    //...
}
4赞 Amos M. Carpenter 3/11/2014 #23

一个没有涉及递归的答案的编程问题?不可思议!

有足够多的“正好 3 个 4 个真”的答案,但这里有一个通用的 (Java) 版本,用于“正好 m 个真”(否则递归真的不值得),因为你可以:

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

它应该返回(因为 8 个值中有 5 个是真的,正如预期的那样)。对“真”和“假”这两个词不太满意,但现在想不出更好的名字......请注意,当找到太多太多的值时,递归将停止。truetruefalse

评论

0赞 Amos M. Carpenter 3/13/2014
@FélixSaparelli:不确定“真相”在这里是否适用......听起来你对一个感到满意。也许是这样的.顺便说一句:不过,Smalltalk的命名更适合于此:.对于某些 Java 开发人员的口味来说可能太长了,但 Smalltalkers 从不害怕正确的命名 ;-)truecontainsNumberOfTrueValues()doesArray: someBooleans startingAt: anIndex containNumberOfTrueValues: anExpectedNumber foundSofar: aNumberFoundSoFar
0赞 Félix Saparelli 3/16/2014
这主要是幽默的。从字面上看,意思是“包含一些未公开的真相”,所以我相信这是可以的。containsTruth
3赞 Bill Ortell 3/11/2014 #24

在 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";
10赞 Paul 3/11/2014 #25

这就是对称布尔函数。对称布尔函数是一个布尔函数,它仅取决于设置的输入数量,但不依赖于它们是哪些输入。Knuth 在《计算机编程的艺术》第 4 卷的第 7.1.2 节中提到了这种类型的函数。S₃(4)

S₃(4)可以用 7 个操作计算,如下所示:

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

Knuth 表明这是最优的,这意味着您不能使用普通运算符在少于 7 次操作中执行此操作: 和 。&&, || , ^, <,>

但是,如果您想在用于 true 和 false 的语言中使用它,您也可以轻松地使用加法:10

x + y + a + b == 3

这使您的意图非常明确。

2赞 user521945 3/12/2014 #26
(((a AND b) OR (x AND y)) AND ((a XOR b) OR (x XOR y)))

虽然我可以证明这是一个很好的解决方案,但 Sam Hocevar 的答案很容易写出来,以后也很容易理解。在我的书中,这让它变得更好。

1赞 JPK 3/14/2014 #27

这是我刚刚写的一些 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。