为什么不用cython编译逻辑或`||`表达式?

HYR*_*YRY 7 c python cython

例如,这是一个或表达式:

c  = f1 == 0 or f1 - f0 > th
Run Code Online (Sandbox Code Playgroud)

这是编译的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;
Run Code Online (Sandbox Code Playgroud)

为什么不输出这个?

__pyx_v_c = (__pyx_v_f1 == 0) || ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th)
Run Code Online (Sandbox Code Playgroud)

是goto版本比||

M. *_*haw 5

使用以下两个文件:

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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

我必须分配f0,f1以及th某些东西,以便编译器不会return 1像C规范那样声明ints被初始化0并且f1 == 0会产生true,因此整个布尔语句将产生true并且汇编将是:

main:
.LFB0:
    .cfi_startproc
.L2:
    movl    $1, %eax
    ret
    .cfi_endproc
Run Code Online (Sandbox Code Playgroud)

使用GCC-S -O2标志进行编译(启用优化),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
Run Code Online (Sandbox Code Playgroud)

因此,除非您禁用优化,否则其中的goto指令将具有大约50%的指令,结果将是相同的.

输出C代码丑陋的原因是因为解释器访问AST中的节点的方式.当or被访问的节点,解释器首先计算第一参数,然后第二个.如果布尔表达式要复杂得多,则解析起来会容易得多.想象一下调用一个返回布尔值的lambda函数(我不确定Cython是否支持这个); 口译员必须遵循以下结构:

hold = ... evaluate the lambda expression...
if (hold) {
    result = hold;
    goto done; // short circuit
}
hold = ... evaluate the second boolean expression...
done:
...
Run Code Online (Sandbox Code Playgroud)

在解释阶段进行优化将是一项艰巨的任务,因此Cython甚至都不会打扰.