假设如下:你有两个函数,它们都做了基本相同的事情,即将两个随机布尔值与AND和OR运算符进行比较 . 但是一个函数用普通的条件运算符&&和||来做,另一个用位运算符&和| .
我认为这两个功能当然需要相同的时间来完成,他们不会这样做 . 具有按位比较的那个比使用"normal"条件运算符的时间多五分之一 .
我很困惑并做了一些研究,并在Oracle的Java文档中找到了条件运算符的以下定义:
The && and || operators perform Conditional-AND and Conditional-OR operations on two boolean expressions. These operators exhibit "short-circuiting" behavior, which means that the second operand is evaluated only if needed.
&& Conditional-AND
|| Conditional-OR
对于按位运算符:
The Java programming language also provides operators that perform bitwise and bit shift operations on integral types.
The bitwise & operator performs a bitwise AND operation.
The bitwise | operator performs a bitwise inclusive OR operation.
嗯,这些定义并没有让我满意,我的问题仍未得到解答 . 所以我做了一些更多的研究,并在stackoverflow上找到了一个关于按位运算符对Java中的布尔运算效果的问题(Effect of a Bitwise Operator on a Boolean in Java),但这并没有真正回答我的问题 .
这是我测试它的代码,它使用一个随机数生成器来获得随机布尔值,以便相互比较并循环遍历那个时代的loooot .
import java.util.Random;
public class Main {
private static final long LOOPS = 100000000L;
private static Random rng = new Random();
public static final void main(String[] args)
{
System.out.println("Bitwise operator: "+loopWithBitwiseOperator(LOOPS));
System.out.println("Normal operator: "+loopWithNormalOperator(LOOPS));
}
public static long loopWithNormalOperator(long loops)
{
long startTime = System.currentTimeMillis();
for (long i = 0L; i < loops; i++)
{
if (rng.nextBoolean() || rng.nextBoolean())
{
i++;
}
if (rng.nextBoolean() && rng.nextBoolean())
{
i++;
}
}
return System.currentTimeMillis()-startTime;
}
public static long loopWithBitwiseOperator(long loops)
{
long startTime = System.currentTimeMillis();
for (long i = 0L; i < loops; i++)
{
if (rng.nextBoolean() | rng.nextBoolean())
{
i++;
}
if (rng.nextBoolean() & rng.nextBoolean())
{
i++;
}
}
return System.currentTimeMillis()-startTime;
}
}
我收到了以下输出:
Bitwise operator: 2502
Normal operator: 1806
因此,按位运算符实际上比“正常”运算符慢 . 我的第一个想法是,随机数生成器生成的布尔值可能在某种程度上在运行时被视为不同,并且当与另一个布尔值进行比较时,它实际上按位比较比需要更多,因为未定义它是如何实际保存的 . 但后来我认为它可能会因为条件运算符的“短路”机制而发生,这可能不适用于可能实际上需要两个值进行比较的按位运算符 .
我的假设是否正确?为什么会这样?另一个特定于示例的行为并不代表Java逻辑运算符的实际行为?
一如既往,感谢任何帮助和提前澄清 .
编辑:
根据评论中的要求,我试图切换调用并包含某种预热阶段,但仍然没有太大的变化:
Normal operator: 1801
Bitwise operator: 2433
1 回答
Louis Wasserman的评论是正确的诊断 . 对随机数发生器的调用次数强烈影响性能,因此短路很重要 . 我修改了程序,使用以下几种方法计算调用次数:
我还在每次运行中进行了多次测量,以消除任何启动效应问题 . 典型的输出是:
4:3的比例如预期 . 每个
if
都会进行一次强制通话 . 如果使用短路运算符,那么只有一半会导致第二次呼叫,每个if
预期1.5次呼叫,而没有短路则为if
. 这个比率与性能比相似,假设呼叫占了大部分时间,但不是全部时间 .JLS中记录了短路行为 . 从技术上讲,当应用于布尔操作数时,
&
和|
是Boolean Logical Operators . "normal"运算符是Conditional-And和Conditional-Or运算符 .通常最好避免迭代次数取决于结果,尽管在这种情况下,如果有足够的迭代次数,则运行之间的差异很小 .