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
我们说的是大的差异