C++ 哪个更好的选择用于将整数除以 2?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10681375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Which is better option to use for dividing an integer number by 2?
提问by Abhineet
Which of the following techniques is the best option for dividing an integer by 2 and why?
以下哪种技术是将整数除以 2 的最佳选择,为什么?
Technique 1:
技术1:
x = x >> 1;
Technique 2:
技术2:
x = x / 2;
Here x
is an integer.
这里x
是一个整数。
回答by Mark Byers
Use the operation that best describes what you are trying to do.
使用最能描述您尝试执行的操作的操作。
- If you are treating the number as a sequence of bits, use bitshift.
- If you are treating it as a numerical value, use division.
- 如果您将数字视为位序列,请使用 bitshift。
- 如果您将其视为数值,请使用除法。
Note that they are not exactly equivalent. They can give different results for negative integers. For example:
请注意,它们并不完全等效。对于负整数,它们可以给出不同的结果。例如:
-5 / 2 = -2
-5 >> 1 = -3
回答by Cat Plus Plus
Does the first one look like dividing? No. If you want to divide, use x / 2
. Compiler can optimise it to use bit-shift if possible (it's called strength reduction), which makes it a useless micro-optimisation if you do it on your own.
第一个看起来像分裂吗?不。如果你想分割,请使用x / 2
。如果可能,编译器可以优化它以使用位移(这称为强度降低),如果您自己进行,这将使其成为无用的微优化。
回答by Michael Burr
To pile on: there are so many reasons to favor using x = x / 2;
Here are some:
继续:有很多理由喜欢使用x = x / 2;
这里有一些:
it expresses your intent more clearly (assuming you're not dealing with bit twiddling register bits or something)
the compiler will reduce this to a shift operation anyway
even if the compiler didn't reduce it and chose a slower operation than the shift, the likelihood that this ends up affecting your program's performance in a measurable way is itself vanishingly small (and if it does affect it measurably, then you have an actual reason to use a shift)
if the division is going to be part of a larger expression, you're more likely to get the precedence right if you use the division operator:
x = x / 2 + 5; x = x >> 1 + 5; // not the same as above
signed arithmetic might complicate things even more than the precedence problem mentioned above
to reiterate - the compiler will already do this for you anyway. In fact, it'll convert division by a constant to a series of shifts, adds, and multiplies for all sorts of numbers, not just powers of two. See this questionfor links to even more information about this.
它更清楚地表达了你的意图(假设你没有处理比特摆弄寄存器位或其他东西)
编译器无论如何都会将其简化为移位操作
即使编译器没有减少它并选择比移位更慢的操作,这最终以可测量的方式影响程序性能的可能性本身也很小(如果它确实对它产生了可测量的影响,那么你有一个实际的使用班次的原因)
如果除法将成为更大表达式的一部分,则如果使用除法运算符,则更有可能获得正确的优先级:
x = x / 2 + 5; x = x >> 1 + 5; // not the same as above
有符号算术可能比上面提到的优先级问题更复杂
重申 - 编译器已经会为你做这件事了。事实上,它会将除以常数转换为一系列移位、加法和乘法,而不仅仅是 2 的幂。有关此问题的更多信息,请参阅此问题的链接。
In short, you buy nothing by coding a shift when you really mean to multiply or divide, except maybe an increased possibility of introducing a bug. It's been a lifetime since compilers weren't smart enough to optimize this kind of thing to a shift when appropriate.
简而言之,当您真正想要乘或除时,您不会通过编码转换来购买任何东西,除非可能增加引入错误的可能性。由于编译器不够聪明,无法在适当的时候将这种事情优化为一种转变,这已经是一辈子了。
回答by Luchian Grigore
Which one is the best option and why for dividing the integer number by 2?
哪一个是最好的选择,为什么要将整数除以 2?
Depends on what you mean by best.
取决于你所说的最好是什么意思。
If you want your colleagues to hate you, or to make your code hard to read, I'd definitely go with the first option.
如果你想让你的同事讨厌你,或者让你的代码难以阅读,我肯定会选择第一个选项。
If you want to divide a number by 2, go with the second one.
如果你想把一个数除以 2,就用第二个。
The two are not equivalent, they don't behave the same if the number is negative or inside larger expressions - bitshift has lower precedence than +
or -
, division has higher precedence.
两者不等价,如果数字为负数或在更大的表达式中,它们的行为不相同 - bitshift 的优先级低于+
or -
,除法的优先级更高。
You should write your code to express what its intent is. If performance is your concern, don't worry, the optimizer does a good job at these sort of micro-optimizations.
您应该编写代码来表达其意图。如果您关心性能,请不要担心,优化器在这些微优化方面做得很好。
回答by justin
Just use divide (/
), presuming it is clearer. The compiler will optimize accordingly.
只需使用divide ( /
),假设它更清楚。编译器会相应地进行优化。
回答by jamesdlin
I agree with other answers that you should favor x / 2
because its intent is clearer, and the compiler should optimize it for you.
我同意你应该赞成的其他答案,x / 2
因为它的意图更明确,编译器应该为你优化它。
However, another reason for preferring x / 2
over x >> 1
is that the behavior of >>
is implementation-dependent if x
is a signed int
and is negative.
然而,另一个原因宁愿x / 2
在x >> 1
是的行为>>
是实现相关的,如果x
是签名int
和为负。
From section 6.5.7, bullet 5 of the ISO C99 standard:
来自 ISO C99 标准的第 6.5.7 节第 5 项:
The result of
E1 >> E2
isE1
right-shiftedE2
bit positions. IfE1
has an unsigned type or ifE1
has a signed type and a nonnegative value, the value of the result is the integral part of the quotient ofE1
/ 2E2
. IfE1
has a signed type and a negative value, the resulting value is implementation-defined.
结果
E1 >> E2
是E1
右移的E2
位位置。如果E1
具有无符号类型或E1
具有有符号类型和非负值,则结果的值是E1
/ 2商的整数部分E2
。如果E1
具有有符号类型和负值,则结果值是实现定义的。
回答by Thomas Mueller
x / 2
is clearer, and x >> 1
is not much faster (according to a micro-benchmark, about 30% faster for a Java JVM). As others have noted, for negative numbers the rounding is slightly different, so you have to consider this when you want to process negative numbers. Some compilers may automatically convert x / 2
to x >> 1
if they know the number can not be negative (even thought I could not verify this).
x / 2
更清晰,但并x >> 1
没有快多少(根据微基准测试,Java JVM 的速度大约快 30%)。正如其他人所指出的,对于负数,舍入略有不同,因此当您要处理负数时必须考虑这一点。如果某些编译器知道数字不能为负数x / 2
,x >> 1
则它们可能会自动转换为(甚至认为我无法验证这一点)。
Even x / 2
may not use the (slow) division CPU instruction, because some shortcuts are possible, but it is still slower than x >> 1
.
甚至x / 2
可能不使用(慢)除法 CPU 指令,因为一些快捷方式是可能的,但它仍然比x >> 1
.
(This is a C / C++ question, other programming languages have more operators. For Java there is also the unsigned right shift, x >>> 1
, which is again different. It allows to correctly calculate the mean (average) value of two values, so that (a + b) >>> 1
will return the mean value even for very large values of a
and b
. This is required for example for binary search if the array indices can get very large. There was a bug in many versions of binary search, because they used (a + b) / 2
to calculate the average. This doesn't work correctly. The correct solution is to use (a + b) >>> 1
instead.)
(这是一个 C / C++ 问题,其他编程语言有更多的运算符。对于 Java 也有无符号右移,x >>> 1
,这又是不同的。它允许正确计算两个值的均值(平均值),因此(a + b) >>> 1
将即使对于非常大的a
和值也返回平均值b
。例如,如果数组索引可以变得非常大,则这是二分搜索所必需的。在许多版本的二分搜索中存在一个错误,因为它们用于(a + b) / 2
计算平均值。这不会不能正常工作。正确的解决方案是(a + b) >>> 1
改用。)
回答by Ivan Californias
Knuth said:
克努特说:
Premature optimization is the root of all evil.
过早的优化是万恶之源。
So I suggest to use x /= 2;
所以我建议使用 x /= 2;
This way the code is easy to understand and also I think that the optimization of this operation in that form, don't mean a big difference for the processor.
这样代码很容易理解,而且我认为以这种形式优化这个操作,对处理器来说并不意味着有很大的不同。
回答by Michael Donohue
Take a look at the compiler output to help you decide. I ran this test on x86-64 with
gcc (GCC) 4.2.1 20070719 [FreeBSD]
查看编译器输出以帮助您做出决定。我用
gcc (GCC) 4.2.1 20070719 [FreeBSD]在 x86-64 上运行了这个测试
Also see compiler outputs online at godbolt.
另请参阅godbolt 在线编译器输出。
What you see is the compiler does use a sarl
(arithmetic right-shift) instruction in both cases, so it does recognize the similarity between the two expressions. If you use the divide, the compiler also needs to adjust for negative numbers. To do that it shifts the sign bit down to the lowest order bit, and adds that to the result. This fixes the off-by-one issue when shifting negative numbers, compared to what a divide would do.
Since the divide case does 2 shifts, while the explicit shift case only does one, we can now explain some of the performance differences measured by other answers here.
您看到的是编译器sarl
在两种情况下都使用了(算术右移)指令,因此它确实识别了两个表达式之间的相似性。如果使用除法,编译器还需要针对负数进行调整。为此,它将符号位向下移动到最低位,并将其添加到结果中。与除法相比,这解决了在移动负数时逐一的问题。
由于除法情况进行了 2 次转换,而显式转换情况仅进行了一次,我们现在可以在这里解释其他答案所衡量的一些性能差异。
C code with assembly output:
带有汇编输出的 C 代码:
For divide, your input would be
对于除法,您的输入将是
int div2signed(int a) {
return a / 2;
}
and this compiles to
这编译为
movl %edi, %eax
shrl , %eax
addl %edi, %eax
sarl %eax
ret
similarly for shift
同样的换档
int shr2signed(int a) {
return a >> 1;
}
with output:
带输出:
sarl %edi
movl %edi, %eax
ret
回答by ansiart
Just an added note -
只是一个补充说明 -
x *= 0.5 will often be faster in some VM-based languages -- notably actionscript, as the variable won't have to be checked for divide by 0.
x *= 0.5 在某些基于 VM 的语言中通常会更快——特别是 actionscript,因为不必检查变量是否被 0 除。