What are the differences between
有什么区别
int size = (int)((length * 200L) / 100L); // (1)
and
int size = length << 1; // (2)
(length is int in both cases)
(两种情况下长度均为int)
I assume both code snippets want to double the length parameter.
我假设两个代码片段都想要加倍长度参数。
I'd be tempted to use (2) ... so are there any advantages for using (1)? I looked at the edge cases when overflow occurs, and both versions seem to have the same behavior.
我很想使用(2)......所以使用(1)有什么好处吗?我查看溢出发生时的边缘情况,两个版本似乎都有相同的行为。
Please tell me what am I missing.
请告诉我我错过了什么。
9 个解决方案
#1
26
And here is the 3rd option:
这是第三种选择:
int size = length * 2; // Comment explaining what is 2 or what means this multiplication
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.
这一定是最好的选择。因为它易读且易于理解您想要做什么。至于性能,编译器正在生成相当优化的代码,因此无需担心这么简单的操作。如果您对溢出有任何疑虑,可以使用check block。
EDIT As mentioned by many others just use any meaningful variable instead of 2
here.
编辑正如许多其他人所提到的,只需使用任何有意义的变量而不是2。
#2
37
The idea that <<
is faster than multiplication is reasoning as though the .NET jit compiler is actually a poorly optimized C compiler written in the 1970's. Even if it were true, the difference would be measured in picoseconds at this point in time, even if there were a difference, which there probably is not.
认为< <比乘法更快的想法是因为.net jit编译器实际上是一个在1970年代写的不太优化的c编译器。即使它是真的,这个时间点的差异将以皮秒为单位,即使存在差异,也可能没有。< p>
Write code so that it is easy to read. Let the compiler take care of the pico-optimizations. Optimize your code based on profiling realistic scenarios, not on second guessing what the compiler will generate.
编写代码以便于阅读。让编译器处理微微优化。基于剖析现实场景优化代码,而不是第二次猜测编译器将生成什么。
Furthermore, the shift operators do not have the same semantics as multiplication. For example, consider the following sequence of edits:
此外,移位运算符不具有与乘法相同的语义。例如,请考虑以下编辑顺序:
Original program by Jill:
Jill的原创节目:
int x = y * 2;
Edit by Bob: Silly Jill, I'll make this "faster":
鲍勃编辑:傻吉尔,我会让这个“更快”:
int x = y << 1;
Edit by Larry the Intern: Oh, we have a bug, we're off by one, let me fix that:
由实习生拉里编辑:哦,我们有一个错误,我们一个接一个,让我解决这个问题:
int x = y << 1 + 1;
and Larry has just introduced a new bug. y * 2 + 1 is different than y << 1 + 1; the latter is actually y * 4.
而拉里刚刚推出了一个新的bug。 y * 2 + 1与y << 1 + 1不同;后者实际上是y * 4。
I have seen this bug in real live production code. It is very easy to mentally get into the mindset that "shifting is multiplication" and forget that shifting is lower precedence than adding, whereas multiplication is higher precedence.
我在实际的实时生产代码中看到了这个bug。精神上很容易进入“转移是乘法”的思维模式,忘记转移的优先级低于加法,而乘法则优先级更高。
I have never once seen someone get arithmetic precedence wrong who multiplied by two by writing x * 2. People understand the precedence of + and *. Lots of people forget what the precedence of shifting is. Are the picoseconds you don't actually save worth any number of potential bugs? I say no.
我从来没有见过有人通过写x * 2得到算术优先级错误乘以2。人们理解+和*的优先级。很多人都忘记了转变的优先顺序。您实际上没有节省的皮秒是否值得任何数量的潜在错误?我拒绝。
#3
7
Which is more readable to your average programmer:
这对普通程序员来说更具可读性:
int size = length * 2;
int size = length << 1;
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.
除非它们来自强大的C ++位调整背景,否则我会打赌你的普通程序员会立即知道第一行是什么(它甚至有“2”代表“double”)但是必须停止并暂停第二行线。
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.
事实上,我倾向于评论第二行,解释它的作用,当你可以让代码像第一行那样进行说话时,这似乎是多余的。
#4
5
It's interesting that most of the answers argue that the compiler will optimise a multiply by a power of 2 into a bitshift. It's obvious that none of the responders have actually tried compiling a bitshift versus a multiply to see what the compiler actually produces.
有趣的是,大多数答案都认为编译器会优化乘以2的幂乘以比特移位。很明显,没有一个响应者真的尝试过编译一个bithift而不是一个乘法来看看编译器实际产生了什么。
This is purely an academic exercise; as just about everyone has pointed out, the multiply is easier to read (though quite why the "*200L / 100L" part is in there is anyone's guess - that just serves to obfuscate things). It's also pretty obvious that replacing a multiply with a bitshift in C# isn't going to have any significant performance increase, even in tight loops. If you need that kind of optimisation, you're using the wrong platform and language to start with.
这纯粹是一种学术活动;正如几乎所有人都指出的那样,乘法更容易阅读(尽管为什么“* 200L / 100L”部分存在于任何人的猜测中 - 这只是用来混淆事物)。很明显,即使在紧密的循环中,用C#中的bitshift替换乘法也不会有任何显着的性能提升。如果您需要这种优化,那么您使用的是错误的平台和语言。
Let's see what happens when we compile a simple program with CSC (the C# compiler) included with Visual Studio 2010 with optimisations enabled. Here's the first program:
让我们看看当我们使用Visual Studio 2010附带的CSC(C#编译器)编译一个简单的程序并启用了优化时会发生什么。这是第一个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j *= 2;
}
}
Using ildasm to decompile the resultant executable gives us the following CIL listing:
使用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
Here's the second program:
这是第二个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j <<= 1;
}
}
Decompiling this gives us the following CIL listing:
反编译这给我们提供了以下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
Note the difference at line 8. The first version of the program uses a multiply (mul), whilst the second version uses a left-shift (shl).
注意第8行的差异。程序的第一个版本使用乘法(mul),而第二个版本使用左移(shl)。
Quite what the JIT does to it when the code is executed I'm not sure, but the C# compiler itself demonstrably does not optimise multiplies by powers of two into bitshifts.
JIT在执行代码时对它做了什么我不确定,但C#编译器本身可以证明没有优化乘以2的幂乘以位移。
#5
5
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:
200L和100L代表什么?在我看来,你正在使用魔术数字。您应该尝试以尽可能好地描述其意图的方式编写您的程序;使其尽可能可读。对这些值使用命名常量而不是幻数是一种很好的方法。同样在其自己的命名方法中提取计算也有帮助。执行此操作时,您将立即看到无法将其重写为x << 1。不是因为结果会有所不同,而是因为可维护性会受到影响。当您编写类似x << 1的代码时,下一个程序员不知道这实际意味着什么,它会每分钟增加着名的WTF:
alt text http://www.osnews.com/images/comics/wtfm.jpg
alt text http://www.osnews.com/images/comics/wtfm.jpg
I think your code should look more like this:
int size = CalculateSizeOfThing(length);
private static int CalculateSizeOfThing(int length)
{
const long TotalArraySize = 200L;
const long BytesPerElement = 100L;
return (length * TotalArraySize) / BytesPerElement;
}
Of course the names of these const
values are a wild guess :-)
当然,这些const值的名称是一个疯狂的猜测:-)
#6
2
This sounds like premature optimizations. The plus for just doing length * 2 is that the compiler most certainly optimizes this and it's easier to maintain.
这听起来像是过早的优化。只做长度* 2的优点是编译器肯定会对此进行优化,并且更容易维护。
#7
2
When I see the idiom:
当我看到成语时:
int val = (someval * someConstant) / someOtherConstant;
I think that the code's intent is to do scaling in some manner. It could be manual fixed point code or it could be avoiding problems with integer division. A concrete example:
我认为代码的意图是以某种方式进行扩展。它可以是手动定点代码,也可以避免整数除法的问题。一个具体的例子:
int val = someVal * (4/5); // oops, val = 0 - probably not what was intended
or written to avoid going back and forth to floating point:
或编写以避免来回浮点:
int val = (int)(someVal * .8); // better than 0 - maybe we wanted to round though - who knows?
when I see this idiom:
当我看到这个成语时:
int val = someVal << someConstant;
I briefly wonder if the individual bits in someVal have some deeper meaning that requires the shifting and then I start looking at surrounding context to understand why it was done this way.
我简单地想知道someVal中的各个位是否具有需要移位的更深层含义,然后我开始查看周围的上下文以了解为什么这样做。
The thing to remember is that when you are writing code that has something like this:
要记住的是,当您编写具有以下内容的代码时:
int val = expr;
that there are an infinite number of ways to create expr such that val will always have the same value. It is important to consider what intent you are expressing in expr for those who will follow.
有无数种方法来创建expr,这样val将始终具有相同的值。重要的是要考虑您在expr中表达的意图对于将要跟随的人。
#8
1
With any modern compiler left shift by 1 or multiplying by 2 will generate the same code. It's probably going to be an add instruction adding the number to itself, but it depends on your target.
对于任何现代编译器,左移1或乘以2将生成相同的代码。它可能是一个添加指令,将数字添加到自身,但它取决于您的目标。
On the other hand, doing (x*200)/100 will not be the same as doubling the number since the first multiplication may overflow, so this cannot be optimized safely to doubling the number.
另一方面,由于第一次乘法可能会溢出,因此执行(x * 200)/ 100与将数字加倍是不同的,因此无法安全地优化以使数字加倍。
#9
0
To answer your actual question, there appears to be no behavior differences between those two snippits of code, when length
is a non-negative int
and the code text is within an unchecked
context.
为了回答你的实际问题,当这两个代码snippits之间似乎没有行为差异,当length是非负int并且代码文本在未经检查的上下文中时。
Within a checked
context (int.MaxValue * 200L)
will never overflow because the result easily fits within a long
. (int)((length * 200L) / 100L
will only overflow when length * 2
overflows. Under no circumstances will a shift operator overflow. Therefore, the code snippits behave differently within a checked
context.
在已检查的上下文(int.MaxValue * 200L)中将永远不会溢出,因为结果很容易适合长整数。 (int)((length * 200L)/ 100L只会在length * 2溢出时溢出。在任何情况下,移位运算符都不会溢出。因此,代码snippits在检查的上下文中表现不同。
If length
is negative, then the shift operation will produce incorrect results, while the multiplication will work correctly. Therefore, the two code snippits are different if the length
variable is allowed to be negative.
如果长度为负,则移位操作将产生不正确的结果,而乘法将正常工作。因此,如果允许长度变量为负,则两个代码snippits是不同的。
(Contrary to popular opinion x << 1 is not the same as x * 2. They are only the same if x is an unsigned integer.)
(与流行的观点相反,x << 1与x * 2不同。如果x是无符号整数,它们只是相同。)
#1
26
And here is the 3rd option:
这是第三种选择:
int size = length * 2; // Comment explaining what is 2 or what means this multiplication
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.
这一定是最好的选择。因为它易读且易于理解您想要做什么。至于性能,编译器正在生成相当优化的代码,因此无需担心这么简单的操作。如果您对溢出有任何疑虑,可以使用check block。
EDIT As mentioned by many others just use any meaningful variable instead of 2
here.
编辑正如许多其他人所提到的,只需使用任何有意义的变量而不是2。
#2
37
The idea that <<
is faster than multiplication is reasoning as though the .NET jit compiler is actually a poorly optimized C compiler written in the 1970's. Even if it were true, the difference would be measured in picoseconds at this point in time, even if there were a difference, which there probably is not.
认为< <比乘法更快的想法是因为.net jit编译器实际上是一个在1970年代写的不太优化的c编译器。即使它是真的,这个时间点的差异将以皮秒为单位,即使存在差异,也可能没有。< p>
Write code so that it is easy to read. Let the compiler take care of the pico-optimizations. Optimize your code based on profiling realistic scenarios, not on second guessing what the compiler will generate.
编写代码以便于阅读。让编译器处理微微优化。基于剖析现实场景优化代码,而不是第二次猜测编译器将生成什么。
Furthermore, the shift operators do not have the same semantics as multiplication. For example, consider the following sequence of edits:
此外,移位运算符不具有与乘法相同的语义。例如,请考虑以下编辑顺序:
Original program by Jill:
Jill的原创节目:
int x = y * 2;
Edit by Bob: Silly Jill, I'll make this "faster":
鲍勃编辑:傻吉尔,我会让这个“更快”:
int x = y << 1;
Edit by Larry the Intern: Oh, we have a bug, we're off by one, let me fix that:
由实习生拉里编辑:哦,我们有一个错误,我们一个接一个,让我解决这个问题:
int x = y << 1 + 1;
and Larry has just introduced a new bug. y * 2 + 1 is different than y << 1 + 1; the latter is actually y * 4.
而拉里刚刚推出了一个新的bug。 y * 2 + 1与y << 1 + 1不同;后者实际上是y * 4。
I have seen this bug in real live production code. It is very easy to mentally get into the mindset that "shifting is multiplication" and forget that shifting is lower precedence than adding, whereas multiplication is higher precedence.
我在实际的实时生产代码中看到了这个bug。精神上很容易进入“转移是乘法”的思维模式,忘记转移的优先级低于加法,而乘法则优先级更高。
I have never once seen someone get arithmetic precedence wrong who multiplied by two by writing x * 2. People understand the precedence of + and *. Lots of people forget what the precedence of shifting is. Are the picoseconds you don't actually save worth any number of potential bugs? I say no.
我从来没有见过有人通过写x * 2得到算术优先级错误乘以2。人们理解+和*的优先级。很多人都忘记了转变的优先顺序。您实际上没有节省的皮秒是否值得任何数量的潜在错误?我拒绝。
#3
7
Which is more readable to your average programmer:
这对普通程序员来说更具可读性:
int size = length * 2;
int size = length << 1;
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.
除非它们来自强大的C ++位调整背景,否则我会打赌你的普通程序员会立即知道第一行是什么(它甚至有“2”代表“double”)但是必须停止并暂停第二行线。
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.
事实上,我倾向于评论第二行,解释它的作用,当你可以让代码像第一行那样进行说话时,这似乎是多余的。
#4
5
It's interesting that most of the answers argue that the compiler will optimise a multiply by a power of 2 into a bitshift. It's obvious that none of the responders have actually tried compiling a bitshift versus a multiply to see what the compiler actually produces.
有趣的是,大多数答案都认为编译器会优化乘以2的幂乘以比特移位。很明显,没有一个响应者真的尝试过编译一个bithift而不是一个乘法来看看编译器实际产生了什么。
This is purely an academic exercise; as just about everyone has pointed out, the multiply is easier to read (though quite why the "*200L / 100L" part is in there is anyone's guess - that just serves to obfuscate things). It's also pretty obvious that replacing a multiply with a bitshift in C# isn't going to have any significant performance increase, even in tight loops. If you need that kind of optimisation, you're using the wrong platform and language to start with.
这纯粹是一种学术活动;正如几乎所有人都指出的那样,乘法更容易阅读(尽管为什么“* 200L / 100L”部分存在于任何人的猜测中 - 这只是用来混淆事物)。很明显,即使在紧密的循环中,用C#中的bitshift替换乘法也不会有任何显着的性能提升。如果您需要这种优化,那么您使用的是错误的平台和语言。
Let's see what happens when we compile a simple program with CSC (the C# compiler) included with Visual Studio 2010 with optimisations enabled. Here's the first program:
让我们看看当我们使用Visual Studio 2010附带的CSC(C#编译器)编译一个简单的程序并启用了优化时会发生什么。这是第一个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j *= 2;
}
}
Using ildasm to decompile the resultant executable gives us the following CIL listing:
使用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
Here's the second program:
这是第二个程序:
static void Main(string[] args)
{
int j = 1;
for (int i = 0; i < 100000; ++i)
{
j <<= 1;
}
}
Decompiling this gives us the following CIL listing:
反编译这给我们提供了以下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
Note the difference at line 8. The first version of the program uses a multiply (mul), whilst the second version uses a left-shift (shl).
注意第8行的差异。程序的第一个版本使用乘法(mul),而第二个版本使用左移(shl)。
Quite what the JIT does to it when the code is executed I'm not sure, but the C# compiler itself demonstrably does not optimise multiplies by powers of two into bitshifts.
JIT在执行代码时对它做了什么我不确定,但C#编译器本身可以证明没有优化乘以2的幂乘以位移。
#5
5
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:
200L和100L代表什么?在我看来,你正在使用魔术数字。您应该尝试以尽可能好地描述其意图的方式编写您的程序;使其尽可能可读。对这些值使用命名常量而不是幻数是一种很好的方法。同样在其自己的命名方法中提取计算也有帮助。执行此操作时,您将立即看到无法将其重写为x << 1。不是因为结果会有所不同,而是因为可维护性会受到影响。当您编写类似x << 1的代码时,下一个程序员不知道这实际意味着什么,它会每分钟增加着名的WTF:
alt text http://www.osnews.com/images/comics/wtfm.jpg
alt text http://www.osnews.com/images/comics/wtfm.jpg
I think your code should look more like this:
int size = CalculateSizeOfThing(length);
private static int CalculateSizeOfThing(int length)
{
const long TotalArraySize = 200L;
const long BytesPerElement = 100L;
return (length * TotalArraySize) / BytesPerElement;
}
Of course the names of these const
values are a wild guess :-)
当然,这些const值的名称是一个疯狂的猜测:-)
#6
2
This sounds like premature optimizations. The plus for just doing length * 2 is that the compiler most certainly optimizes this and it's easier to maintain.
这听起来像是过早的优化。只做长度* 2的优点是编译器肯定会对此进行优化,并且更容易维护。
#7
2
When I see the idiom:
当我看到成语时:
int val = (someval * someConstant) / someOtherConstant;
I think that the code's intent is to do scaling in some manner. It could be manual fixed point code or it could be avoiding problems with integer division. A concrete example:
我认为代码的意图是以某种方式进行扩展。它可以是手动定点代码,也可以避免整数除法的问题。一个具体的例子:
int val = someVal * (4/5); // oops, val = 0 - probably not what was intended
or written to avoid going back and forth to floating point:
或编写以避免来回浮点:
int val = (int)(someVal * .8); // better than 0 - maybe we wanted to round though - who knows?
when I see this idiom:
当我看到这个成语时:
int val = someVal << someConstant;
I briefly wonder if the individual bits in someVal have some deeper meaning that requires the shifting and then I start looking at surrounding context to understand why it was done this way.
我简单地想知道someVal中的各个位是否具有需要移位的更深层含义,然后我开始查看周围的上下文以了解为什么这样做。
The thing to remember is that when you are writing code that has something like this:
要记住的是,当您编写具有以下内容的代码时:
int val = expr;
that there are an infinite number of ways to create expr such that val will always have the same value. It is important to consider what intent you are expressing in expr for those who will follow.
有无数种方法来创建expr,这样val将始终具有相同的值。重要的是要考虑您在expr中表达的意图对于将要跟随的人。
#8
1
With any modern compiler left shift by 1 or multiplying by 2 will generate the same code. It's probably going to be an add instruction adding the number to itself, but it depends on your target.
对于任何现代编译器,左移1或乘以2将生成相同的代码。它可能是一个添加指令,将数字添加到自身,但它取决于您的目标。
On the other hand, doing (x*200)/100 will not be the same as doubling the number since the first multiplication may overflow, so this cannot be optimized safely to doubling the number.
另一方面,由于第一次乘法可能会溢出,因此执行(x * 200)/ 100与将数字加倍是不同的,因此无法安全地优化以使数字加倍。
#9
0
To answer your actual question, there appears to be no behavior differences between those two snippits of code, when length
is a non-negative int
and the code text is within an unchecked
context.
为了回答你的实际问题,当这两个代码snippits之间似乎没有行为差异,当length是非负int并且代码文本在未经检查的上下文中时。
Within a checked
context (int.MaxValue * 200L)
will never overflow because the result easily fits within a long
. (int)((length * 200L) / 100L
will only overflow when length * 2
overflows. Under no circumstances will a shift operator overflow. Therefore, the code snippits behave differently within a checked
context.
在已检查的上下文(int.MaxValue * 200L)中将永远不会溢出,因为结果很容易适合长整数。 (int)((length * 200L)/ 100L只会在length * 2溢出时溢出。在任何情况下,移位运算符都不会溢出。因此,代码snippits在检查的上下文中表现不同。
If length
is negative, then the shift operation will produce incorrect results, while the multiplication will work correctly. Therefore, the two code snippits are different if the length
variable is allowed to be negative.
如果长度为负,则移位操作将产生不正确的结果,而乘法将正常工作。因此,如果允许长度变量为负,则两个代码snippits是不同的。
(Contrary to popular opinion x << 1 is not the same as x * 2. They are only the same if x is an unsigned integer.)
(与流行的观点相反,x << 1与x * 2不同。如果x是无符号整数,它们只是相同。)