我有一个可行的cpp项目,但表现不佳。
int currentPos = getPos();
int length = getLength();
if (1.0 * currentPos / length < 0.5)
{
// do something
}
else
{
// do something
}
问题是:1.0 * currentPos / length
需要花费太多时间。
谷歌告诉我,分工总是花费很多时间,我们可以在右移的帮助下避免它。
例如,a=a/4
可以替换为b=b>>2
。
我可以理解这个例子,但我不知道如何使用右移来优化我的代码。
如果不可能,还有其他方法可以避免分裂吗?
的修改
1)if
中的条件并不总是0.5
,它可以是(0,1)之间的任何理性。
2)上面的代码每秒执行10 * 56 * 181 * 56 * 181
次。
答案 0 :(得分:2)
琐碎避免分裂。
if (length > 2 * currentPos)
Shift而不是division是一个微优化,任何体面的编译器都会自动为你执行,而不会弄乱你的代码并使其无法读取。
答案 1 :(得分:1)
让我们诚实一下。在一个甚至是远程现代的CPU上,浮点数的划分将被流水线化,并且花费的时间大致与大多数其他FPU甚至整数运算一样多。
相反,您应该在代码上使用分析器来确切了解瓶颈实际发生的位置。在编写代码时,除非它在/循环中位于1,000,000,000,000时间类型中,否则它根本不重要。
如果您的代码处于这样的循环中,请告诉我们,因为有一些方法可以减少力量,预先计算等等,这些方法可以帮助那些在简单的分裂之外的情况,这对于十年。
事实证明这确实存在于10亿次循环中。
现在,让我们从您的两个函数GetPos()
和GetLength()
开始。如果您可以组织数据,以便为循环的某些部分使这些值保持不变,则可以完全消除内存访问次数。然后,您也可以在循环外进行乘法运算2。
接下来,如果您可以组织数据,使其在循环运行之前按长度或位置排序,那么您可以对数据进行二进制搜索,并将比较结果降低到最大值20左右而不是数十亿(O(log n)与O(n)的幂),然后你的代码变得非常快。
如果不可能,但数据在每个循环中是恒定的并且“做某事”不会改变条件,那么这就变得非常平行并且可能能够跨越许多CPU - 这并不像它那么容易听起来虽然这么小心。
这只是一个开始,但我想让您看到更多信息可以为您提供更好的解决方案。
答案 2 :(得分:0)
有一种方法可以通过常量进行快速划分,但只有在编译时知道值才有效。一般算法在书Hacker's Delight中描述。互联网上也有大量的例子。不过,你的情况有所不同。您从函数中检索长度
的getLength();
但是,如果长度不是常数,但对于多次计算仍然是相同的数字,则可以通过计算倒数和乘以来提高性能。
这与乘法本身是通过二进制移位和加法完成的事实有关 - 远远少于除法。这可能有点棘手,因为我认为代码片段来自一个函数,所以你可能想要一个全局变量(或至少在函数外部,即一个类)会员)。
答案 3 :(得分:0)
注意:要将整数除以2,您只能移动1 ...(4>&gt;&gt; 1)== 2。 (和4>&gt; 2 == 1)
我最近学到了(艰难的方式)完全优化(-O3)并不总能做到你想要的。 (g ++ v5.2.1,ubuntu 64)
在5x10 ^ 9循环中,我手动更改了代码:
if (ZERO == (n & B00) // n-even
{
...even actions
}
else // n-odd
{
...odd actions
}
为:
if (n & B00) // n-odd
{
...odd actions
}
else // n-even
{
...even actions
}
并在该循环中消除了8秒。 (从58到50)
在我尝试这个测试之前,我认为编译器a)可以(并且会)重新安排代码,并且b)明确地测试ZERO会更快。我错了。
我提到这一点,即使你的问题看起来不同,因为它是一个非常简单的测试,可以尝试......几秒钟的编辑,然后是编译和运行。