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

问题描述 投票:9回答:5

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

Microoptimization tip of the day: when possible, use multiplication instead of division in high frequency areas. It's a few cycles faster.

我很惊讶,因为我一直认为编译器非常聪明(例如,使用位移),最近读了一个post by Shawn Hargreaves saying much the same thing。我想知道这有多少真相,因为我的游戏中有很多计算。

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

Not necessarily when it's something like "center = width / 2". And I've already determined "yes, it's worth it". :)

所以,我很好奇......

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

c# optimization xna compiler-optimization
5个回答
7
投票

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

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

编辑:对于类似的东西(这是相当现实的)最好的选择可能是这样的:

double scale_factor = get_input();

for (i=0; i<values.size(); i++)
    values[i] /= scale_factor;

这相对容易转换为:

scale_factor = 1.0 / scale_factor;

for (i=0; i<values.size(); i++)
    values[i] *= scale_factor;

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


4
投票

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


3
投票

有点迟到但没关系。

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

看看我的文章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应该没问题


-1
投票

在这个pdf上给出一些数字

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

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

  • 最底部的10或11
  • FMUL 3 + 1
  • IDIV 46(32位操作数)
  • FDIV 39

我们说的是大的差异


-1
投票
 while(start<=end)
    {
    int mid=(start+end)/2;
    if(mid*mid==A)
    return mid;
    if(mid*mid<A)
    {
    start=mid+1;
    ans=mid;
    }

如果我这样做,结果是2147483647的平方根超过了时间限制

But if i am doing the following way then the thing is clear that for Division compiler responds faster than for multiplication.

while(start<=end)
    {
    int mid=(start+end)/2;
    if(mid==A/mid)
    return mid;
    if(mid<A/mid)
    {
    start=mid+1;
    ans=mid;
    }
    else
    end=mid-1;
    }
© www.soinside.com 2019 - 2024. All rights reserved.