闰年布尔逻辑:包含括号?

时间:2016-08-15 18:07:37

标签: python boolean-logic parentheses leap-year

哪个是#34;更正确(逻辑上)"? 特定于闰年,而不是一般

  1. 使用括号

    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
    
  2. 没有

    return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
    
  3. 其他信息

    圆括号改变了评估布尔值的顺序(andor括号之前“。

    鉴于此问题中所有较大的数字都可以被较小的数字整除,它会以任何方式返回正确的结果,但我仍然很好奇。

    观察括号的影响:

    1. False and True or True
      #True
      
      False and (True or True)
      #False
      
    2. False and False or True
      #True
      
      False and (False or True)
      #False
      
    3. 如果没有括号,有些情况下即使年不能被4整除(第一个bool),它仍然会返回True (我知道在这个问题上不可能)! 不能被4整除,因此包括括号更正确吗?我还应该注意什么?有人可以解释不包括括号的理论逻辑吗?

4 个答案:

答案 0 :(得分:5)

parens影响你的布尔人采取的顺序。在and之前,or被组合在一起并得到解决,因此:

a and b or c

变为:

(a and b) or c

如果ab两者都是真实的,或者c是真的,我们会True

用括号得到:

a and (b or c)

现在,如果True两者都是真实的,ab是真的,那么你会得到c

就“正确性”而言,只要您的代码得出正确的结果,那么“更正确”只是意见问题。我会在你认为结果更清晰的地方加入parens。例如:

if (a and b) or c:

更清晰
if a and b or c:

然而,(在我看来)并不比以下更清楚:

if some_long_identifier and some_other_long_identifier or \
   some_third_long_identifier_on_another_line:

编写Python代码时,您的指南应为PEP8。当你应该包括风格括号时,PEP8很安静(阅读:遵循自然操作顺序的parens),所以请用你最好的判断。

具体来说,闰年的逻辑是:

  1. 如果年份可被4整除,请转到步骤2. ...
  2. 如果年份可以被100整除,请转到第3步。
  3. 如果年份可以被400整除,请转到步骤4. ...
  4. 这一年是闰年(它有366天)。
  5. 这一年不是闰年(它有365天)。
  6. 换句话说:所有可被4整除的年份都是闰年,除非它们可被100整除且不能被400整除,这意味着:

    return y % 4 == 0 and not (y % 100 == 0 and y % 400 != 0)
    

答案 1 :(得分:3)

包括括号。在英语中,规则是:

  1. 年份必须可被4整除。
  2. 年份不得在100年之前显示,除非它可以被400整除。
  3. 带括号的版本最符合这个双管齐下的规则。

    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
           ^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                (1)                          (2)
    

    实际上,删除括号不会破坏代码,但会导致规则的不自然版本:

    1. 年份必须可被4整除,但不能被100整除;或
    2. 年份必须可被400整除。
    3. 这不是我对闰年规则的看法。

答案 2 :(得分:1)

答案:包含括号

John Kugelman解释了为什么它们是2个单独的逻辑测试而不是3个, - >最后2个应该组合在一起:

  1. 年份必须可被4整除。
  2. (2)年份不得在100,(3)之前显示,除非它可以被400整除。
  3. 带括号的版本最符合这个双管齐下的规则。

    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
           ^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                (1)                          (2)
    

    实际上,删除括号不会破坏代码,但会导致规则的不自然版本:

    1. 年份必须可被4整除,但不能被100整除;或
    2. 年份必须可被400整除。
    3. 这不是我对闰年规则的看法。

      mrdomoboto的启发,100/400是例外!:

      年份必须可以被4 整除,100是例外,400是例外,但它们仍然是一个例外(见上文)。这意味着如果年份不能被4整除,则整个事物必须为假。确保这一点的唯一方法是将异常放在异常周围,因为False and bool将始终返回False。

      请参阅以下JBallin

      的示例
      1. False and True or True
        #True
        
        False and (True or True)
        #False
        
      2. False and False or True
        #True
        
        False and (False or True)
        #False
        
      3. Adam Smith将英语翻译成代码:

        所有可被4整除的年份都是闰年,除非它们可以被100整除而不能被400整除,这意味着:

        return y % 4 == 0 and not (y % 100 == 0 and y % 400 != 0)
        

        JBallin引用De Morgan's Laws

        not(a and b) = (not a or not b)
        

        要将上述内容转换为所需的答案:

        #convert using "DML"
        return y % 4 == 0 and (not y % 100 == 0 or not y % 400 != 0)
        #remove "not"s by switching "==" and "!="
        return y % 4 == 0 and (y % 100 != 0 or y % 400 == 0)
        

答案 3 :(得分:1)

这是另一个区别:速度和效率。

除了评估顺序(已在其他答案中提及)...

让我们简化原始表达 year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

A and (B or C)

如果A为假,则没有理由测试BC,因为and要求两面都为true

短路电路操作员

逻辑运算符andor在包括Python在内的许多语言中都具有“短路”效应,其中仅对左侧求值(请参见https://docs.python.org/2/library/stdtypes.html#boolean-operations-and-or-not):

  • and在左侧为false时发生短路(因为右侧不能使结果为true
  • or在左侧为true时发生短路(因为右侧不能使结果为false

具有监护功能:

A and (B or C)

  • Afalse时,右侧(B or C)不会得到评估,从而节省了CPU资源。
  • Atrue时,B得到评估,但是C仅在B为假时才得到评估。

完全没有心态:

A and B or C

  • Afalse时,B不会得到评估,但是C得到(不必要)会得到评估。
  • Atrue时,B得到评估。如果Bfalse,则C也将得到评估。

结论: 如果没有括号,则C为假(year % 400测试)时,Ayear % 4测试)将得到不必要的评估。这是CPU可以在A处停止的时间的75%,但继续执行不必要的数学运算。

最有效的表达方式

改为使用此: ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0))

在两种情况下,该表达式用按位与(快速!)替换模(慢除)。

更多详细信息,请访问:https://stackoverflow.com/a/11595914/733805