现代处理器应该把这两种计算法优化得都差不多了,可以从多种途径测试一下,看汇编码或者测试:long starttime = System.currentTimeMillis(); for(long i = 0; i < 1000000000; i++) { int x = 100 << 2; } long endtime = System.currentTimeMillis(); System.out.println(endtime - starttime);
long starttime = System.currentTimeMillis(); for(long i = 0; i < 1000000000; i++) { int x = 100 * 2; } long endtime = System.currentTimeMillis(); System.out.println(endtime - starttime);时间越长越精确,当然这不能100%证明,但至少有一点,两个整数的乘法可以转换为位移操作和加法的组合,而加法和位移操作速度是没有区别的 int c = 0; int b = 7; int a = 5;
while(b!=0) { if((b & 1) != 0) { c = c + a; a <<= 1; b >>= 1; } } System.out.println(c);
现代 CPU 都含有乘法、除法指令,因此做这些与做移位的效率是一样的,没区别。只是那种非常 SB 的面试喜欢出一些“如何更高效地计算 2 * 8”这种问题纯属有病,而且还病得不清!两个常量的运算竟然交给计算机去算!
如果真想了解位运算的话,可以看一下这本书: Henry S. Warren, Jr. 写的的 Hacker's Delight,中文版书名:《高效程序的奥秘》。http://www.hackersdelight.org 这本书是位运算的巅峰之作。
等同于
num <<= 5; /* 2 的 5 次方等于 32 */如果乘数不是 2 的 n 次方,我们可以把乘数分解成几个 2 的 n 次方的和:
num *= 20;
等于
num *= (16 + 4);
等于
num = num * 16 + num * 4;
等于
num = (num << 4) + (num << 2); 不过,现在的编译器很聪明,它们会代替我们做这种优化。也就是说,如果我们写的语句是:
num *= 100;
编译器会把这个语句优化为:
num = (num << 6) + (num << 5) + (num << 2);不知道还有什么区别。
无符号右移会在高位自动补0
for(long i = 0; i < 1000000000; i++) {
int x = 100 << 2;
}
long endtime = System.currentTimeMillis();
System.out.println(endtime - starttime);
long starttime = System.currentTimeMillis();
for(long i = 0; i < 1000000000; i++) {
int x = 100 * 2;
}
long endtime = System.currentTimeMillis();
System.out.println(endtime - starttime);时间越长越精确,当然这不能100%证明,但至少有一点,两个整数的乘法可以转换为位移操作和加法的组合,而加法和位移操作速度是没有区别的
int c = 0;
int b = 7;
int a = 5;
while(b!=0) {
if((b & 1) != 0) {
c = c + a;
a <<= 1;
b >>= 1;
}
}
System.out.println(c);