以下哪种技术是将整数除以2的最佳选项,为什么?
技术1:
x = x >> 1;
技巧2:
x = x / 2;
这里的x
是一个整数。
以下哪种技术是将整数除以2的最佳选项,为什么?
技术1:
x = x >> 1;
技巧2:
x = x / 2;
这里的x
是一个整数。
我在这里分享一些关于编程竞赛的技巧。通常情况下,竞赛使用非常大的输入数据,其中会多次进行除以2的操作,且已知输入为正数或负数。
对于x/2和x>>1这两种操作,x>>1的效率更高。我在ideone.com上运行了一个程序,在该程序中进行了超过10^10次的除以2操作。结果表明,x/2用了近5.5秒的时间,而x>>1只用了近2.6秒。
x/2
优化为 x>>1
。对于有符号值,几乎所有实现都定义了 x>>1
的含义等同于 x/2
,但当 x
为正数时可以更快地计算,并且在 x
为负数时与 x/2
有用的不同。 - supercat我认为有几件事需要考虑:
按位移动应该更快,因为没有真正需要特殊计算来移动位,但是正如指出的那样,负数可能会存在问题。如果保证输入的是正数,并且想要速度更快,那么我建议使用位移操作。
除法运算符非常容易被人类阅读理解。因此,如果您正在寻求代码可读性,则可以使用这个。请注意,编译器优化领域已经发展了很长一段时间,因此使代码易于阅读和理解是良好的实践。
根据底层硬件的不同,操作执行速度可能会有所不同。Amdal定律是让常见情况变得更快。因此,您可能拥有可以比其他操作更快执行的硬件。例如,乘以0.5可能比除以2更快。(当然,如果您希望强制执行整数除法,则可能需要取乘法的向下取整)。
如果您追求纯粹的性能,我建议创建一些测试,可以进行数百万次以上的操作。对执行进行多次采样(样本大小),以确定在您的操作系统/硬件/编译器/代码中哪一个在统计上最好。
>>
相匹配且不匹配 /
,那么我也建议使用位移运算符。 - supercat就CPU而言,位移操作比除法操作快。
然而,编译器知道这一点并会尽可能地进行优化,
因此您可以按照最有意义的方式编写代码,并放心地知道您的代码正在高效运行。
但请记住,对于先前指出的原因,unsigned int
在某些情况下可以被更好地优化而不是int
。
如果您不需要有符号算术运算,则不要包含符号位。
使用 x = x / 2;
或 x /= 2;
,因为有可能会有新的程序员在未来处理这段代码。这样他就可以更容易地找出代码行中发生了什么。并非所有人都知道此类优化。
x = x / 2; 是适合使用的代码。但具体操作取决于你的程序以及你想要生成的输出。
让你的意图更明确...例如,如果您想进行除法运算,请使用 x / 2,并让编译器将其优化为移位运算符(或其他任何操作)。
今天的处理器不会让这些优化对程序性能产生任何影响。
x /= 2
转换为 x >>= 1
,但在这种情况下,除法符号的存在会比使用移位操作更加引人注目。x >>= 1
,以保持清晰明了的目的。x /= 2
来使你的代码更加易读。比需要无谓地证明你知道移位操作更高效而导致下一个查看你代码的程序员需要费10秒钟才能明白你的移位操作要好得多。x *=0.5
的好方法。模2,测试等于1。不知道在C语言中的语法,但这可能是最快的方法。
q = i >> n; is the same as: q = i / 2**n;
(x+128)>>8
对于不接近最大值的x
值所计算出的数值,怎样才能在没有移位的情况下简洁地完成呢?请注意,(x+128)/256
无法达到预期效果。你知道任何适用的表达式吗? - supercat
x
,那么这两种方式都不太合适:应该是x >>= 1
或者x /= 2
,具体取决于你希望表达的操作意义。这并不是因为它更快(现代编译器会将所有等效变体编译为相同、快速的汇编代码),而是因为它更清晰易懂。 - leftaroundaboutx = x >>> 1
。另请注意,根据平台和编译器的不同,手动优化除法和乘法使用移位操作可能是相当合理的。举个例子,微控制器没有直接的ALU支持乘法。 - JimmyBx /= 2
,因为x >>= 1
看起来太像单子绑定(monadic bind)了 ;) - fredoverflowx = x / 2
比写x /= 2
更易读。这可能是主观偏好 :) - JimmyB