Frage

public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

Der obige Code druckt:

11.399999999999

Wie würde ich diese erhalten drucken nur (oder in der Lage sein, es zu benutzen als) 11.4?

War es hilfreich?

Lösung

Wie andere erwähnt haben, werden Sie wahrscheinlich wollen die BigDecimal Klasse, wenn Sie eine genaue Darstellung von 11.4 haben wollen.

Nun wird eine kleine Erklärung in warum dies geschieht:

Die float und double primitiven Typen in Java sind Gleitkomma Zahlen, wo die Nummer gespeichert ist als binäre Darstellung einer Fraktion und ein Exponenten.

Insbesondere wird ein doppelter Genauigkeit Gleitkommawert wie der double Typ ist ein 64-Bit-Wert, wobei gilt:

  • 1 Bit bezeichnet das Vorzeichen (positiv oder negativ).
  • 11 Bit für den Exponenten.
  • 52 Bits für die signifikanten Stellen (der Bruchteil als binäres).

Diese Teile werden kombiniert, um eine double Darstellung eines Wertes zu erzeugen.

(Quelle: Wikipedia: doppelte Genauigkeit )

Für eine detaillierte Beschreibung, wie Fließkommawerte in Java behandelt werden, finden Sie in der Abschnitt 4.2.3. Gleitkommatypen, Formate und Werte der Java Language Specification

Die byte, char, int, long Typen sind Festkomma Zahlen, die sind genaue representions von Zahlen. Im Gegensatz zu Festkommazahlen, Zahlen Gleitkomma wird einige Male (sicher „die meiste Zeit“ anzunehmen) nicht in der Lage, eine genaue Darstellung einer Zahl zurück. Dies ist der Grund, warum Sie mit 11.399999999999 als Ergebnis 5.6 + 5.8 enden.

Wenn Sie einen Wert erfordert, die genau wie 1,5 oder 150,1005 ist, werden Sie eine der Festpunkttypen verwenden möchten, die in der Lage sein wird, die Nummer genau darzustellen.

Wie bereits mehrfach erwähnt, Java hat eine BigDecimal Klasse, die sehr große Stückzahl und sehr kleine Zahlen behandelt.

Von der Java-API-Referenz für die BigDecimal Klasse:

  

Immutable,   beliebige Genauigkeit Dezimalzahl mit Vorzeichen   Zahlen. Ein BigDecimal besteht aus einem   beliebiger Genauigkeit integer unskalierten   Wert und einen ganzzahligen Skalierungs 32-Bit. Wenn   Null oder positiv ist, ist das Ausmaß der   Anzahl der Stellen rechts von der   Komma. Wenn negativ, die   unskalierten Wert der Zahl ist,   um zehn bis die volle Leistung der multiplizierten   Negation der Skala. Der Wert von   die Zahl durch die dargestellte   BigDecimal ist daher (unscaledValue   × 10 ^ -Skala).

Es hat sich auf die Frage der Gleitkommazahlen und seine Präzision im Zusammenhang viele Fragen auf Stack-Überlauf gewesen. Hier ist eine Liste von verwandten Fragen, die von Interesse sein können:

Wenn Sie wirklich wollen, auf die Nitty Gritty Details des Schwebens runterPunktzahl, werfen Sie einen Blick auf Was jeder Informatiker über Gleitkommaarithmetik wissen sollte .

Andere Tipps

Bei der Eingabe eine doppelte Anzahl, beispielsweise 33.33333333333333, der Wert, den Sie erhalten, ist eigentlich der nächste darstellbare Wert mit doppelter Genauigkeit, die genau ist:

33.3333333333333285963817615993320941925048828125

Die Aufteilung, dass durch 100 ergibt:

0.333333333333333285963817615993320941925048828125

, die auch nicht darstellbare als Zahl mit doppelter Genauigkeit ist, so es wieder auf den nächsten darstellbaren Wert gerundet wird, was genau ist:

