Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy put High chance clause into the front of nested If else would degenerate performance?
    primarykey
    data
    text
    <p>it is rather strange, I had thought we should always put high chance clause into the front of nested if-elses, until today.</p> <p>Brief setup:</p> <p>an array <code>Zoo[]</code> contains 10,000 objects of 5 classes, based on the weights, e.g. 4,3,2,1,0 (means 4000 Cats, 3000 Dogs, 2000 Chickens, 1000 Rabbits, 0 Owls) and it can either be shuffled or not (exactly in order).</p> <p>Then Use <code>if-else</code> to check each array members.</p> <p>Results: Time (ms)</p> <pre><code> Weights 43210 01234 22222 43210 01234 22222 Shuffle Yes Yes Yes No No No Polymorphism 101 100 107 26 26 27 If Else 77 28 59 17 16 17 If Else Reverse 28 77 59 16 17 16 Switch 21 21 21 18 19 18 </code></pre> <p>It caught my eye when I see the <code>If-Else</code> reverse is much better than <code>if-else</code>. Here <code>if-else</code> exams Cat->Dog->Chicken->Rabbit->Owl, reversed version checks them in reverse order.</p> <p>Also, could someone explain in the non shuffle version every method gain great improvement? (I would assume due to cache or better hit rate in memory?)</p> <h3>Update</h3> <pre><code> Weights 27 9 3 1 0 0 1 3 9 27 27 9 3 1 0 0 1 3 9 27 Shuffle Yes Yes No No Polymorphism 84 82 27 27 If Else 61 20 17 16 If Else Reverse 20 60 16 17 Switch 21 21 18 18 </code></pre> <p>Code follows:</p> <pre><code>class Animal : AnimalAction { public virtual int Bart { get; private set; } public int Type { get; private set; } public Animal(int animalType) { this.Type = animalType; } } interface AnimalAction { int Bart { get; } } class Cat : Animal { public Cat() : base(0) { } public override int Bart { get { return 0; } } } class Dog : Animal { public Dog() : base(1) { } public override int Bart { get { return 1; } } } class Chicken : Animal { public Chicken() : base(2) { } public override int Bart { get { return 2; } } } class Rabbit : Animal { public Rabbit() : base(3) { } public override int Bart { get { return 3; } } } class Owl : Animal { public Owl() : base(4) { } public override int Bart { get { return 4; } } } class SingleDispatch { readonly Animal[] Zoo; int totalSession; SingleDispatch(int totalSession, int zooSize) { this.totalSession = totalSession; Zoo = new Animal[zooSize]; int[] weights = new int[5] { 0, 1, 2, 3, 4 }; int totalWeights = weights.Sum(); int[] tiers = new int[4]; int accumulated = 0; for (int i = 0; i &lt; 4; i++) { accumulated += weights[i] * zooSize / totalWeights; tiers[i] = accumulated; } for (int i = 0; i &lt; tiers[0]; i++) { Animal nextAnimal = new Cat(); Zoo[i] = nextAnimal; } for (int i = tiers[0]; i &lt; tiers[1]; i++) { Animal nextAnimal = new Dog(); Zoo[i] = nextAnimal; } for (int i = tiers[1]; i &lt; tiers[2]; i++) { Animal nextAnimal = new Chicken(); Zoo[i] = nextAnimal; } for (int i = tiers[2]; i &lt; tiers[3]; i++) { Animal nextAnimal = new Rabbit(); Zoo[i] = nextAnimal; } for (int i = tiers[3]; i &lt; zooSize; i++) { Animal nextAnimal = new Owl(); Zoo[i] = nextAnimal; } Zoo.FisherYatesShuffle(); } public static void Benchmark() { List&lt;Tuple&lt;string, double&gt;&gt; result = new List&lt;Tuple&lt;string, double&gt;&gt;(); SingleDispatch myBenchmark = new SingleDispatch(1000, 10000); result.Add(TestContainer.RunTests(10, myBenchmark.SubClassPoly)); result.Add(TestContainer.RunTests(10, myBenchmark.Ifelse)); result.Add(TestContainer.RunTests(10, myBenchmark.IfelseReverse)); result.Add(TestContainer.RunTests(10, myBenchmark.Switch)); foreach (var item in result) { Console.WriteLine("{0,-30}{1:N0}", item.Item1, item.Item2); } Console.WriteLine(); } void SubClassPoly() { long sum = 0; for (int i = 0; i &lt; totalSession; i++) { foreach (var myAnimal in Zoo) { sum += myAnimal.Bart; } } } void Ifelse() { long sum = 0; for (int i = 0; i &lt; totalSession; i++) { foreach (var myAnimal in Zoo) { if (myAnimal.Type == 0) { sum += 0; } else if (myAnimal.Type == 1) { sum += 1; } else if (myAnimal.Type == 2) { sum += 2; } else if (myAnimal.Type == 3) { sum += 3; } else { sum += 4; } } } } void IfelseReverse() { long sum = 0; for (int i = 0; i &lt; totalSession; i++) { foreach (var myAnimal in Zoo) { if (myAnimal.Type == 4) { sum += 4; } else if (myAnimal.Type == 3) { sum += 3; } else if (myAnimal.Type == 2) { sum += 2; } else if (myAnimal.Type == 1) { sum += 1; } else { sum += 0; } } } } void Switch() { long sum = 0; for (int i = 0; i &lt; totalSession; i++) { foreach (var myAnimal in Zoo) { switch (myAnimal.Type) { case 0: sum += 0; break; case 1: sum += 1; break; case 2: sum += 2; break; case 3: sum += 3; break; case 4: sum += 4; break; default: break; } } } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload