2015-08-07 14 views
7

Na przykład, o to czy wyrażenie:Dlaczego nie cytować logiki kompilacji lub wyrażenia "||"?

c = f1 == 0 or f1 - f0 > th 

Oto skompilowany kod 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; 

Dlaczego nie wyjście jest?

__pyx_v_c = (__pyx_v_f1 == 0) || ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th) 

to wersja goto szybsza niż ||?

+0

Wygląda jak 'goto' jest częścią zwarciowego' or'. – hpaulj

Odpowiedz

5

stosując następujące dwa pliki:

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

miałem przypisać f0, f1 i th do czegoś tak, że kompilator nie tylko return 1 zgodnie ze specyfikacją C stwierdza, że ​​int S są inicjowane 0 i f1 == 0 dałoby true, a tym samym cały logiczna stwierdzenie dałoby true i zespół może być:

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

Kompilacja pomocą GCC z -S -O2 flagi (włączone optymalizacja), zarówno test.s i test2.s się :

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 

Więc to chyba wyłączyć optymalizacje, w którym jeden z goto miałby o 50% więcej instrukcji, resul t byłby taki sam.

Powód, dla którego kod wyjściowy C jest brzydki, wynika z tego, w jaki sposób interpreter odwiedza węzły w AST. Po odwiedzeniu węzła or, interpreter najpierw ocenia pierwszy parametr, a następnie drugi. Jeśli wyrażenie boolowskie było znacznie bardziej złożone, byłoby znacznie łatwiejsze do przeanalizowania. Wyobraź sobie wywołanie funkcji lambda, która zwraca wartość boolowską (nie jestem pewien, czy Cython ją obsługuje); interpretator musiałby śledzić strukturę:

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

byłoby trudne zadanie, aby zoptymalizować na etapie interpretacji i tym samym Cython nawet nie przeszkadzało.

2

Jeśli moje zrozumienie C jest poprawne (i ostatnio użyłem C wiele lat temu, więc może być zardzewiałe) "||" Operator (OR) w C tylko zwraca wartości logiczne (czyli 0 dla False lub 1 dla True). Jeśli jest to poprawne, to nie chodzi o to, czy goto jest szybsze czy wolniejsze.

The || dałoby inne wyniki niż kod goto.To dlatego, jak „lub” w Pythonie działa, weźmy przykład -

c = a or b 

W powyższym stwierdzeniem pierwszy a s wartość ocenia się, Jeśli jest to prawdą, jak wartość, która wartość jest zwracana z lub wyrażenia (nie jest to wartość true lub 1, ale a s), jeśli wartość jest fałszywa (jak false wartości w Pythonie to 0, pusty ciąg znaków, puste listy, False itd.), wówczas wartość b jest obliczana i zwracana. Uwaga "lub" zwraca ostatnią ocenianą wartość, a nie True (1) lub (0).

To w zasadzie przydatne, gdy chcesz ustawić domyślne wartości jak -

s = d or 'default value' 
+0

Tak, myślę, że to jest powód, zapomniałem, co lub operator robi w Pythonie. Kod wyjściowy przez Cython może wykonać styl Pythona lub działanie bez spowolnienia. – HYRY

Powiązane problemy