Int Division: Warum ist das Ergebnis von 1/3 == 0?


107

Ich habe diesen Code geschrieben:

public static void main(String[] args) {
    double g = 1 / 3;
    System.out.printf("%.2f", g);
}

Das Ergebnis ist 0. Warum ist das so und wie löse ich dieses Problem?

Antworten:


147

Die beiden Operanden (1 und 3) sind ganze Zahlen, daher wird eine ganzzahlige Arithmetik (Division hier) verwendet. Wenn Sie die Ergebnisvariable als double deklarieren, wird nach der Division nur eine implizite Konvertierung durchgeführt .

Eine ganzzahlige Division gibt natürlich das wahre Ergebnis einer gegen Null gerundeten Division zurück. Das Ergebnis von 0.333...wird hier also auf 0 abgerundet. (Beachten Sie, dass der Prozessor eigentlich keine Rundung durchführt, aber Sie können sich das immer noch so vorstellen.)

Beachten Sie außerdem, dass beide Operanden (Zahlen) als Gleitkommazahlen angegeben werden. 3.0 und 1.0 oder auch nur die erste , dann wird Gleitkomma-Arithmetik verwendet 0.333....


33
+1 und es rundet immer ab. int i = .99999999setzt int auf 0. Insbesondere nimmt es den ganzzahligen Teil und verwirft den Rest.
Byron Whitlock

37
Es rundet "gegen Null", was für Werte größer als Null "nach unten" ist. (+0,9 wird auf 0 gerundet, -0,9 wird auch auf 0 gerundet.)
Adrian Smith

@ Byron: Ja genau. Ich glaube nicht, dass der Prozessor tatsächlich eine Rundung vornimmt, da die Division sehr unterschiedlich implementiert ist, aber es ist praktisch, dies so zu sehen.
Noldorin

15
Nein, nicht gerundet: Kürzung
Basil Bourque

3
@BasilBourque In der Java-Terminologie ist die RundungDOWN gegen Null. Die Rundung FLOORgeht in Richtung negative Unendlichkeit.
Andreas

23

1/3 verwendet die Ganzzahldivision, da beide Seiten Ganzzahlen sind.

Sie brauchen mindestens einen von ihnen zu sein floatoder double.

Wenn Sie die Werte wie in Ihrer Frage in den Quellcode eingeben, können Sie dies tun 1.0/3. Das 1.0ist ein Doppel.

Wenn Sie die Werte von einer anderen Stelle erhalten, können Sie sie in eine (double)verwandeln .intdouble

int x = ...;
int y = ...;
double value = ((double) x) / y;

10

Wirken Sie es explizit als double

double g = 1.0/3.0

Dies liegt daran, dass Java die Ganzzahldivisionsoperation für 1und verwendet, 3da Sie sie als Ganzzahlkonstanten eingegeben haben.


2

du solltest benutzen

double g=1.0/3;

oder

double g=1/3.0;

Die Ganzzahldivision gibt eine Ganzzahl zurück.


2

Weil Sie eine ganzzahlige Division durchführen.

Wie @Noldorin sagt, wird die Ganzzahldivision verwendet, wenn beide Operatoren Ganzzahlen sind.

Das Ergebnis 0.33333333 kann nicht als Ganzzahl dargestellt werden, daher wird dem Ergebnis nur der Ganzzahlteil (0) zugewiesen.

Wenn einer der Operatoren ein double/ ist float, findet eine Gleitkomma-Arithmetik statt. Aber Sie werden das gleiche Problem haben, wenn Sie das tun:

int n = 1.0 / 3.0;

1

Da 1 und 3 als Ganzzahlen behandelt werden, wird das Ergebnis auf 0 abgerundet, sodass es eine Ganzzahl ist.

Um das gewünschte Ergebnis zu erzielen, teilen Sie Java explizit mit, dass die Zahlen wie folgt doppelt sind:

double g = 1.0/3.0;

1

Machen Sie die 1 zu einem Float und es wird eine Float-Division verwendet

public static void main(String d[]){
    double g=1f/3;
    System.out.printf("%.2f",g);
}

1

Die Konvertierung in JAVA ist recht einfach, erfordert jedoch etwas Verständnis. Wie im JLS für ganzzahlige Operationen erläutert :

Wenn ein anderer ganzzahliger Operator als ein Verschiebungsoperator mindestens einen Operanden vom Typ long hat, wird die Operation mit einer Genauigkeit von 64 Bit ausgeführt, und das Ergebnis des numerischen Operators ist vom Typ long. Wenn der andere Operand nicht lang ist, wird er zuerst erweitert (§5.1.5), um durch numerische Heraufstufung lang zu tippen (§5.6).

Und ein Beispiel ist immer der beste Weg, um das JLS zu übersetzen;)

int + long -> long
int(1) + long(2) + int(3) -> long(1+2) + long(3)

Andernfalls wird die Operation mit 32-Bit-Genauigkeit ausgeführt, und das Ergebnis des numerischen Operators ist vom Typ int. Wenn einer der Operanden kein int ist, wird er zunächst durch numerische Heraufstufung erweitert, um int einzugeben.

short + int -> int + int -> int

Ein kleines Beispiel mit Eclipse zeigt, dass selbst das Hinzufügen von zwei shorts nicht so einfach ist:

short s = 1;
s = s + s; <- Compiling error

//possible loss of precision
//  required: short
//  found:    int

Dies erfordert ein Gießen mit einem möglichen Präzisionsverlust.

Gleiches gilt für die Gleitkommaoperatoren

Wenn mindestens einer der Operanden eines numerischen Operators vom Typ double ist, wird die Operation unter Verwendung einer 64-Bit-Gleitkomma-Arithmetik ausgeführt, und das Ergebnis des numerischen Operators ist ein Wert vom Typ double. Wenn der andere Operand kein Double ist, wird er zuerst erweitert (§5.1.5), um double durch numerische Heraufstufung einzugeben (§5.6).

Die Promotion erfolgt also auf dem Float in Double.

Und die Mischung aus ganzzahligem und gleitendem Wert führt wie gesagt zu gleitenden Werten

Wenn mindestens einer der Operanden eines binären Operators vom Gleitkomma-Typ ist, ist die Operation eine Gleitkomma-Operation, selbst wenn der andere ganzzahlig ist.

Dies gilt für Binäroperatoren, jedoch nicht für "Zuweisungsoperatoren" wie +=

Ein einfaches Arbeitsbeispiel reicht aus, um dies zu beweisen

int i = 1;
i += 1.5f;

Der Grund ist, dass hier eine implizite Besetzung erfolgt, die wie folgt ausgeführt wird

i = (int) i + 1.5f
i = (int) 2.5f
i = 2

1

1 und 3 sind integer und Inhalte auch so Java tut , eine ganze Zahl ist , die das Ergebnis 0. Wenn Sie doppelt Konstanten , die Sie schreiben müssen schreiben wollen 1.0und 3.0.


1

Die einfachste Lösung besteht darin, dies einfach zu tun

double g = ((double) 1 / 3);

Da Sie 1.0 / 3.0 nicht eingegeben haben, können Sie es manuell in den Datentyp double konvertieren, da Java davon ausgegangen ist, dass es sich um eine Ganzzahldivision handelt, und dies auch dann, wenn dies eine Einschränkung der Konvertierung bedeutet. Dies wird als Cast-Operator bezeichnet.


1

Ich war das.

double g = 1.0/3.0;
System.out.printf("%gf", g);

Verwenden Sie .0, wenn Sie doppelte Berechnungen durchführen, oder Java geht davon aus, dass Sie Ganzzahlen verwenden. Wenn eine Berechnung eine beliebige Anzahl von Doppelwerten verwendet, ist die Ausgabe ein Doppelwert. Wenn alle Ganzzahlen sind, ist die Ausgabe eine Ganzzahl.


