【问题标题】:An operator riddle运营商之谜
【发布时间】:2012-07-20 06:57:36
【问题描述】:

在将项目从 Python 转换为 C# 时,我发现语法系列中有一些有趣的差异。然而我陷入了困境,仍然无法理解和理解 C# 中 比较运算符 的不同行为。

在消除这种好奇心的过程中,我考虑了一些 C 语法家族的语言; C、C++、C#、Java、Javascript.. 并验证了行为。事情的经过是这样的:

Let a=2, b=3, c=4, d=5;

现在,考虑以下表达式:

a < a < a  // returns true
c < b < a  // returns true
c > b > a  // returns false
a < c > b  // returns false

如果是因为right-associativity,那么 JavaScript 中的以下代码不应该像这样:

console.info(a < false);   // returns false
console.info(a < a);       // returns false
console.info(a < a < a);   // returns true, as opposed to returning false

这里是 C/C++ 版本

int main(){
    int a=2, b=3, c=4, d=5;

    printf("%s\n","false\0true"+6*(a < a < a));  // returns true
    printf("%s\n","false\0true"+6*(c < b < a));  // returns true
    printf("%s\n","false\0true"+6*(c > b > a));  // returns false
    printf("%s\n","false\0true"+6*(a < c > b));  // returns false

  return 0;
}

Python 除外,其中

a < a < a  // returns false
c < b < a  // returns false
c > b > a  // returns true
a < c > b  // returns true

谁能解释为什么 C 系列语言和 Python 计算表达式的方式不同?

【问题讨论】:

  • 如果您使用文字而不是变量来编写示例,这个问题将非常更容易理解。

标签: algorithm programming-languages comparison operators imperative-programming


【解决方案1】:

因为Python uses a slightly interpretation of your input

形式上,如果a, b, c, ..., y, z 是表达式并且op1, op2, ..., opN 是比较运算符,那么a op1 b op2 c ... y opN z 等价于a op1 b and b op2 c and ... y opN z,除了每个表达式最多计算一次。

这意味着您的行将被解释为

a < a < a = a < a and a < a // returns false
c < b < a = c < b and b < a // returns false
c > b > a = c > b and b > a // returns true
a < c > b = a < c and c > b // returns true

在 C 风格的语言中,比较表达式的计算结果为 false(整数值 0)或 true(整数值 1)。所以在 C 中它会表现得像

a < a < a = (a < a) < a = 0 < a  // returns true
c < b < a = (c < b) < a = 0 < a  // returns true
c > b > a = (c > b) > a = 1 > a // returns false
a < c > b = (a < c) > b = 0 > b // returns false

请注意,几乎所有语言都使用布尔返回值定义运算符,但由于布尔值可以隐式转换为零或一,上述命题仍然有效:

// C++ example
struct myComparableObject{
    int data;
    bool operator<(const myComparableObject& o){
       return data < o.data;
    }
};

myComparableObject a, b;
a.data = 2;
b.data = 3;
int c = 5;

a < b; // true
a < c; // error, a cannot be converted to int / unknown operator
a.data < c; // true
a < b < c; // true, as this is equal to
           //   (a < b) < c = false < c = 0 < c

例如,JavaScript 实际上会使用ToNumber 来比较两个非字符串对象,请参阅[ECMAScript p78, 11.8.5 抽象关系比较算法],其中ToNumber(false) 为零,ToNumber(true) === 1

比较x &lt; y,其中xy 是值,产生truefalseundefined[...]

  • 令 px 为调用 ToPrimitive(x, hint Number) 的结果。
  • 令 py 为调用 ToPrimitive(y, hint Number) 的结果。

    1. 如果不是Type(px)是String,Type(py)不是String,那么

      a.令nx为调用ToNumber(px)的结果。因为 px 和 py 是原始值评估 顺序并不重要。
      b. 令 ny 为调用 ToNumber(py) 的结果。
      c. 如果 nx 为 NaN,则返回 undefined。
      d. 如果 ny 为 NaN,则返回 undefined .
      e.如果nx和ny是相同的数值,返回false。
      f.如果nx为+0,ny为-0,返回false。
      g. 如果 nx 为 -0 且 ny 为 +0,则返回 false。
      h. 如果 nx 为 +infty,则返回 false。
      i. 如果 ny 为 +infty,则返回 true。
      j. 如果 ny 是 -infty,则返回 false。
      k. 如果 nx 是 -infty,则返回 true。
      l. 如果 nx 的数学值小于 ny 的数学值 —注意这些 数学值既是有限的,又不是都是零——返回真。否则,返回假。

【讨论】:

  • 请注意,Javascript 再次略有不同 - 比较返回布尔值,而不是整数,但 Javascript 定义了类型的排序顺序。
  • @NickJohnson,您能否解释一下与 C/C++/C# 相比 JavaScript 的变体行为?
  • @vulcanraven:添加了 ECMAScript 文档中的特定部分。
【解决方案2】:

这是因为 a &lt; a &lt; a 被评估为 ((a &lt; a) &lt; a) 然后变为 0 &lt; a 这是真的(当 a >= 0 时)

如果您运行以下命令,第一个表达式将变为 false。

int main(){
    int a=0, b=3, c=4, d=5;

    printf("%s\n","false\0true"+6*(a < a < a));  // returns false
    printf("%s\n","false\0true"+6*(c < b < a));  // returns true
    printf("%s\n","false\0true"+6*(c > b > a));  // returns false
    printf("%s\n","false\0true"+6*(a < c > b));  // returns false

  return 0;
}

而在 Python 中,a &lt; a &lt; a 变为 a &lt; a and a &lt; a。所以它不是比较a &lt; a 的结果。如果您在语句中添加括号,您将再次获得类似 C 的行为。

(a < a) < a  ## returns true
(c < b) < a  ## returns true
(c > b) > a  ## returns false
(a < c) > b  ## returns false

【讨论】:

  • 我没有意识到它会从左到右进行评估,而不是我们有赋值运算符 c = a &lt; b 的情况。感谢您详细说明您的答案。
猜你喜欢
  • 2018-06-07
  • 2023-01-24
  • 1970-01-01
  • 1970-01-01
  • 2017-02-12
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
相关资源
最近更新 更多