修訂後的問題是,是否有任何運行時性能損失寫
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
所以,你可以看到它出來完全相同的兩種方式。 (神祕的數1065353216
是0x3f800000
是1.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中編寫內核,因爲您可能無法充分註釋它來激活自動插件器;那些const
和restrict
是必不可少的。
這似乎並不可能寫出'1.0f'地用Cython。嘗試'( 1 - alpha)'。這將在生成的C代碼中產生'(((float)1) - alpha)'。我不知道MSVC是否會對此提出警告。不管你使用'1'還是'1.0'都可能。 –
zwol
至於運行時性能,它_不應該問題,但如果你想100%確定,你將不得不檢查生成的彙編代碼。 – zwol