2009-06-11 5 views

risposta

31

Sui processori questo veloce, è praticamente impossibile per riorganizzare espressioni booleane fare alcuna differenza reale in termini di velocità. E il compilatore C# è molto intelligente, ottimizzerà anche questo. Ottimizza per leggibilità e chiarezza!

+6

+1. Spesso de-ottimizzo i test booleani nel mio codice, in particolare per la leggibilità. – Cheeso

+0

Compilatori? Inteligente? – Kekoa

+4

Un compilatore non può ottimizzare la logica delle espressioni senza causare valutazioni in momenti diversi. Guarda la risposta di Firoso. Potrebbe essere abbastanza intelligente da sapere quando non è abbastanza intelligente però. – Kekoa

3

Immagino che il compilatore lo farà già. Puoi fare il test e guardare l'IL compilato tramite Reflector.

Ottimizza per la leggibilità e la manutenibilità. Chiedetevi se riuscirete a capire la vostra intelligente ottimizzazione in un anno e se pensate che il codice potrebbe utilizzare alcuni commenti, il rende il codice auto-documentante.

2

Prendere in considerazione la leggibilità e la manutenzione. Se si dispone di un insieme piuttosto complesso di espressioni booleane che sono difficili da leggere, theorm di DeMorgan potrebbe essere una grande approccio per ridurre l'espressione di qualcosa di più facile da leggere/mantenere, ma che è ancora valido/coerente con l'expressiom originale.

Se invece un'espressione più dettagliata è molto più facile da leggere e la riduzione dell'espressione, mentre è logicamente equivoca, rende più difficile la comprensione, lasciandola così com'è.

8

Il vostro primo obiettivo dovrebbe essere quello di ottimizzare tali dichiarazioni per la comprensione degli sviluppatori e la facilità di manutenzione. Teorema

di DeMorgan può essere uno strumento utile per questo.

7

L'ottimizzazione del JIT, nella sua forma attuale, non (da quello che ho letto) ottimizzare questo per voi. Se è necessario ottimizzarlo, è necessario tenerne conto.

Detto, questo è abbastanza piccolo micro-ottimizzazione. In generale, preferirei scrivere le tue "espressioni booleane non banali" in una forma più espressiva per renderle più facili da capire. Per me, questo è più prezioso di qualsiasi ottimizzazione molto piccola ottenuta dall'applicazione del teorema di DeMorgan.

2

In quasi tutti i casi pratici mi vengono in mente, la disposizione degli operatori booleani non ha alcun effetto evidente sulle prestazioni complessive. Se il tuo programma attende il database, la rete ecc. Passerà molto più tempo che in quelle piccole operazioni. Se scrivi un programma in cui fa davvero la differenza, meglio saltare C# e usare invece C++.

+2

l'esempio del contatore è 'fnThatHitsDB && flagVar' C# visualizzerà il db prima che controlli la variabile locale. – BCS

1

Sono d'accordo con le affermazioni generali che leggibilità e la manutenibilità sono più importanti quando si tratta di ottimizzare le espressioni booleane in questi giorni. Pertanto, il teorema di DeMorgan è generalmente molto utile.

C'è una sola eccezione a questa regola. Se l'espressione booleana cambia l'espressione ottimizzata dal teorema di Demorgan, potrebbe essere più difficile da mantenere. Considera un'espressione con diversi input che è stata ottimizzata per mostrare solo alcune condizioni booleane. Una modifica alla logica booleana necessaria potrebbe costringere qualcuno a elencare nuovamente tutte le possibili combinazioni booleane e quindi a risterilizzare. Se l'espressione fosse stata lasciata in un formato non ottimizzato, una modifica avrebbe richiesto meno passaggi per completarla.

Più da una prospettiva aneddotica, mi chiedo se l'istruzione di un team sul Teorema di DeMorgan e le mappe di Karnaugh, ecc. Ridurrebbe le espressioni boolearie inutili/inefficienti. Forse se qualcuno ha una buona comprensione di questi metodi, tenderà a produrre espressioni migliori. Ad esempio, recentemente ho sono imbattuto in questa espressione booleana nel codice del software Io sostengo:

if ({boolean variable} != true && false) 
+1

Chiunque abbia scritto non è ancora pronto per de Morgan e Karnaugh. Prendiamo le stupidaggini di base e poi scriviamo per la leggibilità. –

+0

Yikes! Suppongo che "&& false" possa essere una logica di debug inversa ('temporaneamente' assicurando che il blocco if non sia eseguito), ma è sorprendente la frequenza con cui vi imbattete in cruft come questo. –

7

Credo che la risposta corretta a questa domanda è che il compilatore non (normalmente) ottimizzare valutazioni booleane, semplicemente a causa per logica corto circuito, per esempio:

if (GetFlagA() || GetFlagB()) 
{ 
    ...do something 
} 

L'ordine di che se la valutazione può davvero importa se chiamando GetFlagA modifica qualcosa che GetFlagB si basa su (concesso questo è pratica di codice davvero male, ma questo è un argomento diverso per un diverso thread.) Il problema qui è logico cortocircuito, se GetFlagA viene eseguito e restituisce true, Get FlagB non funzionerà mai, come visto qui il risultato di GetFlagB è irrilevante per la valutazione della dichiarazione.

A | B | =

F | F | F

F | T | T

T | F | T true indipendentemente dal valore di ritorno di B.

T | T | T true indipendentemente dal valore di ritorno di B.

