2010-02-02 17 views
5

Hay Dear!If statement in C++

so che se l'istruzione è una dichiarazione costosa in C++. Ricordo che una volta il mio insegnante disse che se l'affermazione è una dichiarazione costosa nel senso del tempo del computer.

Ora possiamo fare tutto usando l'istruzione if in C++ quindi questa è un'affermazione molto potente in prospettiva di programmazione, ma è costosa in prospettiva temporale del computer.

Sono un principiante e sto studiando il corso di struttura dati dopo l'introduzione al corso C++. la mia domanda a voi è
È meglio per me usare se la dichiarazione estensivamente?

+1

Stai dicendo uso un'istruzione if al posto di un'istruzione if? Che cosa stai suggerendo di usare invece? –

+1

se l'istruzione è più estesa di + - * /, ma è molto più economica del ciclo! quindi usali quando ne hai bisogno :) – Tommy

+0

come può 'se' essere costoso il suo test seguito dal salto nel caso in cui solo il blocco è limitato. Ecco perché inserire sempre il codice subito dopo per il quale il test è vero la maggior parte delle volte. Una moltiplicazione è più costosa. Quindi chi ti ha mai detto "se" è una dichiarazione costosa probabilmente non è la velocità di manutenzione. – affan

risposta

13

Non sono sicuro di come si possa generalizzare che l'istruzione if è costosa.

Se hai

if (true) { ... } 

allora questo il if sarà più likele essere ottimizzato via dal compilatore.

Se, d'altra parte, si ha ..

if (veryConvolutedMethodTogGetAnswer()) { .. } 

e il metodo veryConvolutedMethodTogGetAnswer() fa un sacco di lavoro, allora, si potrebbe sostenere tha questo è un costoso if, ma non a causa del caso, ma a causa del lavoro che stai facendo nel processo decisionale.

"se" di per sé non sono solitamente "costosi" in termini di cicli di clock.

5

Direi un sacco diif statement è costoso dal punto di vista della manutenibilità.

1

Dovresti scrivere il tuo codice per essere corretto, facile da capire e di facile manutenzione. Se questo significa usare le dichiarazioni if, usale! Trovo difficile credere che qualcuno ti abbia suggerito di non utilizzare l'istruzione if.

Forse il tuo istruttore ha fatto sì che si dovrebbe evitare qualcosa di simile:

if (i == 0) { 
    ... 
} else if (i == 1) { 
    ... 
} else if (i == 2) { 
    ... 
} ... 

In questo caso, potrebbe essere più logico ripensare la struttura dei dati e/o algoritmo, o per lo meno, utilizzare switch/case :

switch (i) { 
    case 1: ...; break; 
    case 2: ...; break; 
    ...; 
    default: ...; break; 
} 

Ma anche allora, quanto sopra è meglio più a causa di una migliore leggibilità, piuttosto che l'efficienza. Se hai davvero bisogno di efficienza, cose come eliminare le condizioni di if sono probabilmente un brutto modo di iniziare. Dovresti invece profilare il tuo codice e scoprire dove si trova il collo di bottiglia.

Risposta breve: utilizzare if se e solo se ha senso!

0

In termini di tempo del computer la dichiarazione "se" è di per sé una delle affermazioni più economiche che ci siano.

Basta non mettere venti di loro in fila quando c'è un modo migliore come un interruttore o un tavolo hash, e andrà bene.

+0

Trovo questo dubbio. C'è/è/un costo per un ramo condizionale, e supera (per esempio) l'aritmetica di base intera. –

+0

Sì, l'aritmetica dei numeri interi di base è più veloce a 0.2 ns per un tipico processore al giorno d'oggi, ma "se" è quasi altrettanto veloce - in genere 0,5 ns in media, e la maggior parte delle operazioni come le chiamate di metodo scorrono tra centinaia di nanosecondi. Sostengo la mia affermazione secondo cui "se" è ** una delle ** dichiarazioni meno costose che ci siano. – RobC

17

Se le istruzioni sono compilate in un conditional branch. Ciò significa che il processore deve saltare (o meno) a un'altra riga di codice, a seconda di una condizione. In un processore semplice, questo può causare un pipeline stall, che in termini "non comuni" significa che il processore deve buttar via il lavoro che ha fatto in anticipo, il che fa perdere tempo alla catena di montaggio. Tuttavia, i processori moderni usano branch prediction per evitare bancarelle, quindi se le dichiarazioni diventano meno costose.

In sintesi, sì, possono essere costosi. No, di solito non dovresti preoccupartene. Ma Mykola mostra un punto separato (sebbene altrettanto valido). Polymorphic code è spesso preferibile (per manutenzione) per se di caso o dichiarazioni

+0

Totalmente d'accordo. Polymorphism rocks :) – ScaryAardvark

+0

Matthew solo per chiarimenti se il salto è reso molto vicino alle attuali istruzioni di esecuzione che dovrebbero essere presenti anche nella cache. lo farò se ancora costoso. La maggior parte di se passi a poche istruzioni.E in secondo luogo una chiamata di funzione potrebbe comportare un tempo maggiore di un'istruzione if in quanto una chiamata di funzione richiede il salvataggio del parametro di passaggio dello stack e il salto in un'altra posizione potrebbe essere molto lontano. – affan

+0

Se stai saltando su una linea vicina, potrebbe essere nella cache delle istruzioni. Ma se il processore prevede un errore, potrebbe comunque esserci uno stallo della pipeline. E la logica di predizione del ramo stesso è parte del vero costo. Anche una chiamata di funzione è costosa. –

