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    }