0

(1/3) bedeutet ganzzahlige Division, deshalb können Sie aus dieser Division keinen Dezimalwert erhalten. Um dieses Problem zu lösen, verwenden Sie:

public static void main(String[] args) {
        double g = 1.0 / 3;
        System.out.printf("%.2f", g);
    }

0
public static void main(String[] args) {
    double g = 1 / 3;
    System.out.printf("%.2f", g);
}

Da sowohl 1 als auch 3 Ints sind, wird das Ergebnis nicht gerundet, sondern abgeschnitten. Sie ignorieren also Brüche und nehmen nur Ganzes.

Um dies zu vermeiden, haben Sie mindestens eine Ihrer Zahlen 1 oder 3 als Dezimalform 1.0 und / oder 3.0.


0

Probieren Sie es aus:

public static void main(String[] args) {
    double a = 1.0;
    double b = 3.0;
    double g = a / b;
    System.out.printf(""+ g);
}

Bitte posten Sie keine Nur-Code-Antworten, sondern geben Sie eine Erklärung an, was Ihr Code tut und wie (und warum) er das Problem der Frage löst. Bedenken Sie auch, dass dies eine 8 Jahre alte Frage ist, für die bereits positive Antworten vorliegen, und ob Ihre Antwort einen Mehrwert gegenüber den vorhandenen Antworten bietet.
Mark Rotteveel

-1

Mach "double g = 1.0 / 3.0;" stattdessen.


Nur neugierig ... was ist los mit dieser Antwort? Ich habe diesen Ansatz verwendet, als ich zum ersten Mal auf das Problem gestoßen bin. Eine Erklärung, was mit dieser Lösung nicht stimmt, wäre willkommen. Danke im Voraus.
Herr Port St Joe

@ Mr.PortStJoe Es gibt keine Details zu der Person, die die Frage stellt. Wenn wir uns die am besten bewertete Antwort ansehen, können wir sehen, dass sie erklärt haben, WARUM es auch passiert. Obwohl die Antwort technisch korrekt sein mag, kann ihre Nützlichkeit als begrenzt angesehen werden.
Andrew T Finnell

-1

Viele andere haben es versäumt, auf das eigentliche Problem hinzuweisen:

Eine Operation nur für Ganzzahlen wandelt das Ergebnis der Operation in eine Ganzzahl um.

Dies bedeutet zwangsläufig, dass Gleitkommaergebnisse, die als Ganzzahl angezeigt werden könnten , abgeschnitten werden (den Dezimalteil abschneiden).

Was ist Casting (Typumwandlung / Typkonvertierung), das Sie fragen?

Es hängt von der Implementierung der Sprache ab, aber Wikipedia hat eine ziemlich umfassende Sichtweise und es geht auch um Zwang , der eine wichtige Information bei der Beantwortung Ihrer Frage ist.

http://en.wikipedia.org/wiki/Type_conversion


Diese Antwort ist fehlerhaft. Es gibt keine Typumwandlung oder Typkonvertierung in einer Ganzzahl-Version wie 1/2, nicht in der Zielsprache (Java). Sie rufen einfach eine Ganzzahldivision auf, die zu einem Ganzzahlergebnis führt. Das Type Casting ist nur auf die Aufwärtskonvertierung von a intzu doublewährend der Zuordnung zurückzuführen.
YoYo

@YoYo Du sagst, 0,5 ist eine ganze Zahl? Ich glaube nicht, Homie.
Sova

1
Dieser Homie sagte nichts darüber 0.5. In Java 1/2handelt es sich einfach um eine Ganzzahldivision, die zu einer Ganzzahl von Null führt. Sie können einem Double eine Null zuweisen, es ist immer noch eine Null, wenn auch ein 0.0Double.
YoYo
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.