2017-02-18 67 views
-1

我在寫一個CUDA內核,並且遇到了一些奇怪的行爲,整數除法和常量讓我撓頭。
我會在下面說明會發生什麼:與常量的整數除法

#define X 8 
#define Y 4 
#define K X/Y 
...code.... 
int var = 8; 
...code.... 
printf("K = %d, var = %d, var/K = %d\n", K, var, var/K); 

我使用VAR/K在一個循環終止條件的地方,我會懷疑VAR/K會給值4,但它給值爲1,從而打破了我的內核。下面是print語句的輸出:

K = 2, var = 8, var/K = 1 

當我使用#define改變K至int類型的全局常量:

__device__ const int K=X/Y; 

問題消失,分裂結果給出4,和我的內核正常工作。我已經嘗試將K轉換爲int(這不應該是必須的),並且不會改變任何內容。
我想知道是否有一些限制分割常量或如果我有一個基本的誤解。

+2

預處理器只是文本替換,所以你的定義給出了'8/8/4' var/K'但爲什麼會導致'1'? – deamentiaemundi

+2

這真的與CUDA無關,只是預處理器的怪癖...... – CygnusX1

+0

乘法而不是除法除 –

回答

3

這裏的基本問題與CUDA無關;它會用普通的C/C++編譯器表現出來。

正如評論指出,這兩種不同的方式打造「常量」:

#define K X/Y 

const int K=X/Y; 

不會產生同樣的事情在所有的情況下,因爲你已經發現。第一種方法使用C或C++ 預處理器來遍歷您的代碼,並在X/Y的任何地方進行文字(文本)替換K。所以,當你這樣做:

int var = 8; 
printf("K = %d, var = %d, var/K = %d\n", K, var, var/K); 

var/K毫不誇張地獲取與var/X/Y更換,語言處理開始前表達。由於C和C++會從左到右評估這樣的表達式,因此不會產生您所期望的結果。

第二種方法當然會在語言中創建一個真正的變量,並按您的預期工作。同樣,這對CUDA來說都不是唯一的。

雖然使用預處理宏(即#define)涉及表達式時,它可能無法刪除各式各樣的古怪行爲,常見的建議,就是要始終使用括號身邊有這樣的宏,就像這樣:

#define K (X/Y) 

這通常會強制宏中的文本表達式通過語言處理器以與您的意圖一致的方式進行評估。特別是,它可以防止您在此處產生的不需要的副作用,其中宏的某些部分在宏本身中的表達式被評估之前參與了相鄰的操作。當然,簡單地定義一個全局的const變量就像你已經發現的那樣工作,並且可能是一個更好的選擇。

順便說一句,並在評論中再次提到,我希望var/K正如你在這裏顯示的那樣,在你給出的情況下評估爲0而不是1。然而,你並沒有顯示完整的代碼,所以在這裏可能有其他的東西在工作,不管你有什麼不同的觀點,你所使用的宏的使用如你所示,不會給你預期的結果8/2 = 4。因此,不管它是0還是1,就像你聲稱的那樣,它不會給你預期的結果4.