C#/ XNA – 乘法比分区更快?

我最近看到一条推文让我很困惑(这是由XNA编码器在编写XNA游戏时发布的):

当天的微优化提示:在可能的情况下,在高频区域使用乘法而不是除法。 它的速度提高了几个周期。

我很惊讶,因为我一直认为编译器非常聪明(例如,使用位移),最近读了Shawn Hargreaves的一篇文章说了很多相同的事情 。 我想知道这有多少真相,因为我的游戏中有很多计算。

我询问,希望有一个样本,但原始的海报无法给出一个。 然而,他这样说:

不一定是“center = width / 2”之类的东西。 我已经确定“是的,这是值得的”。 🙂

所以,我很好奇……

任何人都可以给出一些代码示例,您可以将分区更改为乘法并获得性能增益,而C#编译器本身无法执行相同的操作。

大多数编译器在你给他们机会时可以做出合理的优化工作。 例如,如果你除以一个常数 ,那么编译器可以/将优化它的可能性非常大,所以它可以像你可以合理地替代它一样快地完成。

但是,如果你有两个提前未知的值,并且你需要将一个值除以另一个来得到答案,如果编译器有很多方法可以做很多事情,它会 – 和就此而言,如果编译器有很大的空间来优化它,那么CPU就会这样做,因此编译器不必这么做。

编辑:你最喜欢的东西(这是相当现实的)可能是这样的:

double scale_factor = get_input(); for (i=0; i 

这相对容易转换为:

 scale_factor = 1.0 / scale_factor; for (i=0; i 

对于特定的编译器来说,我无法真正保证这一点。 它基本上是强度降低和循环提升的组合。 当然有优化器知道如何做到这两点,但我所看到的C#编译器表明它可能没有(但我从来没有测试过这样的东西,我做的测试是几个版本回来......)

虽然编译器可以用2的幂来优化除法和乘法,但是其他数字可能很难或不可能优化。 尝试优化除以17,你会明白为什么。 这当然是假设编译器不知道您提前除以17(它是运行时变量,而不是常量)。

有点迟到但没关系。

你的问题的答案是肯定的。

请查看我的文章http://www.codeproject.com/KB/cs/UniqueStringList2.aspx ,它使用的信息基于您问题的第一条评论中提到的文章。

我有一个QuickDivideInfo结构,它存储幻数和给定除数的移位,从而允许使用更快的乘法计算除法和模数。 我为Quick Prime数字列表预先计算(并测试!)QuickDivideInfos。 至少对于x64,QuickDivideInfo上的.Divide方法是内联的,比使用除法运算符快3倍(在i5上); 它适用于除int.MinValue之外的所有分子,并且不能溢出,因为乘法在移位之前存储在64位中。 (我没有尝试过x86,但如果由于某些原因它没有内联,那么Divide方法的整洁性将会丢失,你必须手动内联它)。

因此,如果您可以预先计算,上述内容将适用于所有场景(int.MinValue除外)。 如果您信任生成幻数/移位的代码,那么您可以在运行时处理任何除数。

其他具有非常有限的分子范围的着名小除数可以内联写入,如果它们不需要中间长度则可能更快。

除以2的倍数:我希望编译器处理这个(如你的width / 2)例子,因为它是常量。 如果没有,那么将其更改为宽度>> 1应该没问题

在这个pdf上给出一些数字

http://cs.smith.edu/dftwiki/index.php/CSC231_Pentium_Instructions_and_Flags

奔腾我们得到一些数字,他们并不好:

  • IMUL 10或11
  • FMUL 3 + 1
  • IDIV 46(32位操作数)
  • FDIV 39

我们说的是大的差异