0.3333333333333332593184650249895639717578887939453125

Wenn Sie diesen Wert aus drucken, wird sie abgerundet noch einmal auf 17 Dezimalstellen geben:

0.33333333333333326

Wenn Sie nur Werte als Fraktionen bearbeiten möchten, können Sie eine Fraction-Klasse erstellen, die einen Zähler und Nenner-Feld enthält.

Schreibmethoden für Addieren, Subtrahieren, Multiplizieren und sowie eine ToDouble Methode teilen. Auf diese Weise können Schwimmer während Berechnungen vermeiden.

EDIT: Schnelle Implementierung,

public class Fraction {

private int numerator;
private int denominator;

public Fraction(int n, int d){
    numerator = n;
    denominator = d;
}

public double toDouble(){
    return ((double)numerator)/((double)denominator);
}


public static Fraction add(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop + bTop, a.denominator * b.denominator);
    }
    else{
        return new Fraction(a.numerator + b.numerator, a.denominator);
    }
}

public static Fraction divide(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}

public static Fraction multiply(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}

public static Fraction subtract(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop-bTop, a.denominator*b.denominator);
    }
    else{
        return new Fraction(a.numerator - b.numerator, a.denominator);
    }
}

}

Beachten Sie, dass Sie das gleiche Problem haben würden, wenn Sie mit begrenzten Genauigkeit Dezimalarithmetik verwendet, und wollten mit 1/3 beschäftigen: 0,333333333 * 3 ist 0,999999999, nicht 1,00000000.

Leider, 5,6, 5,8 und 11,4 sind einfach nicht runde Zahlen in binär, weil sie Fünftel beteiligt. So ist der Schwimmer Darstellung von ihnen ist nicht exakt, wie 0.3333 ist nicht genau 1/3.

Wenn alle Zahlen, die Sie verwenden, sind nicht-wiederkehrenden Dezimalstellen, und Sie möchten genaue Ergebnisse, BigDecimal verwenden. Oder wie andere gesagt haben, wenn Ihre Werte wie Geld in dem Sinne, dass sie alle ein Vielfaches von 0,01 sind, oder 0,001, oder etwas, dann multiplizieren alles durch eine feste Leistung von 10 und Verwendung int oder lang (Addition und Subtraktion trivial. achten Sie auf Multiplikation)

Wenn Sie jedoch mit binärer für die Berechnung glücklich sind, aber Sie wollen die Dinge nur in einem etwas freundlicheren Format drucken, versuchen java.util.Formatter oder String.format. Im Format-String geben Sie eine Genauigkeit von weniger als die volle Präzision eines Doppel. Zu 10 signifikanten Zahlen, sagen sie, 11,399999999999 ist 11,4, so das Ergebnis fast so genau sein wird und mehr Menschen lesbaren in Fällen, in denen das binäre Ergebnis ist sehr nahe an einen Wert, der nur wenige Dezimalstellen.

Die Genauigkeit angeben, hängt ein wenig ab, wie viel Mathematik Sie mit Ihren Zahlen getan haben - in der Regel Je mehr Sie tun, desto mehr Fehler akkumulieren, aber einige Algorithmen akkumulieren es viel schneller als andere (sie heißen " unstabil Rundungsfehler stabil ‚in Bezug“ im Gegensatz zu‘). Wenn alles, was Sie tun, ist ein paar Werte addiert, dann würde ich vermuten, dass nur eine Dezimalstelle an Präzision fallen die Dinge aussortieren. Experiment.

Sie können in der Verwendung der Java-java.math.BigDecimal Klasse aussehen sollen, wenn Sie wirklich Präzisionsberechnungen benötigen. Hier ist ein guter Artikel von Oracle / Sun auf den Fall für BigDecimal . Während Sie nie erwähnt 1/3 als jemand darstellen kann, können Sie können die Macht haben, genau zu entscheiden, wie genau Sie das Ergebnis sein soll. setScale () ist dein Freund ..:)

