【问题标题】:&& operator behaves like || operator&& 运算符的行为类似于 ||操作员
【发布时间】:2015-12-06 14:13:40
【问题描述】:

我是一名初学者,我一直在尝试运行一个程序,该程序可以打印从 1 到 N(用户输入)的所有数字,但同时可被 3 和 7 整除的数字除外。然而,我的代码所做的是它打印从 1 到 N 的数字,除了那些可以被 3 或 7 整除的数字。我检查了一段时间,但我不知道为什么会这样。请向我解释我要去哪里错了。

static void Main(string[] args)
{
    int n = 0;
    int a = 0;
    n = Convert.ToInt32(Console.ReadLine());
    while (a <= n)
    {
        a++;
        if (a % 3 != 0 && a % 7 != 0)
        {
            Console.WriteLine(a);
        }
    }
    Console.ReadKey();
}

当我将 if 语句的符号反转为 == 时,&amp;&amp; 运算符可以正常工作,但如果符号是 !=,它就像 || 运算符一样,这​​让我更加困惑。问题很可能出在条件上,但我看不出它有什么问题。

【问题讨论】:

  • 附带说明,一个数字可以被 3 和 7 整除当且仅当它可以被 21 整除。
  • !(a%3==0 &amp;&amp; a%7==0)
  • @AndreyChernyakhovskiy:更好的概括是 - 一个数字可以被 ab 整除,如果它可以被 a 的 LCM 整除和 b.
  • @displayName: meta.stackexchange.com/a/19479/135695 另外,最好使用手绘维恩图:meta.stackexchange.com/a/19775/135695
  • x = a%3 == 0(可被 3 整除),y = a%7 == 0(可被 7 整除)。你想要!(x&amp;&amp;y) = !x || !y,而不是代码中的!x &amp;&amp; !y。你只需要学习一些数学逻辑。

标签: c# .net logic


【解决方案1】:

查看条件语句的真值表,您可以看到如果

 X(NOT multiple of 3) Y(NOT multiple of 7)   X && Y
      true                   true            'a' printed as it is not a multiple of either
      true                   false           'a' not printed, it is multiple of 7
      false                  true            'a' not printed, it is multiple of 3
      false                  false           'a' not printed, it is multiple of both 

这就是为什么没有打印出所有 3 或 7 或 21 的倍数。


你想要什么:数字,那是

  • 不是 (3 AND 7 的倍数)。那就是
  • !(a%3==0 && a%7==0) 甚至进一步简化为
  • !(a%21 == 0) 甚至
  • (a%21 != 0)

【讨论】:

  • 我认为 this 确实是该问题的主要答案。 &amp;&amp; 操作符完全按照它所说的去做;只需一步一步地按照表达式的评估。
【解决方案2】:

如果您不知道如何实现算法,请尝试将其分解为明显正确的函数,每个实现算法的部分。强>

您想要“打印从 1 到 N(用户输入)的所有数字,但同时可被 3 和 7 整除的数字除外。”老前辈可以使用逻辑运算符快速吐出正确且高效的实现。作为初学者,您可能会发现将其分解成碎片会有所帮助。

// write out the highest level problem to solve, using functions as
// placeholders for part of the algorithm you don't immediately know
// how to solve
for ($x = 1; $x <= $N; $x++) {
    if (is_not_divisible_by_3_and_7($x)) {
        print "$x\n";
    }
}

// then think about the function placeholders, writing them out using
// (again) function placeholders for things you don't immediately know
// how to do
function is_not_divisible_by_3_and_7($number) {
    if (is_divisible_by_3_and_7($number)) {
        return false;
    } else {
        return true;
    }
}

// keep repeating this...
function is_divisible_by_3_and_7($number) {
    if (is_divisible_by_3($number) && is_divisible_by_7($number)) {
        return true;
    } else {
        return false;
    }
}

// until you have the simplest possible functions
function is_divisible_by_3($number) {
    if ($number % 3 === 0) {
        return true;
    } else {
        return false;
    }
}

function is_divisible_by_7($number) {
    if ($number % 7 === 0) {
        return true;
    } else {
        return false;
    }
}

这更容易理解,因为每个函数都做一件事,而函数名准确地描述了那一件事。这也满足了编程的第一条规则:正确的代码在前

然后您可以开始考虑让代码变得更好,其中更好意味着:

  • 代码行数更少
  • 更少的计算
  • 更多cmets

在上面的代码中采用这种方法,一个明显的改进是将is_divisible_by_3is_divisible_by_7 替换为通用函数:

function is_divisible_by_n($number, $divisor) {
    if ($number % $divisor === 0) {
        return true;
    } else {
        return false;
    }
}

然后,您可以将所有大而笨重的 if x return true else return false 替换为三元运算符,这样您就可以:

