是否比Java中的乘法和除法更快地移位?.净?

Jam*_* M. 64 .net c# java optimization bit-manipulation

如果您恰好使用2的幂,则左右移位显然比大多数甚至所有CPU上的乘法和除法运算更快.但是,它可能会降低某些读取器和某些算法的代码清晰度.位移对于性能是否真的是必要的,或者我可以期望编译器或VM注意到这种情况并对其进行优化(特别是当2的幂是文字时)?我主要对Java和.NET行为感兴趣,但欢迎深入了解其他语言实现.

Mic*_*urr 89

今天的大多数编译器将做的不仅仅是转换乘法或除以2的幂来转换操作.在优化时,许多编译器可以优化乘法或除以编译时间常数,即使它不是2的幂.通常乘法或除法可以分解为一系列的移位和加法,如果这一系列操作会更快比乘法或除法,编译器将使用它.

对于除以常数,编译器通常可以将操作转换为乘以"幻数"然后移位的乘法.这可以是主要的时钟周期保护程序,因为乘法通常比除法运算快得多.

Henry Warren的书"Hacker's Delight"有关于这个主题的大量信息,在同伴网站上也有很好的介绍:

另请参阅讨论(带有一个或两个链接):

无论如何,所有这些归结为允许编译器处理微优化的繁琐细节.自从你自己的班次超过编译器以来已经有好几年了.

  • 你应该注意,如果x是一个奇数负数,`x/2`和`x >> 1`将计算不同的东西.如果一个人关心计算将对奇数负数做什么,那么应该使用产生正确答案的形式. (5认同)

Jas*_*ton 87

几乎任何有价值的环境都会为您优化这一点.如果没有,你就会有更大的鱼来炸.说真的,不要再浪费一点思考这个.你会知道什么时候出现性能问题.运行探查器后,您将知道导致它的原因,并且应该非常清楚如何修复它.

你永远不会听到有人说"我的应用程序太慢,然后我开始随机更换x * 2,x << 1一切都被修复了!" 性能问题通常通过找到一种方法来减少工作量来解决,而不是通过找到一种方法来快速完成相同的工作.

  • 为"和你运行一个分析器后..."+1 (16认同)
  • 使用哪个更清楚.如果它是乘法或除法中的常数因子,编译器几乎肯定会做正确的事情. (6认同)
  • 非常好的答案 - 过早优化几乎总是浪费时间. (4认同)
  • 如果x可能是奇数负数,则"x >> 1"和"x/2"的行为是不同的.除非两个操作都是正确的(例如因为x永远不会是一个奇数负数,或者其他地方的代码将处理一个逐个条件),否则更快的问题就无关紧要了.我经常看到`x >> 2`时使用的'x/2`是正确的,反之亦然[寻找图形在原点X和Y坐标处有一个难看的接缝的程序]. (4认同)
  • 实际上我正在翻译(并试图理解/清楚)从C到托管代码的音频处理算法,原来充满了N4 = N2 >> 2等.我开始将它们改为乘法和除法,但是想通了值得一问的是我是否会在脚下射击自己. (2认同)

小智 33

在这些情况下,人类是错误的.

99%,当他们试图猜测现代(和所有未来)编译器时.
当他们试图同时猜测现代(和所有未来)JIT时,99.9%.
当他们试图再次猜测现代(和所有未来的)CPU优化时,99.999%.

以准确描述您想要完成的内容的方式编程,而不是如何编写.未来版本的JIT,VM,编译器和CPU都可以独立改进和优化.如果您指定的内容非常小且具体,那么您将失去所有未来优化的好处.

  • ...和83.7%的统计数据组成:-) (51认同)
  • 思考未来的+1 (2认同)

Gre*_*ill 21

几乎可以肯定的是,对于换档操作,可以依赖于二次幂乘法优化.这是编译器构建的学生将学习的第一个优化之一.:)

但是,我认为没有任何保证.您的源代码应该反映您的意图,而不是试图告诉优化器该做什么.如果您的数量较大,请使用乘法.如果您将一个位域从一个位置移动到另一个位置(想想RGB颜色操作),请使用移位操作.无论哪种方式,您的源代码都将反映您实际在做什么.

  • 这种微优化可能有助于*特定的*JIT编译器.但是,您的代码将比运行它的JIT编译器的版本更长,并且无法确定下一版本的JIT编译器将执行哪些优化.甚至有可能你在之前版本中做得更快的东西在下一个版本中表现更差*!这种情况与C之类的语言非常不同,其中编译步骤仅执行一次.编写代码后,JIT编译的字节码语言可以提高性能. (2认同)

izb*_*izb 13

注意,向下移动和除法将(在Java中,当然)给出负数,奇数的不同结果.

int a = -7;
System.out.println("Shift: "+(a >> 1));
System.out.println("Div:   "+(a / 2));
Run Code Online (Sandbox Code Playgroud)

打印:

Shift: -4
Div:   -3
Run Code Online (Sandbox Code Playgroud)

由于Java没有任何无符号数,因此Java编译器实际上不可能对其进行优化.


小智 8

在我测试的计算机上,整数除法比其他操作慢4到10倍.

当编译器可以用2的倍数替换除法并使你看不出差异时,除以2的倍数的除法明显变慢.

例如,我有一个(图形)程序有许多除以255的许多除法.实际上我的计算是:

r = (((top.R - bottom.R) * alpha + (bottom.R * 255)) * 0x8081) >> 23;
Run Code Online (Sandbox Code Playgroud)

我可以确保它比我以前的计算快得多:

r = ((top.R - bottom.R) * alpha + (bottom.R * 255)) / 255;
Run Code Online (Sandbox Code Playgroud)

所以不,编译器不能做所有的优化技巧.


Chr*_*sma 5

我会问"你在做什么才重要?".首先设计代码以提高可读性和可维护性.通过标准乘法进行位移的可能性将使性能差异非常小.