检查整数是否在两个数字之间

33

如果您尝试查找一个整数是否在两个数字之间,为什么不能这样做:

if(10 < x < 20)

你不再使用它,而是要做

if(10<x && x<20)

这似乎会增加一些额外的开销。


12
因为这是Java使用的语法。没有“为什么”,它就是这样。 - skaffman
1
@Timo Willemsen - 关于上面的评论;也许你看到的问题有点因你使用的数学而恶化,但在日常使用中(在通用语言中),这并不是一个大问题,因此不值得使用不同的语法。 - Marc Gravell
@Timo - 学会不被语法问题所困扰。 - Stephen C
11
不管Java会不会改变,挑战这种设计决策都不是异端。你可能会觉得“自然编程”研究很有启发性。他们研究的内容包括要求人们去水果篮子里拿出“不是苹果也不是梨子的东西”。如果你没有夸张地重读“OR”,很少有人会拿回一个梨子……因为我们会将其解读为(not(apple or pear))而不是(not apple) or (pear)。我们可以调整编程语言以更好地符合人类的期望。请参见:http://www.cs.cmu.edu/~NatProg/index.html - HostileFork says dont trust SE
挑战语言设计决策是可以的...但是除非你打算采取行动,否则这在很大程度上是浪费时间。但无论如何,这都不是SO的主题。 - Stephen C
显示剩余4条评论
11个回答

22

问题之一是,三元关系结构会引入严重的解析器问题:

<expr> ::= <expr> <rel-op> <expr> |
           ... |
           <expr> <rel-op> <expr> <rel-op> <expr>
当你试图用典型的自下而上语法分析器来表达这些产生式的语法时,你会发现在第一个 <rel-op> 的位置存在一种移进-归约冲突(shift-reduce conflict)。解析需要向前查看任意数量的符号,以确定是否在其之前有第二个 <rel-op>,才能决定是使用二元还是三元形式。在这种情况下,你不能简单地忽略该冲突,因为那将导致错误的解析。
我并不是说这个语法是严重的二义性。但我认为你需要一个回溯解析器才能正确处理它。对于一个编程语言而言,快速编译是一个主要的卖点,而这是一个严重的问题。

3
不完全是。请参考http://docs.python.org/reference/expressions.html#notin和http://docs.python.org/reference/grammar.html了解Python如何处理它。 - Adam Rosenfield
@Adam - 这很奇怪。语法允许“1 < i < 3 < 4”等等。我猜这都是由语义分析器解决的。 - Stephen C
你的第一个生产规则使用 (<expr> <rel-op> <expr>) <rel-op> <expr>,这将是你第三行代码的解析方式(因为Java中关系运算符是左结合的)。我没有看到你的例子如何证明你的观点。 - Eric Towers
@EricTowers - 当然可以。但那不是重点。重点是解析器必须理解用户没有包含括号的情况。而当一个单元构造有两个运算符和三个操作数时,正常的结合律实际上并不适用。 - Stephen C

10

为什么这种语法根本没有定义呢?此外,x < y的计算结果是布尔值,那么bool < int是什么意思呢?这并不是额外的负担;此外,如果你真的想要 - isBetween(10,x,20) - 你可以编写一个实用程序方法。虽然我自己不会这样做,但嘿……


6
有趣的是,我认为 isBetween() 方法的第一个参数应该是要测试的值,第二个和第三个参数应该是上限和下限。不要问我原因,这种方式只是更加合理。 - Joachim Sauer
3
说实话,我不打算为顺序感到兴奋和担忧。嘿,我主要是C#程序员,所以我可以添加一个扩展方法:if(x.IsBetween(10,20)) {...} ;-p - Marc Gravell
2
@Cellfish:流畅的API都很好,但你走得太远了:x.IsBetween(10)是什么意思? - Joachim Sauer
@Joachim - 一些短暂的接口。实际上,这种模式(带有流畅的API)在.NET测试框架中并不罕见。 - Marc Gravell
1
那是什么样的回答?难道OP不知道语法不是定义吗?你是在暗示三元运算符不存在吗? - irreputable
显示剩余2条评论

10

这只是语法问题。'<' 是一个二元操作符,大多数语言不会使其具有传递性。他们本可以像你说的那样设计它,但之后就会有人问为什么不能在三元操作符中使用其他操作呢?比如 "if (12 < x != 5)"?