Ok, da ich im Moment viel zu viel Zeit auf meinen Händen hier habe, ist ein Codebeispiel, das auf Ihre Frage bezieht:

import java.math.BigDecimal;
/**
 * Created by a wonderful programmer known as:
 * Vincent Stoessel
 * xaymaca@gmail.com
 * on Mar 17, 2010 at  11:05:16 PM
 */
public class BigUp {

    public static void main(String[] args) {
        BigDecimal first, second, result ;
        first = new BigDecimal("33.33333333333333")  ;
        second = new BigDecimal("100") ;
        result = first.divide(second);
        System.out.println("result is " + result);
       //will print : result is 0.3333333333333333


    }
}

und meine neue Lieblingssprache zu stopfen, Groovy, hier ist ein ordentliches Beispiel für die gleiche Sache:

import java.math.BigDecimal

def  first =   new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")


println "result is " + first/second   // will print: result is 0.33333333333333

Ziemlich sicher, dass Sie, dass in ein dreizeilige Beispiel gemacht haben könnten. :)

Wenn Sie genaue Präzision möchten, verwenden BigDecimal. Andernfalls können Sie Ints mit 10 ^ multipliziert verwenden, was auch immer Präzision, die Sie wollen.

Wie andere bereits erwähnt haben, sind nicht alle Dezimalzahlen als binäre dargestellt werden, da dezimal auf Potenzen von 10 und binäre basiert basiert auf Zweierpotenzen.

Wenn Präzision Angelegenheiten, verwenden BigDecimal, aber wenn man nur freundlich ausgegeben werden soll:

System.out.printf("%.2f\n", total);

geben Sie:

11.40

Sie laufen gegen die Präzision Begrenzung vom Typ double.

java.math hat einige beliebige Genauigkeit arithmetische Einrichtungen.

Sie können nicht, weil 7.3 keine endliche Repräsentation binär haben. Die nächstgelegene Sie erhalten können, ist 2054767329987789/2 ** 48 = 7,3 + 1/1407374883553280.

Hier finden Sie aktuelle http://docs.python.org/tutorial/floatingpoint.html für eine weitere Erklärung. (Es ist auf der Python-Website, aber Java und C ++ haben das gleiche "Problem".)

