2015-08-07 10 views
7

Per esempio, qui è una o l'espressione:Perché cython non compila la logica o l'espressione `||`?

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

ecco il codice C compilato:

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

Perché non uscita questo?

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

è la versione goto più veloce di ||?

+0

sembra la goto' è parte 'del corto circuito' o'. – hpaulj

risposta

5

Utilizzando i seguenti due file:

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

ho dovuto assegnare f0, f1 e th a qualcosa in modo che il compilatore non sarebbe solo return 1 come specifica C indica che int s vengono inizializzati a 0 e f1 == 0 produrrebbe true, e quindi l'intera istruzione booleana produrrebbe true e l'assemblea sarebbe:

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

compilazione utilizzando GCC con -S -O2 bandiere (ottimizzazione abilitata), sia test.s e test2.s diventano :

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 

Quindi a meno che non si disattiva le ottimizzazioni, in cui quello con goto avrebbe circa il 50% in più di istruzioni, il Resul sarebbe lo stesso

Il motivo dell'output del codice C è dovuto al modo in cui l'interprete visita i nodi nell'AST. Quando viene visitato un nodo or, l'interprete valuta prima il primo parametro e poi il secondo. Se l'espressione booleana fosse molto più complessa, sarebbe molto più semplice da analizzare. Immagina di chiamare una funzione lambda che restituisce un valore booleano (non sono sicuro che Cython lo supporti); l'interprete avrebbe dovuto seguire la struttura:

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

Sarebbe un compito arduo per ottimizzare durante la fase di interpretazione e quindi Cython non si preoccupano neppure.

2

Se la mia comprensione di C è corretta (e l'ultima volta ho usato C molti anni fa, quindi potrebbe essere arrugginito) il '||' L'operatore (OR) in C restituisce solo valori booleani (ovvero 0 per False o 1 per True). Se questo è corretto, non si tratta di se goto è più veloce o più lento.

Il || darebbe risultati diversi rispetto al codice goto.Questo è a causa di come 'o' in Python funziona, diamo un esempio -

c = a or b 

Nella dichiarazione di cui sopra primo valore a s viene valutato, se si tratta di un vero come valore che valore viene restituito dalla o l'espressione (non vero o 1, ma valore a), se il valore è falso come (valori falsi come in Python sono 0, stringa vuota, liste vuote, False, ecc.) allora il valore di b viene valutato e viene restituito. Si prega di notare 'o' restituisce l'ultimo valore valutato, e non True (1) o False (0).

Questo è fondamentalmente utile quando si desidera impostare valori di default come -

s = d or 'default value' 
+0

Sì, penso che questo sia il motivo, ho dimenticato cosa o l'operatore fa in Python. Il codice di output di Cython può eseguire lo stile o l'operazione Python senza rallentare. – HYRY