例如,这里有一个 or 表达式:
c = f1 == 0 or f1 - f0 > th
编译后的C代码:
__pyx_t_24 = (__pyx_v_f1 == 0);
if (!__pyx_t_24) {
} else {
__pyx_t_23 = __pyx_t_24;
goto __pyx_L5_bool_binop_done;
}
__pyx_t_24 = ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th);
__pyx_t_23 = __pyx_t_24;
__pyx_L5_bool_binop_done:;
__pyx_v_c = __pyx_t_23;
为什么不输出这个?
__pyx_v_c = (__pyx_v_f1 == 0) || ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th)
goto 版本是否比 ||
更快?
最佳答案
使用以下两个文件:
test.c
:
int main(int argc, char** argv) {
int c, f0, f1, th;
int hold, hold1;
f0 = (int) argv[1];
f1 = (int) argv[2];
th = (int) argv[3];
hold1 = (f0 == 0);
if (!hold1) {
} else {
hold = hold1;
goto done;
}
hold1 = (f1 - f0 > th);
hold = hold1;
done: c = hold;
return c;
}
test2.c
:
int main(int argc, char** argv) {
int c, f0, f1, th;
f0 = (int) argv[1];
f1 = (int) argv[2];
th = (int) argv[3];
c = (f1 == 0) || (f1 - f0 > th);
return c;
}
我必须将 f0
、f1
和 th
分配给某些东西,这样编译器就不会只是返回 1
因为 C 规范指出 int
被初始化为 0
并且 f1 == 0
会产生 true
,因此整个 bool 语句将产生 true
并且程序集将是:
main:
.LFB0:
.cfi_startproc
.L2:
movl $1, %eax
ret
.cfi_endproc
使用带有 -S -O2
标志(启用优化)的 GCC
编译,test.s
和 test2.s
变成:
main:
.LFB0:
.cfi_startproc
movl 8(%rsi), %edx
movq 16(%rsi), %rdi
movl $1, %eax
movq 24(%rsi), %rcx
testl %edx, %edx
je .L2
subl %edx, %edi
xorl %eax, %eax
cmpl %ecx, %edi
setg %al
.L2:
rep
ret
.cfi_endproc
因此除非您禁用优化,其中带有 goto
的指令将多出大约 50% 的指令,否则结果将是相同的。
输出 C
代码难看的原因是解释器访问 AST 中节点的方式。当访问 或
节点时,解释器首先计算第一个参数,然后计算第二个。如果 bool 表达式复杂得多,解析起来就会容易得多。想象一下调用一个返回 bool 值的 lambda 函数(我不确定 Cython 是否支持这个);口译员必须遵循以下结构:
hold = ... evaluate the lambda expression...
if (hold) {
result = hold;
goto done; // short circuit
}
hold = ... evaluate the second boolean expression...
done:
...
在解释阶段进行优化将是一项艰巨的任务,因此 Cython 甚至不会打扰。
关于python - 为什么cython不编译逻辑或者到 `||`表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31868440/