Is shifting bits faster than multiplying and divid

2019-01-01 13:49发布

Shifting bits left and right is apparently faster than multiplication and division operations on most, maybe even all, CPUs if you happen to be using a power of 2. However, it can reduce the clarity of code for some readers and some algorithms. Is bit-shifting really necessary for performance, or can I expect the compiler or VM to notice the case and optimize it (in particular, when the power-of-2 is a literal)? I am mainly interested in the Java and .NET behavior but welcome insights into other language implementations as well.

13条回答
墨雨无痕
2楼-- · 2019-01-01 14:10

If the compiler (compile-time constant) or JIT (runtime constant) knows that the divisor or multiplicand is a power of two and integer arithmetic is being performed, it will convert it to a shift for you.

查看更多
倾城一夜雪
3楼-- · 2019-01-01 14:12

Humans are wrong in these cases.

99% when they try to second guess a modern (and all future) compilers.
99.9% when they try to second guess modern (and all future) JITs at the same time.
99.999% when they try to second guess modern (and all future) CPU optimizations.

Program in a way that accurately describes what you want to accomplish, not how to do it. Future versions of the JIT, VM, compiler, and CPU can all be independantly improved and optimized. If you specify something so tiny and specific, you lose the benefit of all future optimizations.

查看更多
浅入江南
4楼-- · 2019-01-01 14:14

I would ask "what are you doing that it would matter?". First design your code for readability and maintainability. The likelyhood that doing bit shifting verses standard multiplication will make a performance difference is EXTREMELY small.

查看更多
心情的温度
5楼-- · 2019-01-01 14:16

According to the results of this microbenchmark, shifting is twice as fast as dividing (Oracle Java 1.7.0_72).

查看更多
墨雨无痕
6楼-- · 2019-01-01 14:18

This is an analysis of the benchmark done by from Savvas Dalkitsis. Although this test checks speed of multiplication over bit shifting, the values used are not the same, check code below in C# which displays the values)

for (int i = 0, j = 1, k = 1; i < 10; i++)
{
  j = j * 2;
  k <<= 2;
  Console.WriteLine("{0} {1}", j, k);
}

The equivalent code of Savvas Dalkitsis example with the values displayed in C# will be

    public static void Main(String[] args)
    {
        for (int i = 0, j = 1, k = 1; i < 10; i++)
        {
            j = j * 2; k <<= 2;
            Console.WriteLine("{0} {1}", j, k);
        }
        Console.WriteLine("-----------------------------------------------");


        DateTime before = DateTime.Now;
        for (int j = 1; j < 500000000; j++)
        {
            int a = 1;
            for (int i = 0; i < 10; i++) a *= 2;
        }
        DateTime after = DateTime.Now;

        Console.WriteLine("Multiplying " + (after - before).ToString() + " milliseconds");

        before = DateTime.Now;
        for (int j = 1; j < 500000000; j++)
        {
            int a = 1;
            for (int i = 0; i < 10; i++) a = a << 1;
        }
        after = DateTime.Now;
        Console.WriteLine("Shifting " + (after - before).ToString() + " milliseconds");
        Console.ReadKey();
    }
查看更多
梦该遗忘
7楼-- · 2019-01-01 14:19

Most compilers today will do more than convert multiply or divide by a power-of-two to shift operations. When optimizing, many compilers can optimize a multiply or divide with a compile time constant even if it's not a power of 2. Often a multiply or divide can be decomposed to a series of shifts and adds, and if that series of operations will be faster than the multiply or divide, the compiler will use it.

For division by a constant, the compiler can often convert the operation to a multiply by a 'magic number' followed by a shift. This can be a major clock-cycle saver since multiplication is often much faster than a division operation.

Henry Warren's book, Hacker's Delight, has a wealth of information on this topic, which is also covered quite well on the companion website:

See also a discussion (with a link or two ) in:

Anyway, all this boils down to allowing the compiler to take care of the tedious details of micro-optimizations. It's been years since doing your own shifts outsmarted the compiler.

查看更多
登录 后发表回答