语法始终是复杂性、表达能力和可读性之间的权衡。不同的语言设计者做出了不同的选择。例如,SQL 中有 "x BETWEEN y AND z",其中 x、y 和 z 可以分别或全部是列、常量或绑定变量。我很高兴在 SQL 中使用它,并且同样也很高兴不用担心它在 Java 中不存在的原因。


3
然而,在Python中可以使用这样的结构。 - President James K. Polk
实际上,我更喜欢Marc的答案而不是我的。 - Paul Tomblin

8
您可以自己制作。
public static boolean isBetween(int a, int b, int c) {
    return b > a ? c > a && c < b : c > b && c < a;
}

编辑:抱歉,检查 c 是否在 a 和 b 之间


1
这个不正常,因为如果你在10到20之间检查并且想要检查20,它会返回false。 - mas-designs
@EvilP 这是主要的事情;between 意味着,字面上来说,是在两个值之间。所以是排除两端的。 - Dediqated
Java 默认库中没有类似这样的东西吗? - Simon Baars
如何包含边界值?假设a = 100,b = 200和c = 100。如何使此条件也为真?在当前情况下它是假的。 - Revan siddappa

7

相比于允许10 < x < 20,键入10 < x && x < 20的不便微不足道, 因此Java语言的设计师决定不支持它,以避免语言复杂度增加。


6

COBOL允许这样做(我相信其他一些语言也可以)。Java大部分语法是从不允许这样做的C语言继承而来的。


1
显然,自从我上一次开发COBOL以来已经过去了很长时间,因为我已经记不起来了。只是因为我有点疯狂,想要恢复我的记忆,请你用大写字母发表一行评论吧 :-) - Fredrik
3
我很确定我记得在 COBOL 中做过那件事情(哭泣) - TofuBeer
显然,使用不同的语法,以下是关于编程的内容。请返回已翻译的文本。 - TofuBeer
1
@TofuBeer:好的,我要求它了 :-D - Fredrik
通用Lisp允许这些比较运算符的任何正数位数。对于<的情况,参数必须单调递增才能评估为t。请参见http://www.lispworks.com/documentation/HyperSpec/Body/f_eq_sle.htm#LT。 - seh
Icon 也允许使用语法 10 < x < 20,因为所有操作都会产生“成功或失败”和一个值。 - Code-Apprentice

4
您是人类,因此您理解“10 < x < 20”这个术语的含义。计算机没有这种直觉,所以它将其读作:“(10 < x)< 20”。
例如,如果x = 15,则计算如下:
(10 < x)=> TRUE
“TRUE < 20” => ???
在C编程中,情况会更糟,因为没有True \ False值。如果x = 5,则计算如下:
10 < x => 0(False的值)
0 < 20 =>非0数字(True)
因此,“10 < 5 < 20”将返回True! :S

2
我知道它是如何工作的。但编程语言不是应该让人类更容易吗?否则我们仍然会写汇编或二进制代码。 - Timo Willemsen
这是一个重要的观点:将“10 < x < 20”设为非法的比使用C方式更有帮助(虽然C方式使表达式有效,但它不会按非C程序员所期望的方式执行)。 - Joachim Sauer
Timo - 你可能会对这篇文章感兴趣:http://blogs.msdn.com/ericgu/archive/2004/01/12/57985.aspx。记住,总有人需要实现你的请求,并进行调试、测试和维护。 - Michael Petrotta
1
有人认为多重继承和宏也是一个好主意。或许是这样,但代价是什么? - Michael Petrotta
1
这并不是计算机普遍固有的东西,而是大多数流行编程语言所具有的。正如其他人指出的那样,一些编程语言允许更数学化的 10 < x < 20 语法。 - Code-Apprentice
显示剩余2条评论

1
简化:
a = 10; b = 15; c = 20

public static boolean check(int a, int b, int c) {
    return a<=b && b<=c;
}

这个代码检查 b 是否在 a 和 c 之间


0
可以使用Guava库中的Range类:
 Range.open(10, 20).contains(n)

Apache Commons Lang 也有类似的类。


0

由于<运算符(以及大多数其他运算符)都是二元运算符(它们需要两个参数),而 (true true) 不是一个有效的布尔表达式。

Java 语言设计者本可以设计一种允许您所偏好的语法的语言,但他们决定不值得增加更复杂的解析规则(我猜测如此)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接