0

È possibile utilizzare Switch al posto che rende il più leggibile, ma non mi se è più veloce. Se avete qualcosa di simile:

if (condition1) { 
    // do something 
} else if (condition2) { 
    // do something 
} else if (condition3) { 
    // do something 
} else if (condition4) { 
    // do something 
} 

Non sono che cosa si può fare per accelerarlo. se condition4 si verifica più frequentemente, è possibile spostarlo all'inizio.

7

L'ottimizzazione prematura è una cattiva idea. Utilizzare se dichiarazioni in cui hanno senso. Quando scopri una parte del tuo codice in cui è necessario migliorare le sue prestazioni, allora forse lavorerai sulla rimozione di istruzioni da quella parte del tuo codice.

Se le istruzioni possono essere costose perché costringono il compilatore a generare istruzioni di diramazione. Se riesci a capire un modo per codificare la stessa logica in modo tale che il compilatore non debba ramificarsi, il codice sarà probabilmente molto più veloce, anche se ci sono più istruzioni totali. Ricordo di essere stato incredibilmente sorpreso di come la ricodifica di un breve frammento di codice per l'utilizzo di varie manipolazioni di bit invece di eseguire qualsiasi ramificazione lo accelerasse di un fattore del 10-20%.

Ma questo non è un motivo per evitarli in generale. È solo una cosa da tenere a mente quando stai provando a strappare l'ultima parte della velocità a una sezione di codice che sai essere critica dal punto di vista delle prestazioni perché hai già eseguito un profiler e vari altri strumenti per dimostrarlo a te stesso.

Un'altra ragione per cui le dichiarazioni possono essere costose è perché possono aumentare la complessità del programma che rende più difficile la lettura e la manutenzione. Mantenere bassa la complessità delle singole funzioni. Non utilizzare troppe istruzioni che creano percorsi di controllo diversi attraverso la tua funzione.

+0

+1 per aver menzionato che l'ottimizzazione prematura è una cattiva idea – chrmue

2

Un'istruzione if implica un ramo condizionale che potrebbe essere un po 'più costoso di un codice che non si dirama.

Come esempio, contare quante volte una condizione è true (ad esempio quanti numeri in un vettore sono maggiore di 10000):

for (std::vector<int>::const_iterator it = v.begin(), end = v.end(); it != end; ++it) { 
    //if (*it > 10000) ++count; 
    count += *it > 10000; 
} 

La versione che semplicemente aggiunge 1 o 0 per il maggio totale corrente essere una piccola quantità più veloce (ho provato con 100 milioni di numeri prima di poter discernere una differenza).

Tuttavia, con MinGW 3.4.5, utilizzando un algoritmo standard dedicato risulta essere notevolmente più veloce:

count = std::count_if(v.begin(), v.end(), std::bind2nd(std::greater<int>(), 10000)); 

Quindi la lezione è che prima di iniziare a ottimizzare prematuramente, utilizzando alcuni trucchi che avete imparato dagli Internet, potresti provare le pratiche raccomandate per la lingua. (E naturalmente assicuratevi per prima cosa che quella parte del programma sia irragionevolmente lenta in primo luogo.)

Un altro punto in cui è spesso possibile evitare di valutare condizioni complesse è l'utilizzo di tabelle di ricerca (una regola pratica: gli algoritmi possono spesso essere eseguiti più rapidamente se si consente loro di utilizzare più memoria). Ad esempio, le vocali AEIOU (conteggio) in una parola-list, dove si può evitare di ramificazione e la valutazione delle condizioni multiple:

unsigned char letters[256] = {0}; 
letters['a'] = letters['e'] = letters['i'] = letters['o'] = letters['u'] = 1; 

for (std::vector<std::string>::const_iterator it = words.begin(), end = words.end(); it != end; ++it) { 
    for (std::string::const_iterator w_it = it->begin(), w_end = it->end(); w_it != w_end; ++w_it) { 
     unsigned char c = *w_it; 
     /*if (c == 'e' || c == 'a' || c == 'i' || c == 'o' || c == 'u') { 
      ++count; 
     }*/ 
     count += letters[c]; 
    } 
} 
0

In un corso strutture dati, le prestazioni di un if dichiarazione non importa. La piccola differenza tra una dichiarazione if e una qualsiasi delle alternative oscure è totalmente sommersa dalla differenza tra le strutture di dati. Ad esempio, nel seguente pseudocodice

FOR EACH i IN container 
    IF i < 100 
    i = 100 
    container.NEXT(i) 
END FOR 

la prestazione è più determinata container.NEXT(i); questo è molto più costoso per le liste collegate, quindi è per gli array contigui. Per gli elenchi collegati questo richiede un accesso extra alla memoria, che a seconda delle cache può richiedere tra 2,5 ns e 250 ns. Il costo dell'istruzione if verrebbe misurato in frazioni di un nanosecondo.

0

Mi sono confrontato con problemi di prestazioni dovuti a molte istruzioni if ​​chiamate all'interno di loop in script batch, così invece ho usato la matematica integer per emulare if statement, e ha migliorato notevolmente le prestazioni.

if [%var1%] gtr [1543] 
     set var=1 
    else 
     set var=0 

equivalente a

set /a var=%var1%/1543 

Ho anche usato espressioni molto più lunga, con molti/e operazioni%, e ancora era preferibile rispetto un'istruzione if.

So che questo non è il C++, ma credo sia lo stesso principio. Quindi, ogni volta che hai bisogno di prestazioni, evita le dichiarazioni condizionali il più possibile.