使用MSVC编译下面的Cython代码时:
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>1.0
。这无论如何会影响运行时性能吗?
答案 0 :(得分: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
,并使用-O2 -march=native
和而不是1}在x86-64上使用GCC 6.3进行编译em>使用-ffast-math
。这是我得到的汇编代码(再次,删除了一堆无关的聊天):
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数组。海湾合作委员会可以对此进行自动审核; MSVC也应该能够,而英特尔的编译器当然可以。我不会尝试在Cython中编写内核,因为您可能无法对其进行充分注释以激活自动向量器;那些const
和restrict
是必不可少的。