Die Lösung hängt davon ab, was genau das Problem ist:

  • Wenn es, dass Sie gerade nicht mag all diese Lärm Stellen sehen, dann Zeichenfolge Formatierung beheben. Sie nicht mehr als 15 signifikante Stellen angezeigt werden (oder 7 für float).
  • Wenn es, dass die Ungenauigkeit Ihrer Zahlen ist Dinge wie "if" Aussagen zu brechen, dann sollten Sie schreiben, wenn (abs (x - 7,3) .
  • Wenn Sie mit dem Geld arbeiten, dann, was Sie wahrscheinlich wirklich ist Fixpunkt dezimal wollen. Speichern Sie eine ganze Anzahl von Cent oder was auch immer die kleinste Einheit Ihrer Währung ist.
  • (sehr unwahrscheinlich) Wenn Sie mehr als 53 Bits (15-16 signifikante Stellen) müssen Präzision, dann verwenden, um eine hochpräzise Gleitkommatyp, wie BigDecimal.
private void getRound() {
    // this is very simple and interesting 
    double a = 5, b = 3, c;
    c = a / b;
    System.out.println(" round  val is " + c);

    //  round  val is  :  1.6666666666666667
    // if you want to only two precision point with double we 
            //  can use formate option in String 
           // which takes 2 parameters one is formte specifier which 
           // shows dicimal places another double value 
    String s = String.format("%.2f", c);
    double val = Double.parseDouble(s);
    System.out.println(" val is :" + val);
    // now out put will be : val is :1.67
}

Verwenden java.math.BigDecimal

Doubles sind Binärbrüche intern, so dass sie manchmal nicht Dezimalbrüchen auf die genaue dezimal darstellen.

alles mit 100 multiplizieren und speichern sie in einem langen Cent.

Computer speichern Zahlen in binär und kann nicht wirklich solche Zahlen darstellen, wie 33,333333333 oder 100,0 genau. Dies ist eine der kniffligen Dinge über verdoppelt werden. Sie werden nur rund um die Antwort haben, bevor es zu einem Benutzer zeigt. Zum Glück in den meisten Anwendungen, die Sie nicht brauchen, dass viele Dezimalstellen sowieso.

Gleitkommazahlen unterscheiden sich von reellen Zahlen, dass für jede Gleitkommazahl gegeben gibt es eine nächsthöhere Gleitpunktzahl. Das gleiche wie ganze Zahlen. Es gibt keine ganze Zahl zwischen 1 und 2.

Es gibt keinen Weg 1/3 als Schwimmer zu vertreten. Es gibt einen Schwimmer darunter und es gibt einen Schwimmer darüber, und es gibt eine gewisse Distanz zwischen ihnen. Und ein Drittel ist in diesem Raum.

Apfloat für Java behauptet mit beliebiger Genauigkeit Gleitkommazahlen zu arbeiten, aber ich habe es nie benutzt. Wahrscheinlich einen Blick wert. http://www.apfloat.org/apfloat_java/

Eine ähnliche Frage wurde hier gefragt, bevor Java Gleitkomma hohe Präzision Bibliothek

Doubles sind Annäherungen der Dezimalzahlen in Ihrer Java-Quelle. Sie sind die Folge der fehlenden Übereinstimmung zwischen dem Doppel zu sehen (die ein binär codierter Wert ist) und Ihre Quelle (die Dezimal-codiert ist).

Java Herstellung der nächste binäre Annäherung. Sie können die java.text.DecimalFormat verwenden, um eine besser aussehende Dezimalwert angezeigt werden soll.

Verwenden Sie ein BigDecimal. Damit können Sie auch Rundungsregeln festlegen (wie ROUND_HALF_EVEN, die durch Rundung auf den auch Nachbar statistische Fehler minimieren, wenn beide den gleichen Abstand sind, das heißt beide 1,5 und 2,5 Runde 2).

Überprüfen Sie heraus BigDecimal, es behandelt Probleme Umgang mit Gleitpunktarithmetik ähnlich.

Der neue Aufruf wie folgt aussehen:

term[number].coefficient.add(co);

Mit setScale () die Anzahl der Nachkommastellen Genauigkeit einzustellen verwendet werden.

Warum nicht die Runde () -Methode von Math-Klasse verwenden?

// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4

Wenn Sie keine andere Wahl haben andere als die doppelten Werte verwenden, kann den Code unten verwenden.

public static double sumDouble(double value1, double value2) {
    double sum = 0.0;
    String value1Str = Double.toString(value1);
    int decimalIndex = value1Str.indexOf(".");
    int value1Precision = 0;
    if (decimalIndex != -1) {
        value1Precision = (value1Str.length() - 1) - decimalIndex;
    }

    String value2Str = Double.toString(value2);
    decimalIndex = value2Str.indexOf(".");
    int value2Precision = 0;
    if (decimalIndex != -1) {
        value2Precision = (value2Str.length() - 1) - decimalIndex;
    }

    int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
    sum = value1 + value2;
    String s = String.format("%." + maxPrecision + "f", sum);
    sum = Double.parseDouble(s);
    return sum;
}

Do not waste your efford mit BigDecimal nicht. In 99,99999% Fällen Sie brauchen es nicht. java double Typ ist von cource annähernde, jedoch in fast allen Fällen ist es hinreichend präzise. Beachten Sie, dass Ihr haben einen Fehler bei der 14. signifikanten Stelle. Das ist wirklich vernachlässigbar!

Um schön Ausgang Verwendung zu erhalten:

System.out.printf("%.2f\n", total);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top