001    package de.hska.java.aufgaben.ausdruecke;
002    
003    /**
004     * Berechnungen zeigt, warum man Gleitkommazahlen nie
005     * mit dem Identitätsoperator vergleichen darf.
006     * <p>
007     * 0,1 binär ist 1 : 1010 = 0,00001
008     * </p>
009     * <pre>
010     * 1 : 1010 = 0,00001100110011001100...
011     * 10000
012     * -1010
013     * -----
014     *   1100
015     *  -1010
016     *  -----
017     *     1000
018     * </pre>
019     * <p>
020     *   Hier geht es zur <a title="Zum Aufgabentext dieser Java-Übungsaufgabe"
021     *   href="http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/datentypen.html#eins">Beschreibung dieser Java-Aufgabe</a>
022     * </p>
023     * 
024     * @author Christian Pape
025     */
026    public class Berechnungen {
027    
028            /**
029             * Bitte betrachten Sie die Kommentare im
030             *  Quelltext für die Beschreibung
031             *  dieser Lösung.
032             */
033            public static void main(String[] args) {
034                    double einZehntel = 0.1;
035                    double eins = 0.0;
036                    
037                    System.out.println(einZehntel);
038    
039                    eins += einZehntel;
040                    eins += einZehntel;
041                    eins += einZehntel;
042                    eins += einZehntel;
043                    eins += einZehntel;
044                    eins += einZehntel;
045                    eins += einZehntel;
046                    eins += einZehntel;
047                    eins += einZehntel;
048                    eins += einZehntel;
049    
050                    System.out.println(eins == 1.0);
051                    // Der Ausdruck ist false, da 0,1 nicht genau als Gleitkommazahl
052                    // im Speicher repräsentiert werden kann und auf diesen
053                    // Wert beruhende Berechnungen falsch werden können.
054                    
055                    if (eins == 1.0) {
056                            System.out.println("Eins ist 1");
057                    } else {
058                            System.out.println("Eins ist nicht 1, sondern " + eins);
059                    }
060                    
061                    // Gleitkommazahlen dürfen nie mit der Identität vergliechen werden
062                    // Statt dessen den Abstand der Zahlen daraufhin überprüfen,
063                    // ob er sehr klein ist. Der sehr kleine Wert hängt von der Anwendung ab.
064                    // Bei Bankanwendungen reicht 5-8 Stellen Genauigkeit hinter dem Komma.
065                    if ( Math.abs(eins - 1.0) < 1E20 ) {
066                            System.out.println("Eins ist 1");                       
067                    }
068                    
069                    // Runden ist übrigens keine befriedigende Lösung,
070                    // da im Fall 1,49999 oder 1,500001 (statt 1,5)
071                    // in vielen Fälle falsch gerundet wird.
072            }
073    
074    }