![](/img/trans.png)
[英]Division using right shift operator gives TLE while normal division works fine
[英]How to use right shift to avoid operator division
我有一個cpp項目,該項目可以運行,但是性能不佳。
int currentPos = getPos();
int length = getLength();
if (1.0 * currentPos / length < 0.5)
{
// do something
}
else
{
// do something
}
問題是: 1.0 * currentPos / length
花費太多時間。
Google告訴我,部門划分總是花費很多時間,我們可以通過右移來避免這種分裂。
例如, a=a/4
可以替換為b=b>>2
。
我可以理解此示例,但是我不知道如何使用右移來優化我的代碼(如上所述)。
如果不可能,還有其他避免分裂的方法嗎?
編輯
1) if
的條件並不總是0.5
,在(0,1)之間可以是任何有理數。
2)上面的代碼每秒執行10 * 56 * 181 * 56 * 181
次。
避免了分裂。
if (length > 2 * currentPos)
Shift而不是除法是微優化,任何體面的編譯器都將為您自動執行,而不會弄亂您的代碼並使之不可讀。
讓我們誠實一點。 在什至是遠程的現代CPU上,浮點數的除法將被流水線化,所需的時間與大多數其他FPU甚至Integer操作大致相同。
相反,您應該在代碼上使用探查器以查看瓶頸實際發生的確切位置。 在編寫代碼時,除非它位於1,000,000,000,000時間類型的for / loop中,否則根本沒有關系。
如果您的代碼處於這樣的循環中,請告訴我們,因為有一些降低強度,預先計算等方法可以在那些十年來毫無用處的簡單除法hack之外的情況下提供幫助。
更新,因為它確實處於10億個時間循環中。
現在,讓我們從兩個函數GetPos()
和GetLength()
如果您可以以某種方式組織數據以使這些值對於循環的某些部分恆定,則可以完全消除許多內存訪問。 然后,您還可以在循環外部進行2的乘法運算。
接下來,如果您可以組織數據,以便在運行循環之前按長度或位置對其進行排序,則可以對數據進行二進制搜索,並將比較結果最多減少到20個左右(而不是數十億個) (O(log n)與O(n)的冪),然后您的代碼運行得非常快。
如果不可能,但是每個循環中的數據是恆定的,並且“執行某些操作”不會改變條件,那么這將令人尷尬地變為並行狀態,並且可能能夠跨多個CPU進行線程處理-這聽起來並不那么容易謹防。
這只是一個開始,但我想讓您看到更多信息可以為您提供更好的解決方案。
有一種方法可以對常數進行快速除法,但是只有在知道編譯時的值時,這種方法才有效。 通用算法在Hacker's Delight一書中進行了描述。 互聯網上也有很多例子。 但是,您的情況有所不同。 您從函數中檢索長度
的getLength();
但是,如果長度不是常數,但對於多次計算仍為相同的數字,則可以通過計算倒數並與之相乘來提高性能。
它與以下事實有關:乘法本身是通過二進制移位和加法來完成的-遠遠少於除法。 不過,這可能會有些棘手,因為我假設代碼片段來自某個函數內部,因此您可能希望擁有一個全局變量(或至少在函數外部,即類成員)。
注意:要將整數除以2,只需移位1 ...(4 >> 1)==2。(和4 >> 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會更快。 我錯了。
即使您的問題看起來有所不同,我也要提到這一點,因為嘗試這是一個非常簡單的測試……幾秒鍾的編輯,然后進行編譯和運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.