2015-08-07 2 views
7

Например, здесь есть или выражение:Почему не цитировать компиляцию логики или выражение `||`?

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) 

- это версия с более быстрой скоростью, чем ||?

+0

Похоже 'goto' является частью короткого замыкания' or'. – hpaulj

ответ

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; 
} 

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 к чему-то, так что компилятор будет не просто return 1, как указано в спецификации C, int s инициализируются 0 и f1 == 0 даст true, и, таким образом, весь логический оператор даст true и сборка будет:

main: 
.LFB0: 
    .cfi_startproc 
.L2: 
    movl $1, %eax 
    ret 
    .cfi_endproc 

Компиляция с использованием 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 

Так что, если вы не отключить оптимизацию, в котором один с goto будет иметь около 50% больше инструкций, то Ресул t будет одинаковым.

Причина, по которой вывод C является уродливым, объясняется тем, как интерпретатор посещает узлы в AST. При посещении узла or интерпретатор сначала оценивает первый параметр, а затем второй. Если бы логическое выражение было намного сложнее, было бы намного легче разобрать. Представьте, что вы вызываете функцию лямбда, которая возвращает логическое значение (я не уверен, поддерживает ли Cython это); интерпретатор должен следовать структуру:

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

Это будет непростой задачей для оптимизации во время интерпретации фазы и, таким образом, Cython даже не заморачиваться.

2

Если мое понимание С верно (и я последний раз использовал C много лет назад, поэтому он может быть ржавым), '||' (OR) в C возвращает только логические значения (то есть 0 для False или 1 для True). Если это правильно, то это не о том, если goto работает быстрее или медленнее.

The || даст разные результаты, чем код goto.Это происходит потому, как «или» в Python работает, давайте рассмотрим пример -

c = a or b 

В приведенном выше заявлении первым a сек значение вычисляется, если это верно, как значение, которое возвращается значение из или выражения (не true или 1, но значение a s), если значение равно false (значения false в Python равны 0, пустая строка, пустые списки, False и т. д.), тогда значение b оценивается и возвращается. Обратите внимание: «или» возвращает последнее оцениваемое значение, а не True (1) или False (0).

В основном это полезно, если вы хотите, чтобы установить значения по умолчанию, как -

s = d or 'default value' 
+0

Да, я думаю, что это причина, я забыл, что или оператор делает в Python. Выходной код Cython может выполнять стиль или операцию python без замедления. – HYRY