2017-03-11 35 views
2

當編譯下面用Cython代碼MSVC:在Cython代碼中使用float literals而不是double?

cpdef float interpolate(float start, float end, float alpha): 
    return end * alpha + start * (1.0 - alpha) 

我得到這樣的警告:

warning C4244: '=': conversion from 'double' to 'float', possible loss of data 

它涉及到在代碼中1.0,這應該是浮動的,但它的兩倍。上面的Cython代碼可以修改以防止警告出現嗎?

編輯:剛剛發現我可以將此文字轉換爲float:<float>1.0。無論如何,這會影響運行時性能嗎?

+0

這似乎並不可能寫出'1.0f'地用Cython。嘗試'( 1 - alpha)'。這將在生成的C代碼中產生'(((float)1) - alpha)'。我不知道MSVC是否會對此提出警告。不管你使用'1'還是'1.0'都可能。 – zwol

+0

至於運行時性能,它_不應該問題,但如果你想100%確定,你將不得不檢查生成的彙編代碼。 – zwol

回答

3

修訂後的問題是,是否有任何運行時性能損失寫

cpdef float interpolate_cast(float start, float end, float alpha): 
    return end * alpha + start * (<float>1.0 - alpha) 

代替

cpdef float interpolate_lit(float start, float end, float alpha): 
    return end * alpha + start * (1.0f - alpha) 

(如果你能寫,你不能)。

在一般的中,對這類問題的回答是「當然不是,編譯器會以任何方式生成完全相同的機器代碼(確保你確實打開了優化器)」;但對於浮點而言並非總是如此,因爲對於如何優化浮點有一些不明顯的限制。這是在這種情況下,一個相當安全的賭注,因爲1.0處於float精確表示的,但讓我告訴你如何找到肯定。

剝出的CPython集成膠的一個巨大的體積後,這是用Cython生成用於上述第一功能的代碼:

float interpolate_cast(float start, float end, float alpha) { 
    float r; 

    r = ((end * alpha) + (start * (((float)1.0) - alpha))); 
    goto L0; 
    L0:; 
    return r; 
} 

我手動創建與(float)1.0此功能的第二拷貝改變爲1.0f,和編譯時同時與x86-64的GCC 6.3,不使用使用-ffast-math-O2 -march=native。這是彙編代碼我(再次,一堆不相干的嘮叨已被刪除):

interpolate_cast: 
     vmovss .LC0(%rip), %xmm3 
     vsubss %xmm2, %xmm3, %xmm3 
     vmulss %xmm0, %xmm3, %xmm0 
     vfmadd231ss  %xmm2, %xmm1, %xmm0 
     ret 

interpolate_lit: 
     vmovss .LC0(%rip), %xmm3 
     vsubss %xmm2, %xmm3, %xmm3 
     vmulss %xmm0, %xmm3, %xmm0 
     vfmadd231ss  %xmm2, %xmm1, %xmm0 
     ret 

.LC0: 
     .long 1065353216 

所以,你可以看到它出來完全相同的兩種方式。 (神祕的數10653532160x3f8000001.0f。)你可以重複這個實驗MSVC找出如果編譯器做同樣的事情;我期望它。

如果這個函數是真正的關鍵性能,你應該考慮的問題得到它量化。比如,你可以寫該C計算內核:

#include <stddef.h> 
void interpolate_many(float *restrict dest, 
         float const *restrict start, 
         float const *restrict end, 
         float const *restrict alpha, 
         size_t n) 
{ 
    for (size_t i = 0; i < n; i++) 
    dest[i] = end[i] * alpha[i] + start[i] * (1.0f - alpha[i]); 
} 

,並把它周圍的用Cython包裝,採取適當類型的NumPy的陣列。海灣合作委員會可以autovectorize這; MSVC應該也可以,而英特爾的編譯器當然可以。我不會嘗試在Cython中編寫內核,因爲您可能無法充分註釋它來激活自動插件器;那些constrestrict是必不可少的。

相關問題