2017-10-16 53 views
0

問題就是這麼簡單: 如果將兩個低值與像加法,除法,模數,位移等其他基本操作相結合的速度比具有更大值的相同操作快?據我所知,這將會要求CPU跟蹤最重要的位(我認爲這不太可能),但也許在業務中還有其他的東西。是一個(通用)CPU在計算較低值時比較快嗎?

我特別問,因爲我經常看到相當低的素數(例如31)在一些Java的基本類hashCode()方法的使用(例如StringList),這是令人驚訝的,因爲更大的價值很可能會導致更多的擴散(其通常是散列函數的一個好東西)。

+1

AFAIK處理器不關心某個變量類型中的值,在Java中哈希碼中使用31後面的推理在所提出的方法中得到了很好的解釋。 – fvu

+0

對於除法和模(*實際*除法和模,用一個常數左操作數他們不計數),實際上是的,也許,這取決於。它們是值很重要的*少數*操作中的兩個。 – harold

+1

這不是一個dublicate,因爲我只提供''hashCode()'函數。我之前就知道這篇文章,並且很清楚在那裏指出的某些相關情況。然而,我的實際問題是,CPU是否可以更快地處理低值,在那裏並不令人驚訝,這使我自己的問題合法化。 – Reizo

回答

0

算術

我不認爲有很多流水線處理器(即幾乎所有的除外非常最小的),其中一個簡單的算術指令的成本將與寄存器或存儲器操作數的值更改。這會使管道的設計更加複雜,並且在實踐中可能會適得其反。

我可以想象,一個非常複雜的指令(至少是一個除法)可能需要很多週期而不是管線長度,因爲它可能會引入等待狀態。 Agner Fog寫道,這是真實的「在AMD處理器上,而不是在Intel處理器上。」

如果一個操作無法在一條指令中計算出來,比如大於原始整數寬度的數字相乘,那麼該實現可能包含一個例如「快速路徑」的例子。兩個操作數的上半部分都是零。一個常見的例子是MSVC使用的x86 32位體系結構上的64位乘法。一些較小的處理器不具有劃分指令,有時甚至不用於乘法。用於計算這些操作的程序集可能會較早終止較小的操作數。在較小的體系結構中,這種影響會更敏銳。

立即值編碼

對於立即值(常數),這可能是不同的。例如,RISC處理器允許在加載/加法立即指令中編碼多達16位立即數,並且需要兩個操作來通過load-upper-immediate + add-immediate加載32位字或者必須加載常數來自程序存儲器。

在CISC處理器中,大的立即值可能會佔用更多的內存,這可能會減少每個週期可獲取的指令數量,或者增加緩存未命中數量。

在這種情況下,一個較小的常數可能比一個大的便宜。

我不確定編碼差異是否與Java的問題一樣重要,因爲大多數代碼至少最初都會作爲Java字節碼分發,如果啓用JIT的JVM將代碼轉換爲機器代碼,並且某些庫類可能具有預編譯的實現。我對Java字節碼瞭解不夠,無法確定其大小恆定的後果。從我讀的內容看來,大多數常量通常通過常量池中的索引加載,而不是直接在字節碼流中編碼,所以我不希望這裏有太大的區別。

實力減小優化

對於非常昂貴的操作(相對於處理器)編譯器和程序員通常採用花樣通過更簡單的一個是有效的常數,想在乘法示例替換硬計算上面提到乘法由移位和減法/加法代替。

在給出的例子中(乘以31乘以65,537),我不會期望有差異。對於其他數字將會有所不同,但與數量的大小並不完全相關。常數的分割也通常被一個神祕的乘法和移位序列所取代。

請參閱gcc如何翻譯division by 13

在x86處理器上,一些小常量的乘法操作可以被load-effective-address指令替代,但只能用於某些常量。總而言之,我期望這種效果很大程度上取決於處理器架構和要執行的操作。由於Java應該幾乎在任何地方運行,我認爲庫作者希望他們的代碼在大範圍的處理器上有效,包括小型嵌入式處理器,其中操作數大小將扮演更重要的角色。