3

在将项目从 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 计算表达式的方式不同?

4

2 回答 2

4

因为Python 对您的输入进行了轻微的解释

形式上,如果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 The Abstract Relational Comparison Algorithm],其中ToNumber(false)0 和ToNumber(true) === 1.

比较x < y, wherexyare values, 产生true, false, 或undefined[...]

  • 令 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 是相同的 Number 值,则返回 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 的数学值——<em>请注意,这些数学值都是有限的,而不是都是零——返回真。否则,返回假。
于 2012-07-20T07:02:41.793 回答
2

这是因为a < a < a被评估为((a < a) < a)which then 成为0 < atrue (当 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 < a < a变成a < a and a < a. 所以它不是比较a < a. 如果您在语句中添加括号,您将再次获得类似 C 的行为。

(a < a) < a  ## returns true
(c < b) < a  ## returns true
(c > b) > a  ## returns false
(a < c) > b  ## returns false
于 2012-07-20T07:04:03.837 回答