function is_divisible_by_n($number, $divisor) {
    return ($number % $divisor === 0) ? true : false;
}

function is_divisible_by_3_and_7($number) {
    return (is_divisible_by_n($number, 3) && is_divisible_by_n($number, 7)) ? true : false;
}

function is_not_divisible_by_3_and_7($number) {
    return (is_divisible_by_3_and_7($number)) ? false : true;
}

现在,请注意 is_not_divisible_by_3_and_7 看起来与 is_divisible_by_3_and_7 完全一样,只是切换了返回值,因此您可以将它们合并为一个方法:

function is_not_divisible_by_3_and_7($number) {
    // look how it changed here ----------------------------------------------VVVVV - VVVV
    return (is_divisible_by_n($number, 3) && is_divisible_by_n($number, 7)) ? false : true;
}

现在,您可以利用比较本身返回值这一事实,而不是使用三元运算符:

function is_divisible_by_n($number, $divisor) {
    // this expression returns a "truthy" value: true or false
    //     vvvvvvvvvvvvvvvvvvvvvvvvvv
    return ($number % $divisor === 0);
}

function is_not_divisible_by_3_and_7($number) {
    // also returns a truthy value, but inverted because of the !
    //    vvv
    return ! (is_divisible_by_n($number, 3) && is_divisible_by_n($number, 7));
}

最后,您可以机械地将函数调用替换为等效的逻辑操作:

for ($x = 1; $x <= $N; $x++) {
    // all I did below was copy from the function, replace variable names
    //  v  vvvvvvvvvvvvvv    vvvvvvvvvvvvvv
    if (! (($x % 3 === 0) && ($x % 7 === 0))) {
        print "$x\n";
    }
}

作为奖励积分,您可以应用 DeMorgan 规则,通过表达式分配 not:

for ($x = 1; $x <= $N; $x++) {
    if ($x % 3 !== 0 || $x % 7 !== 0) {
        print "$x\n";
    }
}

此外,您可能会观察到两个互质数具有公因数当且仅当它们的公因数为 N 乘以 M,所以:

for ($x = 1; $x <= $N; $x++) {
    if ($x % (3*7) !== 0) {
        print "$x\n";
    }
}

您可以通过使用您的语言的功能来进一步压缩表达式:

array_walk(
    range(1, $N),
    function ($x) {
        if ($x % 21 !== 0) print "$x\n";
    }
);

等等。关键是你首先要让你的代码正确,然后再让它变得更好。有时,使代码正确意味着要长期努力地思考。有时它只是意味着用非常小的、非常明确的步骤写出来。

