001 package de.hska.java.aufgaben.sonstiges;
002
003 /**
004 * Enthält eine main-Methode, um die durchschnittliche Zeit in Nanosekunden zu messen, die
005 * ein Aufruf von getDezimaWert() der verschiedenen HexadezimalZiffer-Implementierungen
006 * benötigt.
007 * <p/>
008 * Hier die Werte meiner Implementierung (JDK 1.6, keine Optimierung,
009 * Athlon 64 3500+).
010 * <pre>
011 * Switch: 11.996048504545454
012 * If: 17.546552072727273
013 * Feld: 14.882158081818181
014 * </pre>
015 * switch ist also am schnellsten.
016 * <p/>
017 * Es gibt im Bytecode zwei verschiedene
018 * switch-Befehle: der eine vergleicht die Werte, der andere verwendet
019 * eine Sprungtabelle.
020 * Vermutlich ist switch hier schneller, als die eigene Implementierung
021 * mit einer "Sprung"tabelle, da der Bytecode für das switch effizienter und
022 * direkter vom Interpreter ausgeführt werden kann.
023 * <p/>
024 *
025 * <p>
026 * <a href="http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/sonstige.html#zeitmessung">Zurück zum Aufgabentext</a>
027 * </p>
028 *
029 *
030 * @author Christian Pape
031 *
032 */
033 public class HexadezimalZifferZeitmessung {
034
035 /**
036 * Misst die durchschnittliche Zeit in Nanosekunden, die ein
037 * Aufruf von getDezimalWert() für alle Implementierungen von
038 * HexadezimalZiffer hat. Dabei werden immer die Dezimalwerte
039 * alle Ziffer von '0' bis '9', 'a'-'f' und 'A'-'F' gleichverteilt
040 * sehr oft nacheinander berechnet.
041 */
042 public static void main(String[] args) {
043 final int anzahlAufrufe = 10000000;
044 HexadezimalZiffer[] hexadezimalZiffern = new HexadezimalZiffer[22];
045 char [] ziffern = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
046 'a', 'b', 'c', 'd', 'e', 'f',
047 'A', 'B', 'D', 'E', 'E', 'F' };
048 double teiler = anzahlAufrufe * ziffern.length;
049
050 for (int i = 0; i < ziffern.length; i++) {
051 hexadezimalZiffern[i] = new HexadezimalZifferSwitch();
052 hexadezimalZiffern[i].setZiffer(ziffern[i]);
053 }
054 System.out.println("Switch: "
055 + getNanoTime(anzahlAufrufe, hexadezimalZiffern)
056 / teiler);
057
058 for (int i = 0; i < ziffern.length; i++) {
059 hexadezimalZiffern[i] = new HexadezimalZifferIf();
060 hexadezimalZiffern[i].setZiffer(ziffern[i]);
061 }
062 System.out.println("If: "
063 + getNanoTime(anzahlAufrufe, hexadezimalZiffern)
064 / teiler);
065
066 for (int i = 0; i < ziffern.length; i++) {
067 hexadezimalZiffern[i] = new HexadezimalZifferFeld();
068 hexadezimalZiffern[i].setZiffer(ziffern[i]);
069 }
070 System.out.println("Feld: "
071 + getNanoTime(anzahlAufrufe, hexadezimalZiffern)
072 / teiler);
073 }
074
075 /**
076 * Gibt die Gesamtzeit für alle Aufrufe von getDezimalWert() der
077 * HexadezimalZiffern zurück. Es werden insgesamt <code>anzahlAufrufe *
078 * hexadezimalZiffer.length</code> Aufrufe durchgeführt.
079 * <code>anzahlAufrufe</code> sollte möglichst gross sein, damit bei der
080 * Zeitmessung die initialen Zeitaufwände
081 * für die for-Schleifen nicht besonders ins Gewicht fallen.
082 */
083 public static long getNanoTime(int anzahlAufrufe,
084 HexadezimalZiffer [] hexadezimalZiffern) {
085 long nanoTime = 0;
086
087 long timeNs = System.nanoTime();
088 for (int i = 0; i < anzahlAufrufe; i++) {
089 for (HexadezimalZiffer hexadezimalZiffer : hexadezimalZiffern) {
090 hexadezimalZiffer.getDezimalWert();
091 }
092 }
093
094 nanoTime = System.nanoTime() - timeNs;
095
096 return nanoTime;
097 }
098
099 }