有趣的是,大多数答案都认为编译器会将乘以 2 的幂优化为位移。很明显,没有一个响应者真正尝试过编译位移和乘法来查看编译器实际产生的结果。
这纯粹是一个学术练习;正如几乎每个人都指出的那样,乘法更容易阅读(尽管有人猜测为什么“* 200L / 100L”部分存在 - 这只是为了混淆事物)。同样很明显,在 C# 中用位移位替换乘法不会有任何显着的性能提升,即使在紧密循环中也是如此。如果您需要这种优化,那么您一开始就使用了错误的平台和语言。
让我们看看当我们使用 Visual Studio 2010 中包含的 CSC(C# 编译器)编译一个启用了优化的简单程序时会发生什么。这是第一个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j *= 2;
}
}
使用 ildasm 反编译生成的可执行文件会为我们提供以下 CIL 清单:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] int32 j,
[1] int32 i)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.0
IL_0003: stloc.1
IL_0004: br.s IL_000e
IL_0006: ldloc.0
IL_0007: ldc.i4.2
IL_0008: mul
IL_0009: stloc.0
IL_000a: ldloc.1
IL_000b: ldc.i4.1
IL_000c: add
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldc.i4 0x186a0
IL_0014: blt.s IL_0006
IL_0016: ret
} // end of method Program::Main
这是第二个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j <<= 1;
}
}
对它进行反编译会得到以下 CIL 清单:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] int32 j,
[1] int32 i)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.0
IL_0003: stloc.1
IL_0004: br.s IL_000e
IL_0006: ldloc.0
IL_0007: ldc.i4.2
IL_0008: shl
IL_0009: stloc.0
IL_000a: ldloc.1
IL_000b: ldc.i4.1
IL_000c: add
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldc.i4 0x186a0
IL_0014: blt.s IL_0006
IL_0016: ret
} // end of method Program::Main
注意第 8 行的区别。程序的第一个版本使用乘法 (mul),而第二个版本使用左移 (shl)。
我不确定执行代码时 JIT 对它的作用,但 C# 编译器本身确实不将乘以 2 的幂优化为位移位。