# Performance Vergleich von if-Abfragen mit mehreren Bedingungen



## Jagito (14. Okt 2009)

Hallo,

vielleicht kann mir jemand weiterhelfen. 
Welche Modellierung ist schneller? (a,b,c,d sind int-Werte) 


```
if(a> 1 && b>2 && c>2 && d<5) {
tuwas();
}
else {
 if ((a< 1 && b<2 && c<2 && d>5)
 tuwasanderes();
}
```

oder die folgende, wenn ich die Bedingungen in einzelne if-Schleifen zerlege

```
if(a> 1){
      if (b<2) {
         if (c<2){
            if(d>5){
				tuwas();
				}
			else {}
		 else {}		}
	  else {} 		 }
	  }
	else{
		if (b>2) {
          if (c>2){
            if(d<5){
				tuwasanderes();
			}
		  }
		}
	}
```

Ist dahingehend wichtig, da mein Algorithmus ca. 10 E12 mal die if-Schleife durchlaufen wird, und da machen auch kleinere Zeitunterschiede einen Unterschied.


----------



## SlaterB (14. Okt 2009)

die Bedingungen sind übrigens nicht gleich,
bei a == 1 ist im obigen Fall kein Durchkommen, 
im unteren schon

man kann grob annehmen, dass die Verknüpfung irrelevant ist,
allein schon die Vergleiche dürften deutlich mehr Zeit kosten,

im Vergleich aber zu irgendeinem selbst leeren Methodenaufruf sind die if-Verknüpfungen + Vergleiche praktisch kein Faktor mehr,
von einer gefüllten Methode mit gewissen Aktionen ganz zu schweigen,

interessant wäre das also höchstens, wenn tuwas()/  tuwasanderes() praktisch nie drankommt,
und auch dann müsste man wieder drauf achten, dass der Code in einer anderen Methode drinsteht, etwa in einer Schleife,
sonst hätte man einen Methodenaufruf zu diesem Code hin, der wieder mehr kostet als alles andere

auch wo die Variablen her kommen, ob sie final sind oder Klassenattribute mit Vererbung usw.
kann viel mehr Arbeit bereiten, lieber nicht über sowas genauer nachdenken,

was muss man eigentlich 10^12x ausführen?
wenn vorher die Variablen neu belegt werden oder sonst ein Code ausgeführt wird, dann ist das noch etwas, was sicher die 100fache Zeit dauert,

viel tiefer als einfache Kontrollstrukturen oder Zahl-Vergleiche kann man kaum sinken


----------



## Jagito (14. Okt 2009)

Danke für die Antwort SlaterB. 
Die Methoden tuwas()/ tuwasanderes() kommen häufig genug vor. Daher ist meine Frage gelöst  

Es handelt sich um ein Netzwerkflussproblem von ca. 170 Knoten, wobei das Netzwerk symmetrisch ist und jeder Knoten genau zwei Vorgänger und Nachfolgerknoten besitzt. 
Wenn man alle möglichen Kombinationen (unter Berücksichtigung gewisser Nebenbedingungen) betrachtet, erhält man rund 10^12 verschiedene Wege von Quelle zu Senke. Diese werden im Laufe des Algorithmus alle abgefragt, ob sie nicht von einem anderen Weg dominiert werden und daher gelöscht werden können.


----------



## bygones (14. Okt 2009)

klingt fuer mich bisschen eher nach nicht oop - wenn man ueber primitive werte alle kombinationen per if abfragen will / muss.

ansonsten wie slater schon sagte sind die beiden versionen semantisch untersch.

leserlich ist die erste zu vorziehen

performance ist meist so was von unwichtig, dass man sich darueber nicht mal ansatzweise den kopf zerbrechen soll.

Leserlichkeit >>>>> Performanz


----------



## Leroy42 (14. Okt 2009)

Noch ein Hinweis:



Jagito hat gesagt.:


> ...ca. 10 E12 mal die if-Schleife durchlaufen wird...



if-schleife.de


----------



## SlaterB (14. Okt 2009)

stand anfangs sogar im Titel und eine Antwort auch schon, hatte L-ectron-X dann aufgeräumt, wohl nicht genug


----------



## 0x7F800000 (14. Okt 2009)

wie du das hinschreibst dürfte von der performance her egal sein.

Allerdings macht es evtl. einen unterschied, in welcher reihenfolge du etwas hinschreibst:

```
if(sehrSeltenErfüllt && fastImmerErfüllt){
   ...
}
```
sollte imho schneller laufen, als die äquivalente Bedingung