【讨论】:

    【解决方案3】:

    你说的:

       if not (divisible by 3 and divisible by 7) then print
    

    你写的:

       if not divisible by 3 and not divisible by 7 then print
    

    不是一回事。亚里士多德首先想到的是,奥古斯都德摩根在 158 年前写了定律,将非运算符应用于操作数并反转逻辑运算:

       if not divisible by 3 or not divisible by 7 then print
    

    产生:

       if (a % 3 != 0 || a % 7 != 0)
    

    或者就按照你说的那样写:

       if (!(a % 3 == 0 && a % 7 == 0))
    

    【讨论】:

    • 第一部分很有意义。在您提到逻辑 OR 运算符后,我就迷路了。 OR 运算符如何可能包含两个值需要同时回答一个条件的情况?我明白你说的是对的,但我不明白为什么。我知道德摩根定律对反转运算符有很多说明,但是满足同时条件的 OR 运算符对我来说听起来绝对令人困惑和不可能。如果您不介意,您能给我一个简单的解释吗?
    • 不确定我是否能理解你的挂断,我已经这样做太久了。我猜您对将 == 替换为 != 感到困惑。当您使用 bool 类型的变量来解决这个问题时,可能会更容易获得。像 bool divisiblyBy3 = a % 3 == 0;与 divisiblyBy7 相同,然后编写 if() 语句。除此之外,德摩根先生是您的朋友,请始终让他得心应手。
    • 其他一些答案设法填补了空白,我现在明白了。只是使用 OR 运算符使决定 a 是否可被 3 和 7 整除的方式与使用 AND 运算符时完全不同。另外,也许我应该多读几次任务本身,因为现在我已经成功地掌握了这个概念。无论哪种方式,您与其他 2 人的回答都设法帮助我理解了这个问题。非常感谢您的帮助和时间!
    【解决方案4】:

    显然 && 和 ||不一样。

    它指出: 如果(真 && 假)= 假 如果(真||假)=真

    【讨论】:

      【解决方案5】:

      应该是:

      if ( !(a % 3 == 0 && a % 7 == 0) )
      {
          Console.WriteLine(a);
      }
      

      确切的意思是:除了可以同时被3和7整除的数字之外的所有数字。

      你也可以改写成:

      if ( a % 3 != 0 || a % 7 != 0 )
      {
          Console.WriteLine(a);
      }
      

      【讨论】:

      • 谢谢,您的解决方案有效。第二段代码对我来说似乎有点奇怪,但它是有道理的。如果可能的话,您能否更详细地向我解释一下为什么您的第一个陈述有效而我的无效?
      • @Ornstein 像@MatthewWatson 那样使用单词,你的声明说if a is not divisible by 3 AND a is not divisible by 7,但@user2622016 的回答说if it's not true that a is divisible by BOTH 3 and 7。像 6 这样的数字不会通过您的检查,但会通过 @user2622016 的检查。如果您在@user2622016 的代码开头分发not,您将获得第二段代码。和你最初贴的代码几乎一模一样,但是在分发nots的时候,我们需要把&amp;&amp;改成||,把||改成&amp;&amp;
      【解决方案6】:

      你应该阅读De Morgan's laws

      "not (A and B)" 等同于"(not A) or (not B)"

      还有,

      "not (A or B)" 与 "(not A) and (not B)" 相同。

      a 不能被 3 (a % 3 != 0) 整除且不能被 7 (a % 7 != 0) 整除时,

      a % 3 != 0 &amp;&amp; a % 7 != 0 为真。所以所有可以被 37 (3,6,7,9,12,14,...) 整除的as 使整个表达式为假。你可以改写成!(a % 3 == 0 || a % 7 == 0)

      【讨论】:

      • 我想要的是当 a 不能被 3 和 7 整除时条件为真,但它仍然表现得好像它是 3 或 7。我用“if (!( a % 3 == 0 && a % 7 == 0))" 并且它起作用了,但我仍然不太确定为什么我的初始条件没有这样做。
      • @Ornstein 试着大声读出你的初始状态;你应该得到类似的结果:只要 a 不除以 3 并且 a 不除以 7,就打印 a。要打印 a 的两个部分都必须为真,所以不打印 a 的情况是至少其中一个部分是错误的情况。那是除数 3 或除数 7。这是德摩根定律告诉你的。
      • 有一个简单的解决方法可以避免这种尴尬的情况,使用比绝对必要的更多的括号。
      • @Dukeling ( (a % 3 != 0) &amp;&amp; (a % 7 != 0) )
      • 这应该是公认的答案 - 这实际上与操作员无关,而是 OP 没有得到的一般布尔逻辑的概念。
      【解决方案7】:

      “除了能同时被 3 和 7 整除的数”可以分解如下:

      "divisible by 3 and 7 at the same time"可以表示为:

      "(divisible by 3 and divisible by 7)"

      "Except"可以表示为"Not"

      所以你得到:

      Not (divisible by 3 and divisible by 7)

      “能被 3 整除”是(a % 3) == 0

      “能被 7 整除”是(a % 7) == 0

      给予:

      Not ( (a % 3) == 0 and (a % 7) == 0)

      在 C# 中,Not 变为 !and 变为 &amp;&amp;,因此您可以在 C# 中将整个内容编写为:

      if (!((a % 3) == 0 &amp;&amp; (a % 7) == 0))


      与你的错误比较:

      if (a % 3 != 0 &amp;&amp; a % 7 != 0)

      后者是不正确的,因为它意味着:

      if (the number is not divisible by 3) and (the number is not divisible by 7)。

      即表示"Print the number if it is neither divisible by 3 nor divisible by 7",表示"don't print the number if it's divisible by 3 or 7"

      要了解原因,首先考虑数字 6:

      6 is not divisible by 3? = false (because 6 *is* divisible by 3)
      6 is not divisible by 7? = true (because 6 is *not* divisible by 7)
      

      所以这会解析为if false and true,当然也就是false

      此结果也适用于任何其他可被 3 整除的数字,因此不会打印可被 3 整除的数字。

      现在考虑数字 14:

      14 is not divisible by 3? = true (because 14 is *not* divisible by 3)
      14 is not divisible by 7? = false (because 14 *is* divisible by 7)
      

      所以这会解析为if true and false,当然也就是false

      此结果也适用于任何其他可被 7 整除的数字,因此不会打印可被 7 整除的数字。

      希望你现在能明白为什么错了。如果不是,请考虑以下等效示例:


      假设我们有四个人,木匠汤姆、木匠迪克、屠夫哈利和屠夫汤姆。

      这个问题和你问的一样:

       Name every person who is (not called Tom and is not a Butcher)
      

      你应该可以看到这和问的一样:

      Name every person except (anyone called Tom or anyone who is a Butcher)
      

      在这两种情况下,答案都是木匠迪克。

      你应该问的问题是:

      Name every person except (anyone called Tom who is also a butcher)
      

      答案是木匠汤姆、木匠迪克和屠夫哈利。


      脚注De Morgan's laws

      第二定律规定:

      "not (A or B)" is the same as "(not A) and (not B)"
      

      这相当于我上面的例子:

      Name every person except (anyone called Tom or anyone who is a Butcher)
      

      相当于:

      Name every person who is (not called Tom and is not a Butcher)
      

      其中A是anyone called Tom,B是anyone who is a butchernot写成except

      【讨论】:

      • 一个很好的回应。但是,理论上,“ if (a % 3 != 0 && a % 7 != 0) ”不应该也是正确的吗?我的逻辑不是只有 2 个“!=”符号而不是一个“!”签名,所以我觉得这很令人困惑。
      • @Ornstein 我添加了更多信息来解释错误的原因。
      • 尽管对详尽的解释表示赞赏,但我相信答案将受益于用逻辑陈述(即德摩根定律)解释幕后发生的理论。
      • @Leon7C 我认为这样的解释超出了这里的答案范围。有人已经链接了关于德摩根定律的 Wiki 文章(尽管我担心这对于 OP 来说可能太复杂了,至少在现阶段如此)。我与 Tom、Dick 和 Harry 的示例旨在提供对 OP 特定问题的逻辑的基本介绍。不过,我会添加一个脚注。
      • 几乎以为您根本不会在这个冗长的答案中提及德摩根。 :)
      【解决方案8】:

      你真正需要的是:

      if ((a%21) != 0) Console.WriteLine(a);
      

      解释:能被ab整除的数本质上是能被a和LCM整除的数b. 由于 3 和 7 是质数,所以您基本上是在寻找不能被 3*7 整除的数字。

      【讨论】:

      • 花了一秒钟才意识到你的观点是别人没有提出的。
      • @kleineg 它是在评论中提出的。但是,是的,这是迄今为止解决此问题的最佳方法。所有这些帖子都清楚而广泛地解释了如何使设计糟糕的程序工作......悲伤。
      • @Yakk 我同意。人们从表面上回答这个问题是有道理的(尽管很多答案都是多余的),因为它促进了对德摩根定律的理解,这在否定条件陈述时会很有帮助。但在这种情况下确实存在一个......更优雅的解决方案。对此点赞并投票。
      • @Yakk:我在阅读评论之前发布了答案,然后我阅读了评论,然后也在那里发布了我的评论。对该问题的最高评价实际上具有误导性。它之所以有效,是因为 3 和 7 是素数。不适用于 4 和 6。对于非互质数,它不是乘法,而是,正如我所说,要使用的 LCM。
      • 4 * 6 是 24。但是被 24 过滤的第一个数字本身就是 24,而 12 是 4 和 6 的倍数,也应该被过滤。那是因为 4 和 6 不是互质数。
      【解决方案9】:

      a % b != 0 表示“a 不能被 b 整除”。

      如果某物不能被 3 整除,也不能被 7 整除,则它都不能被 7 整除。因此,如果它是 3 的倍数是 7 的倍数,您的陈述将是错误的。

      根据现实世界的事物来思考逻辑通常会有所帮助:
      (请记住true and false == falsetrue or false == true

      海洋是蓝色的(a 可以被 3 整除)。
      海洋不是黄色的(a 不能被 7 整除)。

      你有什么:
      海洋不是蓝色的,海洋也不是黄色的——这是错误的(你希望这是真的)。​​

      你想要什么:
      海洋不是(蓝色和黄色) - 这是真的(海洋只有蓝色,而不是蓝色和黄色)。
      海洋不是蓝色的或海洋不是黄色的——这是真的(海洋不是黄色的)。

      最后两条语句的等价物是:

      !(a % 3 == 0 && a % 7 == 0)
      (a % 3 != 0 || a % 7 != 0)
      

      您可以使用De Morgan's laws 将一个转换为另一个。

      【讨论】:

        【解决方案10】:

        && 的行为与 ||

        不同

        要了解差异,使用更简单的表达式进行一些测试可能会有所帮助:

        if (true && false)
        if (true || false)
        

        因此,您的问题在于理解代码中的其他运算符(!= 和 %)。

        通常有助于将条件拆分为更小的表达式,并附上解释:

        bool divisbleBy3 = (a % 3 == 0);
        bool divisbleBy7 = (a % 7 == 0);
        
        if (divisbleBy3 && divisibleBy7)
        {
            // do not print
        }
        else
        {
            // print
        }
        

        【讨论】:

        • 是的,结果不一样。这就是拥有两个不同运算符的全部意义所在,如果结果相同,那么其中一个运算符将是多余的。你的观点是什么?
        • 嗯,重点是回答这个问题。看标题... :-)
        • 你已经回答了标题,但没有回答问题
        • 其实这连标题都答不上来?!
        • @buffjape 我知道逻辑与和逻辑或之间的区别。问题是在我的程序中,逻辑 AND 的行为类似于逻辑 OR,至少就我的理解而言。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多