我最近看到一则推文令我感到困惑(这是由XNA编码员在编写XNA游戏时发布的):
我很惊讶,因为我一直认为编译器非常聪明(例如,使用位移),最近读过post by Shawn Hargreaves saying much the same thing。我想知道这有多少真相,因为我的游戏中有很多计算。
我询问,希望有一个样本,但原始的海报无法给出一个。然而,他确实这么说:
所以,我好奇......
任何人都可以提供一些代码示例,您可以将分区更改为乘法并获得性能提升,而C#编译器本身无法做同样的事情。
答案 0 :(得分: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#编译器表明它可能没有(但我从未测试过这样的任何东西,我做的测试是几个版本回来......)
答案 1 :(得分:4)
虽然编译器可以用2的幂来优化除法和乘法,但是其他数字可能很难或不可能优化。尝试优化除以17,你会明白为什么。这当然是假设编译器不知道您提前除以17(它是运行时变量,而不是常量)。
答案 2 :(得分: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中),因为它是常量。如果没有,则将其更改为宽度&gt;&gt; 1应该没问题
答案 3 :(得分:-1)
在这个pdf
上给出一些数字http://cs.smith.edu/dftwiki/index.php/CSC231_Pentium_Instructions_and_Flags
奔腾的我们得到了一些数字,但它们并不好:我们谈论的是巨大的差异
答案 4 :(得分:-1)
while(start<=end)
{
int mid=(start+end)/2;
if(mid*mid==A)
return mid;
if(mid*mid<A)
{
start=mid+1;
ans=mid;
}
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;
}