```
if(fastImmerErfüllt && sehrSeltenErfüllt){
   ...
}
```
weil man im ersten Fall fast immer nur 1 vergleich macht, und im zweiten Fall fast immer 2. Das könnte bei vielen kostenspieligen Vergleichen ins Gewicht fallen.


----------



## SlaterB (14. Okt 2009)

die Frequenz der Erfüllungen reicht nicht, der Aufwand der Prüfung muss auch mit rein

lieber
if(fastImmerErfüllt * 1ms && sehrSeltenErfüllt * 1min){
als
if(sehrSeltenErfüllt * 1min && fastImmerErfüllt * 1ms){


----------



## 0x7F800000 (14. Okt 2009)

SlaterB hat gesagt.:


> die Frequenz der Erfüllungen reicht nicht, der Aufwand der Prüfung muss auch mit rein



Da hast du auch wieder recht! Da es immer nur um dieselben vergleiche ging, hab ich das gar nicht berücksichtigt^^ Erwartungswert der benötigten zeit sollte jedenfalls minimiert werden


----------



## Marco13 (14. Okt 2009)

Dass man die leeren elses weglassen sollte, ist klar.

Oh ja, während Andrey diese Erkenntnis schon ganz abstrakt formuliert hat, habe ich sie mal konkret ausgetestet.


Ich glaube nicht, dass der Unterschied zwischen einer einzelnen if-Abfrage und einer geschachtelten in der Praxis wirklich relevant ist (aufgrund der von SlaterB schon genannten Punkte). Bei eine Microbenchmark, sieht man, nachdem der JIT angesprungen ist, zwar einen (für mich überraschend deutlichen) Vorteil für die einzelne If-Abfrage, aber es sollte klar sein, dass dessen Aussagekraft für die Praxis wegen der trivialen Operationen gegen 0 geht.

Und wie Andrey schon gesagt hat: Hilfreicher wäre vermutlich, bei einem repräsentativen Testlauf (sofern es den gibt) zu überprüfen, welche der Abfragen am häufigsten für einen frühen Abbruch verwendet werden kann.


```
class IfTest
{
    private static long case0 = 0;
    private static long case1 = 0;

    public static void main(String args[])
    {
        long before = 0;
        long after = 0;


        for (int passes=10000; passes<100000; passes+=10000)
        {
            for (int runs=100000; runs<=1000000; runs+=100000)
            {
                before = System.nanoTime();
                test_D_single(passes, runs);
                after = System.nanoTime();
                System.out.println("passes "+passes+" runs "+runs+" case0 "+case0+" case1 "+case1+" test_D_single "+((after-before) / 1000000));

                before = System.nanoTime();
                test_D_nested(passes, runs);
                after = System.nanoTime();
                System.out.println("passes "+passes+" runs "+runs+" case0 "+case0+" case1 "+case1+" test_D_nested "+((after-before) / 1000000));

                before = System.nanoTime();
                test_A_nested(passes, runs);
                after = System.nanoTime();
                System.out.println("passes "+passes+" runs "+runs+" case0 "+case0+" case1 "+case1+" test_A_nested "+((after-before) / 1000000));
            }
        }
    }


    private static void test_D_single(int passes, int runs)
    {
        case0 = 0;
        case1 = 0;

        for (int j=0; j<passes; j++)
        {
            for (int i=0; i<runs; i++)
            {
                countCaseSingle(0,0,0,10);
            }
        }
    }

    private static void test_D_nested(int passes, int runs)
    {
        case0 = 0;
        case1 = 0;

        for (int j=0; j<passes; j++)
        {
            for (int i=0; i<runs; i++)
            {
                countCaseNested(0,0,0,10);
            }
        }
    }

    private static void test_A_nested(int passes, int runs)
    {
        case0 = 0;
        case1 = 0;

        for (int j=0; j<passes; j++)
        {
            for (int i=0; i<runs; i++)
            {
                countCaseNested(10,0,0,0);
            }
        }
    }


    public static void countCaseSingle(int a, int b, int c, int d)
    {
        if(a> 1 && b>2 && c>2 && d<5)
        {
            case0++;
        }
        else if (a< 1 && b<2 && c<2 && d>5)
        {
            case1++;
        }
    }


    public static void countCaseNested(int a, int b, int c, int d)
    {
        if (a < 1)
        {
            if (b < 2)
            {
                if (c < 2)
                {
                    if (d > 5)
                    {
                        case1++;
                    }
                }
            }
        }
        else
        {
            if (b > 2)
            {
                if (c > 2)
                {
                    if (d < 5)
                    {
                        case0++;
                    }
                }
            }
        }
    }

}
```


----------