Quindi, in sintesi, chiedere se è possibile ottimizzare utilizzando Demorgan o qualsiasi altra cosa è proprio come il resto dell'informatica e dell'ingegneria del software. "Dipende." se stai usando la valutazione non funzionale, probabilmente può essere ottimizzato. Onestamente, se stai parlando di alcune operazioni su una piattaforma follemente veloce, ti conviene passare il tempo a scrivere documentazione.

Spero che questo aiuti.

+1

Demorgan's non dovrebbe modificare l'esecuzione. Perché la logica si capovolge. ! (! A &&! B) esegue ancora solo B se A è falso. –

+0

@BenjaminAutin Mi stavo chiedendo. Il comportamento che hai descritto è tipico della maggior parte delle lingue che implementano il cortocircuito o univoco in C#? –

+0

Dovrebbe essere, una volta impostato il risultato finale, perché fare altro lavoro del necessario? –

3

L'unica volta che si dovrebbe fare riorganizzare, algebra booleana o demorgan è quando la logica è troppo complessa per farlo in un altro modo. Se non è troppo complesso, tienilo leggibile. C'è un caso per semplificare la logica.

A volte quando la logica è complessa, ho bisogno di creare un Karnaugh Map per semplificare la logica fino a qualcosa che posso persino annotare. Spesso usare K-Maps può aiutarti a trovare modi più concisi per esprimere la tua logica. Il risultato può o non può avere senso, ma sarà equivalente.

E direi anche che lo stesso DeMorgan non è un'ottimizzazione che farà la differenza, se più della metà dei termini è negativo (NON), nel migliore dei casi si otterrà la rimozione di alcuni NOT, che è una singola istruzione per una CPU per NOT. Nel peggiore dei casi, puoi aggiungere tutti i NOT che togli, e se non dovessi usare DeMorgan otterrai più NOT rispetto a prima.

Se si intende ottimizzare la logica, utilizzare qualche algebra booleana o il mio preferito personale K-Maps per ridurre il numero di termini (se possibile). Non limitarti a muovere gli operatori booleani, è sciocco.

0

Primo accordo con la manutenibilità e high-level optimization.

Affrontare quindi l'ottimizzazione a basso livello.

2

DeMorgan di per sé può essere totalmente irrilevante in presenza di una valutazione di cortocircuito.

return !(exp1 || exp2); 
return !exp1 && !exp2; 

guida compilato

if( exp1) return !(true); else return !(exp2); 
if(!(!exp1)) return false; else return !(exp2); 

con i not s annullati e costanti piegati, essi sono identici.

Il caso più importante è l'ordine di valutazione; metti a punto cose che potrebbero innescare cortocircuiti nella parte anteriore delle espressioni. Il compilatore non può ottimizzare questo per voi, perché è difficile per poter rilevare i problemi semantici come gli effetti collaterali o se l'espressione successiva effettuare assunzioni sulla base di quelli precedenti:

return validState() && checkAssumuingValidState(); 
0

per tutti noi non-CS majors:

wikipedia on De Morgan's laws:

leggi di De Morgan sono regole relative gli operatori logici "e" e "o" in termini di tra loro attraverso la negazione, vale a dire:

NOT (P o Q) = (NOT P) e (NON Q)
NOT (P e Q) = (NON P) OR (NOT Q) la legge di

0

De Morgan è utile per ridurre a una forma normale, ad es Forma normale disgiuntiva (DNF) o forma normale congiuntiva (CNF). In pratica questo significa che è sia

DNF: (a, b, c) OR (e ed f, g) ...

o

CNF: (a o b o c) E (eof o g) ....

È possibile lanciare i NON al livello più basso.

Sono d'accordo con i poster precedenti che dovresti ottimizzare per leggibilità e comprensione.

1

L'ottimizzatore C# non può davvero fare troppo dato le regole di cortocircuito per la valutazione di espressioni logiche. Quindi applicare la legge di DeMorgan non farà molto a meno che non ti permetta di vedere altri utili refactoring (e ovviamente può aiutarti a rendere più chiaro il tuo codice).

Ma ci sono casi in cui è possibile apportare miglioramenti sostanziali delle prestazioni con altri tipi di ottimizzazione delle espressioni. Ad esempio queste condizioni devono essere scambiati

if (costly_boolean_function() && cheap_often_false_boolean_function()) 

ottimizzatori di query SQL fare questo come una cosa ovvia, poiché SQL non ha corto circuito. Un ottimizzatore di query riorganizzerà in modo aggressivo i predicati di clausole WHERE congiuntivi (del modulo c1 AND c2 AND ... cn) per mettere le condizioni meno costose prima, poiché potrebbero valutare false e ovviare alla necessità di valutare quelle più costose.

3

Dal valutazione espressioni booleane utilizza la semantica di scelta rapida, è possibile spostare sottoespressioni che sono più convenienti per il calcolo al fronte:

if (CountAllFilesOnDrive('C:\') > 7 && useFileScan) { ... } 

verrà eseguito in qualsiasi momento chiamata costoso l'expresison è ewvaluated, anche se non è necessario . Voltandosi questa affermazione ignora il controllo del file se useFileScan è falso:

if (useFileScan && CountAllFilesOnDrive('C:\') > 7) { ... } 

DeMorgan potrebbe aiutare a spostare "uscite anticipate" per la parte anteriore, e quindi ottenere una migliore performance media.

Si noti che a causa della garanzia della valutazione da sinistra a destra, l'ottimizzatore non ha molta libertà di modificare l'espressione.

Problemi correlati