本期的语法话题为:
两个int类型的变量a与b( a ≠ b a \neq b a=b):
- 不允许使用任何比较运算符(例如>,<,?:等)。
- 不允许使用任何选择判断语句(例如if,switch等)。
- 不允许使用任何比较函数(例如max,min等)。
怎样输出a与b中的较大者?
这个问题也经常作为程序员的面试题被问到,当然,解决本问题的方式不止一种,我们现在就来给出几种不同的实现方式。
我们知道, ∣ a − b ∣ |a - b| ∣a−b∣可以表示成如下的形式:
∣ a − b ∣ = { a − b a ⩾ b b − a a < b |a - b| = \left\{\begin{matrix} a - b & a \geqslant b \\ b - a & a < b & \\ \end{matrix}\right. ∣a−b∣={a−bb−aa⩾ba<b
因此,我们就可以通过绝对值完成任务,如下:
a
+
b
+
∣
a
−
b
∣
2
\frac{a + b + |a - b|}{2}
2a+b+∣a−b∣
在Java中,程序如下:
package test; public class Test { public static void main(String[] args) { int a = 2; int b = 3; int c = (a + b + Math.abs(a - b)) / 2; System.out.println(c); } }
程序运行结果如下:
3
不过,通过绝对值的方式,严格来说并不算是正确的解决方案,因为在Java中,Math类的abs方法实现,也是通过?:运算符来判断的,源码如下:
public static int abs(int a) { return (a < 0) ? -a : a; }
所以,如果遇到严格的面试官(比如梁老师^_^),这就不是一个最佳的解决方案。不过,我们依然可以通过其他方法来解决该问题。
对于int类型的变量,在内存中占用4个字节,也就是32位。int类型变量在内存中的存储格式为:
1个符号位 + 31个数据位
当变量存储的数值为非负数时,符号位为0,否则为1(变量存储数值为负数)。因此,我们可以通过符号位来判断变量a与b谁大。令c = a - b,则:
c = a − b ⇒ { c 的 符 号 位 为 0 ⇒ a − b ⩾ 0 ⇒ a 大 c 的 符 号 位 为 1 ⇒ a − b < 0 ⇒ b 大 c = a - b \Rightarrow \left\{\begin{matrix} c的符号位为0 & \Rightarrow a - b \geqslant 0 & \Rightarrow a大 \\ c的符号位为1 & \Rightarrow a - b < 0 & \Rightarrow b大 \\ \end{matrix}\right. c=a−b⇒{c的符号位为0c的符号位为1⇒a−b⩾0⇒a−b<0⇒a大⇒b大
可是,该如何获取变量c的符号位呢?通过与运算即可。
对于数据中的某个位(bit),设为x,有:
{ x & 1 = = x 保 留 x 位 的 信 息 x & 0 = = 0 清 理 x 位 的 信 息 \left\{\begin{matrix} x \& 1 == x & 保留x位的信息\\ x \& 0 == 0 & 清理x位的信息\\ \end{matrix}\right. {x&1==xx&0==0保留x位的信息清理x位的信息
这样,我们就可以通过与运算,只保留符号位,而将其余31位(数据位)都清零,根据运算结果,就可以获取a与b的较大者,执行操作如下:
(a - b) & 0x8000_0000
程序实现如下:
package test; public class Test { public static void main(String[] args) { int a = 2; int b = 3; int c = (a - b) & 0x8000_0000; String result = c == 0 ? "a大,值为:" + a : "b大,值为:" + b; System.out.println(result); } }
程序运行结果如下:
b大,值为:3
这种方式与之前的与远算差不多,同样令c = a - b,然后对变量c进行无符号右移31位(只保留符号位),这样一来,c中的符号位就会成为数据位中的最后一位(最低位),其余31位高位都是0。
这种实现,只需要把与运算程序中的第7行,修改成如下的方式即可:
int c = (a - b) >>> 31;