有什么区别
int size = (int)((length * 200L) / 100L); // (1)
Run Code Online (Sandbox Code Playgroud)
和
int size = length << 1; // (2)
Run Code Online (Sandbox Code Playgroud)
(两种情况下长度均为int)
我假设两个代码片段都想要加倍长度参数.
我很想使用(2)......那么使用(1)有什么好处吗?我查看溢出发生时的边缘情况,两个版本似乎都有相同的行为.
请告诉我我错过了什么.
Eri*_*ert 42
<<比乘法更快的想法是推理,好像.NET jit编译器实际上是一个写得不好的C编译器,写于1970年代.即使它是真的,这个时间点的差异将以皮秒为单位进行测量,即使存在差异,也可能没有.
编写代码以便于阅读.让编译器处理微微优化.基于分析实际场景优化代码,而不是第二次猜测编译器将生成什么.
此外,移位运算符与乘法不具有相同的语义.例如,请考虑以下编辑顺序:
Jill的原创节目:
int x = y * 2;
Run Code Online (Sandbox Code Playgroud)
鲍勃编辑:傻吉尔,我会让这个"更快":
int x = y << 1;
Run Code Online (Sandbox Code Playgroud)
由实习生拉里编辑:哦,我们有一个错误,我们一个人关闭,让我解决这个问题:
int x = y << 1 + 1;
Run Code Online (Sandbox Code Playgroud)
而拉里刚刚推出了一个新的bug.y*2 + 1与y << 1 + 1不同; 后者实际上是y*4.
我在实际的实时生产代码中看到了这个bug.精神上很容易进入"移位是乘法"的思维模式,忘记移位优先于加法,而乘法优先级更高.
我从来没有见过有人通过写x*2得到算术优先级错误乘以2.人们理解+和*的优先级.很多人都忘记了转移的优先顺序.您实际上没有保存的皮秒是否值得任何数量的潜在错误?我拒绝.
Inc*_*ito 27
And here is the 3rd option:
int size = length * 2; // Comment explaining what is 2 or what means this multiplication
Run Code Online (Sandbox Code Playgroud)
And this must be the best option. As it is readable and easy to understand what you want to do.
As for performance, compilers are generating pretty optimized code, so no need to worry for such a simple operation.
If you have any concerns concerning overflow you can use checked block.
EDIT As mentioned by many others just use any meaningful variable instead of 2 here.
Which is more readable to your average programmer:
int size = length * 2;
int size = length << 1;
Run Code Online (Sandbox Code Playgroud)
Unless they come from a strong C++ bit tweaking background I'd wager your average programmer knows immediately what the first line does (it even has the number "2" for "double" in it) but would have to stop and pause for the second line.
In fact I'd feel inclined to comment the second line explaining what it does which seems redundant when you can get the code do the talking as in the first line.
What do 200L and 100L represent? Seems to me you are using magic numbers. You should try to write your program in such a way that it describes its intent as good as possible; making it as readable as possible. Using named constants for these values instead of magic numbers is a good way of doing this. Also extracting the calculation in its own well named method helps too. When you do this, you will immediately see that there is no way of rewriting it to x << 1. Not because the results will be different, but because maintainability will suffer. When you write code like x << 1, the next programmer has no idea what that actually means and it will increase the famous WTFs per minute:
alt text http://www.osnews.com/images/comics/wtfm.jpg
int size = CalculateSizeOfThing(length);
private static int CalculateSizeOfThing(int length)
{
const long TotalArraySize = 200L;
const long BytesPerElement = 100L;
return (length * TotalArraySize) / BytesPerElement;
}
Run Code Online (Sandbox Code Playgroud)
当然,这些const值的名称是一个疯狂的猜测:-)
有趣的是,大多数答案都认为编译器会优化乘以2的幂乘以比特移位.显而易见的是,没有任何响应者实际上尝试编译bithift而不是乘法来查看编译器实际产生的内容.
这纯粹是一种学术活动; 就像每个人都指出的那样,乘法更容易阅读(尽管为什么"*200L/100L"部分存在于任何人的猜测中 - 这只是用来混淆事物).很明显,即使在紧密的循环中,用C#中的bitshift替换乘法也不会有任何显着的性能提升.如果您需要这种优化,那么您开始使用错误的平台和语言.
让我们看看当我们使用Visual Studio 2010附带的CSC(C#编译器)编译一个简单的程序并启用了优化时会发生什么.这是第一个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j *= 2;
}
}
Run Code Online (Sandbox Code Playgroud)
使用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
Run Code Online (Sandbox Code Playgroud)
这是第二个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j <<= 1;
}
}
Run Code Online (Sandbox Code Playgroud)
反编译这给我们提供了以下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
Run Code Online (Sandbox Code Playgroud)
注意第8行的差异.程序的第一个版本使用乘法(mul),而第二个版本使用左移(shl).
JIT在执行代码时对它做了什么我不确定,但C#编译器本身显然没有优化乘以2的幂乘以位移.