闰年布尔逻辑:包括括号?
Leap Year Boolean Logic: Include Parentheses?
哪个是"more correct (logically)"? 闰年特有,不泛泛.
带括号
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
没有
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
附加信息
括号更改布尔值的计算顺序(and
在 or
w/o 括号之前)。
鉴于此问题中所有较大的数字都可以被较小的数字整除,因此 returns 无论哪种方式都是正确的结果,但我仍然很好奇。
观察括号的效果:
False and True or True
#True
False and (True or True)
#False
False and False or True
#True
False and (False or True)
#False
没有括号,有些情况下即使 year 不能被 4 整除(第一个布尔值)它仍然 returns True (我知道在这个问题中这是不可能的)! 被 4 整除不是必须的,因此包含括号更正确吗? 这里还有什么我应该注意的吗?有人可以解释一下 not/including 括号的理论逻辑吗?
括号会影响布尔值的顺序。 and
组合在一起并在 or
之前解析,因此:
a and b or c
变为:
(a and b) or c
如果 a
和 b
都为真,或者如果 c
为真,我们得到 True
.
加上括号你得到:
a and (b or c)
现在如果 a
为真且 b
或 c
为真,则得到 True
。
就"correctness,"而言,只要您的代码得出正确的结果,那么"more correct"只是一个见仁见智的问题。我会在您认为可以使结果更清晰的地方包括括号。例如:
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 对何时应该包含文体括号(阅读:遵循自然操作顺序的括号)保持沉默,因此请使用您的最佳判断。
特别是对于闰年,逻辑是:
- 如果年份可以被 4 整除,则转到步骤 2。...
- 如果年份可以被 100 整除,则转到步骤 3。...
- 如果年份可以被 400 整除,则转到步骤 4。...
- 该年为闰年(有366天)。
- 该年不是闰年(它有 365 天)。
换句话说:所有能被 4 整除的年份都是闰年,除非它们能被 100 整除且不能被 400 整除,即:
return y % 4 == 0 and not (y % 100 == 0 and y % 400 != 0)
Which answer is "more correct" and why?
这不是什么'更正确'的问题,而是;你想实现什么逻辑? boolean 表达式中括号'改变order of operations。这允许您在执行时强制执行优先级。
>>> (True or True) and False # or expression evaluates first.
False
>>> True or True and False # and evaluates first.
True
闰年公式中的逻辑rules如下:
闰年是任何可以被4整除的年份(如2012、2016等)
除非能被100整除,否则不能整除(如2100、2200等)
除非能被400整除则为(如2000、2400)
因此例外规则必须优先,这就是 or
周围的括号对于遵守公式规则是必要的。否则 and
的两个参数将首先被评估。
包括括号。在英语中,规则是:
- 年份必须能被 4 整除。
- 年份不能被 100 整除,除非它可以被 400 整除。
带括号的版本最符合这条双管齐下的规则。
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(1) (2)
碰巧,删除括号不会破坏代码,但会导致规则版本不自然:
- 年份必须能被 4 整除,但不能被 100 整除;或
- 年份必须能被 400 整除。
这不是我对闰年规则的看法。
Which answer is "more correct" and why? (Specific to Leap Year Logic, not in general)
With Parentheses
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
Without
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
取决于你对“更正确”的定义。如您所知,两者 return 都是正确的。
现在推测“更正确”- 如果您指的是性能优势,考虑到当前的智能编译器,我想不出任何。
如果你是在讨论人类可读性的观点,我会同意,
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
它自然会缩小范围,这与您的其他选择相反,后者似乎在视觉上包含两个不相交的元素。
我建议,包括括号,但如下所示:
return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
正如你所指出的,在操作上,没有区别,因为数字被400整除意味着它也可以被100整除,这意味着它也可以被4整除。操作上,括号是否有任何效果取决于语言的词汇顺序(求值顺序)。今天的大多数语言都遵循 c 的约定,这意味着运算符的指定优先级,否则是从左到右。如有疑问,我总是会加上括号以提高可读性。
从文体上来说,这种东西放在这么长的表达式中很难读懂。如果它必须是一个表达式,我宁愿使用逻辑 "sum of products" 而不是 "product of sums" 所以我会去
return (year%400 == 0) or (year%100 != 0 and year%4 == 0)
甚至
bool IsLeap = false;
if (year%4 == 0) IsLeap = true;
if (year%100 == 0) IsLeap = false;
if (year%400 == 0) IsLeap = true;
return IsLeap;
无论如何,优化的编译器会产生高效的代码,这种东西确实有助于像我这样的穷人阅读它。
答案:包括括号
John Kugelman 解释了为什么它们是 2 个独立的逻辑测试而不是 3 个,-> 最后 2 个应该组合在一起:
- 年份必须能被 4 整除。
- (2) 年份不能被 100 可见,(3) 除非它能被 400 整除。
带括号的版本最符合这条双管齐下的规则。
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(1) (2)
碰巧,删除括号不会破坏代码,但会导致规则版本不自然:
- 年份必须能被 4 整除,但不能被 100 整除;或
- 年份必须能被 400 整除。
这不是我对闰年规则的看法。
受mrdomoboto启发,100/400是例外!:
年份必须能被4整除,100是个例外,400是例外中的例外,但他们加起来还是一个例外(见上文)。这意味着如果年份不能被 4 整除,那么整个事情一定是假的。确保这一点的唯一方法是将异常放在括号中,因为 False and bool
将始终 return False.
请参阅以下来自 JBallin
的示例
False and True or True
#True
False and (True or True)
#False
False and False or True
#True
False and (False or True)
#False
Adam Smith 将英文翻译成代码:
所有能被 4 整除的年份都是闰年,除非它们能被 100 整除且不能被 400 整除,即:
return y % 4 == 0 and not (y % 100 == 0 and y % 400 != 0)
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)
这是另一个区别:速度和效率。
除了评估顺序(已在其他答案中提及)...
让我们简化原始表达式
year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
到此:
A and (B or C)
如果A
为假,则没有理由测试B
或C
,因为and
要求双方都是true
。
短路操作员
逻辑运算符 and
和 or
在许多语言中具有 "short-circuit" 效果,包括 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)
- 当
A
为 false
时,右侧 (B or C)
不被计算,节省了 CPU 资源。
- 当
A
为 true
时,B
被计算,但 C
仅在 B
为假时被计算。
没有括号:
A and B or C
- 当
A
为 false
时,B
未被计算,但 C
被(不必要地)计算。
- 当
A
为 true
时,B
被计算。如果 B
是 false
,C
也会计算。
结论:
如果没有括号,当 A
为假(year % 4
测试)时,C
(year % 400
测试)会被不必要地求值。这是 CPU 可以停在 A
的时间的 75%,但会继续做更多不必要的数学运算。
最高效的表达式:
改用这个:
((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0))
此表达式在两种情况下将模(慢除法)替换为按位与(快!)。
更多详细信息:
哪个是"more correct (logically)"? 闰年特有,不泛泛.
带括号
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
没有
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
附加信息
括号更改布尔值的计算顺序(and
在 or
w/o 括号之前)。
鉴于此问题中所有较大的数字都可以被较小的数字整除,因此 returns 无论哪种方式都是正确的结果,但我仍然很好奇。
观察括号的效果:
False and True or True #True False and (True or True) #False
False and False or True #True False and (False or True) #False
没有括号,有些情况下即使 year 不能被 4 整除(第一个布尔值)它仍然 returns True (我知道在这个问题中这是不可能的)! 被 4 整除不是必须的,因此包含括号更正确吗? 这里还有什么我应该注意的吗?有人可以解释一下 not/including 括号的理论逻辑吗?
括号会影响布尔值的顺序。 and
组合在一起并在 or
之前解析,因此:
a and b or c
变为:
(a and b) or c
如果 a
和 b
都为真,或者如果 c
为真,我们得到 True
.
加上括号你得到:
a and (b or c)
现在如果 a
为真且 b
或 c
为真,则得到 True
。
就"correctness,"而言,只要您的代码得出正确的结果,那么"more correct"只是一个见仁见智的问题。我会在您认为可以使结果更清晰的地方包括括号。例如:
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 对何时应该包含文体括号(阅读:遵循自然操作顺序的括号)保持沉默,因此请使用您的最佳判断。
特别是对于闰年,逻辑是:
- 如果年份可以被 4 整除,则转到步骤 2。...
- 如果年份可以被 100 整除,则转到步骤 3。...
- 如果年份可以被 400 整除,则转到步骤 4。...
- 该年为闰年(有366天)。
- 该年不是闰年(它有 365 天)。
换句话说:所有能被 4 整除的年份都是闰年,除非它们能被 100 整除且不能被 400 整除,即:
return y % 4 == 0 and not (y % 100 == 0 and y % 400 != 0)
Which answer is "more correct" and why?
这不是什么'更正确'的问题,而是;你想实现什么逻辑? boolean 表达式中括号'改变order of operations。这允许您在执行时强制执行优先级。
>>> (True or True) and False # or expression evaluates first.
False
>>> True or True and False # and evaluates first.
True
闰年公式中的逻辑rules如下:
闰年是任何可以被4整除的年份(如2012、2016等)
除非能被100整除,否则不能整除(如2100、2200等)
除非能被400整除则为(如2000、2400)
因此例外规则必须优先,这就是 or
周围的括号对于遵守公式规则是必要的。否则 and
的两个参数将首先被评估。
包括括号。在英语中,规则是:
- 年份必须能被 4 整除。
- 年份不能被 100 整除,除非它可以被 400 整除。
带括号的版本最符合这条双管齐下的规则。
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(1) (2)
碰巧,删除括号不会破坏代码,但会导致规则版本不自然:
- 年份必须能被 4 整除,但不能被 100 整除;或
- 年份必须能被 400 整除。
这不是我对闰年规则的看法。
Which answer is "more correct" and why? (Specific to Leap Year Logic, not in general)
With Parentheses
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
Without
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
取决于你对“更正确”的定义。如您所知,两者 return 都是正确的。
现在推测“更正确”- 如果您指的是性能优势,考虑到当前的智能编译器,我想不出任何。
如果你是在讨论人类可读性的观点,我会同意,
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
它自然会缩小范围,这与您的其他选择相反,后者似乎在视觉上包含两个不相交的元素。
我建议,包括括号,但如下所示:
return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
正如你所指出的,在操作上,没有区别,因为数字被400整除意味着它也可以被100整除,这意味着它也可以被4整除。操作上,括号是否有任何效果取决于语言的词汇顺序(求值顺序)。今天的大多数语言都遵循 c 的约定,这意味着运算符的指定优先级,否则是从左到右。如有疑问,我总是会加上括号以提高可读性。
从文体上来说,这种东西放在这么长的表达式中很难读懂。如果它必须是一个表达式,我宁愿使用逻辑 "sum of products" 而不是 "product of sums" 所以我会去
return (year%400 == 0) or (year%100 != 0 and year%4 == 0)
甚至
bool IsLeap = false;
if (year%4 == 0) IsLeap = true;
if (year%100 == 0) IsLeap = false;
if (year%400 == 0) IsLeap = true;
return IsLeap;
无论如何,优化的编译器会产生高效的代码,这种东西确实有助于像我这样的穷人阅读它。
答案:包括括号
John Kugelman 解释了为什么它们是 2 个独立的逻辑测试而不是 3 个,-> 最后 2 个应该组合在一起:
- 年份必须能被 4 整除。
- (2) 年份不能被 100 可见,(3) 除非它能被 400 整除。
带括号的版本最符合这条双管齐下的规则。
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(1) (2)
碰巧,删除括号不会破坏代码,但会导致规则版本不自然:
- 年份必须能被 4 整除,但不能被 100 整除;或
- 年份必须能被 400 整除。
这不是我对闰年规则的看法。
受mrdomoboto启发,100/400是例外!:
年份必须能被4整除,100是个例外,400是例外中的例外,但他们加起来还是一个例外(见上文)。这意味着如果年份不能被 4 整除,那么整个事情一定是假的。确保这一点的唯一方法是将异常放在括号中,因为 False and bool
将始终 return False.
请参阅以下来自 JBallin
的示例False and True or True #True False and (True or True) #False
False and False or True #True False and (False or True) #False
Adam Smith 将英文翻译成代码:
所有能被 4 整除的年份都是闰年,除非它们能被 100 整除且不能被 400 整除,即:
return y % 4 == 0 and not (y % 100 == 0 and y % 400 != 0)
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)
这是另一个区别:速度和效率。
除了评估顺序(已在其他答案中提及)...
让我们简化原始表达式
year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
到此:
A and (B or C)
如果A
为假,则没有理由测试B
或C
,因为and
要求双方都是true
。
短路操作员
逻辑运算符 and
和 or
在许多语言中具有 "short-circuit" 效果,包括 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)
- 当
A
为false
时,右侧(B or C)
不被计算,节省了 CPU 资源。 - 当
A
为true
时,B
被计算,但C
仅在B
为假时被计算。
没有括号:
A and B or C
- 当
A
为false
时,B
未被计算,但C
被(不必要地)计算。 - 当
A
为true
时,B
被计算。如果B
是false
,C
也会计算。
结论:
如果没有括号,当 A
为假(year % 4
测试)时,C
(year % 400
测试)会被不必要地求值。这是 CPU 可以停在 A
的时间的 75%,但会继续做更多不必要的数学运算。
最高效的表达式:
改用这个:
((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0))
此表达式在两种情况下将模(慢除法)替换为按位与(快!)。
更多详细信息: