Integer Division: Wie erzeugt man ein Double?


249

Für diesen Codeblock:

int num = 5;
int denom = 7;
double d = num / denom;

der Wert von dist 0.0. Es kann durch Casting zur Arbeit gezwungen werden:

double d = ((double) num) / denom;

Aber gibt es einen anderen Weg, um das richtige doubleErgebnis zu erzielen ? Ich mag es nicht, Primitive zu gießen, wer weiß, was passieren kann.



9
Wenn Sie ein 'int' in ein Double umwandeln, ist dies sicher. Sie erhalten immer den gleichen Wert, ohne an Präzision zu verlieren.
Peter Lawrey

1
Ich würde gerne wissen, ob die folgenden Schritte vom Compiler für die Division korrekt ausgeführt wurden: 1) cast num to float 2) cast denom to float sowie 2) divid num durch denom. Bitte lassen Sie mich wissen, wenn ich falsch liege.
Mannyee

Antworten:


156
double num = 5;

Das vermeidet eine Besetzung. Sie werden jedoch feststellen, dass die Besetzungskonvertierungen genau definiert sind. Sie müssen nicht raten, überprüfen Sie einfach die JLS . int to double ist eine zunehmende Umwandlung. Aus §5.1.2 :

Durch das Erweitern primitiver Konvertierungen gehen keine Informationen über die Gesamtgröße eines numerischen Werts verloren.

[...]

Die Umwandlung eines int oder eines langen Werts in float oder eines langen Werts in double kann zu einem Genauigkeitsverlust führen, dh das Ergebnis kann einige der niedrigstwertigen Bits des Werts verlieren. In diesem Fall ist der resultierende Gleitkommawert eine korrekt gerundete Version des ganzzahligen Werts im IEEE 754-Modus zum Runden auf den nächsten (§4.2.4) .

5 kann genau als Doppel ausgedrückt werden.


60
+1. Hör auf, Angst vor dem Casting zu haben. Erfahren Sie, wie es funktioniert. Es ist alles gut definiert.
Mark Peters

1
@FabricioPH Dies funktioniert in jeder Situation und identisch mit der * 1.0-Lösung.
Vitruvius

3
@Saposhiente Es geht über das Arbeiten hinaus oder nicht. Das Ändern des Variablentyps scheint mir ein schmutziger Code zu sein. Wenn Sie etwas haben, das eine Ganzzahl sein MUSS, und Sie die Darstellung für einen Float ändern, um die mathematische Operation ausführen zu können, riskieren Sie möglicherweise selbst. In einigen Zusammenhängen erleichtert das Lesen der Variablen als Ganzzahl das Verständnis des Codes.
Fabricio PH

2
@FabricioPH, Multiplikation mit 1.0ändert den Typ des Ergebnisses nur auf eine andere Art und Weise. "Scheint mir schmutziger Code" erklärt nicht, in welchen Szenarien Sie glauben, dass das Multiplizieren 1.0tatsächlich besser ist (oder warum das so sein könnte).
Matthew Flaschen

4
@FabricioPH Sie und das OP scheinen unter der falschen Überzeugung zu arbeiten (wo Sie "Ändern des Typs der Variablen" sagen), dass sich dies (double)numirgendwie ändert num. Dies ist nicht der Fall - es wird ein temporäres Double für den Kontext der Anweisung erstellt.
Paul Tomblin

100

Was ist falsch daran, Primitive zu gießen?

Wenn Sie aus irgendeinem Grund nicht besetzen möchten, können Sie dies tun

double d = num * 1.0 / denom;

63
... was eine implizite Besetzung vor der Multiplikation macht
Alice Purcell

2
In den meisten Fällen ist dies besser als das Ändern des Typs einer anderen Variablen.
Fabricio PH

3
@FabricioPH Nichts deutet darauf hin, dass dies wahr ist, es sei denn, Sie haben eine Quelle zum Zitieren.
Vitruvius

1
@ Saposhiente antwortete in Ihrem anderen ähnlichen Kommentar
Fabricio PH

1
Sie können auch das Postfix "D" verwenden (um dieselbe implizite Umwandlung durchzuführen). - so zum Beispiel:double d = num * 1D / denom;
BrainSlugs83

73

Ich mag es nicht, Primitive zu gießen, wer weiß, was passieren kann.

Warum hast du eine irrationale Angst davor, Primitive zu wirken? Es wird nichts Schlimmes passieren, wenn Sie ein intzu einem werfen double. Wenn Sie sich nicht sicher sind, wie es funktioniert, schlagen Sie es in der Java-Sprachspezifikation nach . Das Casting eines intto doubleist eine sich erweiternde primitive Konvertierung .

Sie können das zusätzliche Klammerpaar entfernen, indem Sie den Nenner anstelle des Zählers setzen:

double d = num / (double) denom;

2
Sie können auch tun double d = (double) num / denom;... (OK, dies hängt von der Priorität ab)
user85421

27

Wenn Sie den Typ einer der Variablen ändern, müssen Sie daran denken, sich erneut zu verdoppeln, wenn sich Ihre Formel ändert. Wenn diese Variable nicht mehr Teil der Berechnung ist, ist das Ergebnis durcheinander. Ich mache es mir zur Gewohnheit, innerhalb der Berechnung zu gießen, und füge einen Kommentar daneben hinzu.

double d = 5 / (double) 20; //cast to double, to do floating point calculations

Beachten Sie, dass das Casting des Ergebnisses nicht ausreicht

double d = (double)(5 / 20); //produces 0.0

17

Wandeln Sie eine der Ganzzahlen / beide Ganzzahlen in float um, um zu erzwingen, dass die Operation mit Gleitkomma-Mathematik ausgeführt wird. Ansonsten wird immer eine ganzzahlige Mathematik bevorzugt. So:

1. double d = (double)5 / 20;
2. double v = (double)5 / (double) 20;
3. double v = 5 / (double) 20;

Beachten Sie, dass das Casting des Ergebnisses nicht ausreicht. Weil die erste Division gemäß der Vorrangregel erfolgt.

double d = (double)(5 / 20); //produces 0.0

Ich glaube nicht, dass es ein Problem mit dem Casting als solchem ​​gibt, über das Sie nachdenken.


10

Typ Casting ist der einzige Weg


Produzieren einer doubleaus einer ganzzahligen Division - es gibt keinen anderen Weg ohne Casting (vielleicht werden Sie es nicht explizit tun, aber es wird passieren).

Nun gibt es verschiedene Möglichkeiten, wie wir versuchen können, einen genauen doubleWert zu erhalten (wonum und denomsind intTyp und natürlich beim Casting ) -

  1. mit explizitem Casting:

    • double d = (double) num / denom;
    • double d = ((double) num) / denom;
    • double d = num / (double) denom;
    • double d = (double) num / (double) denom;

aber nicht double d = (double) (num / denom);

  1. mit implizitem Casting:

    • double d = num * 1.0 / denom;
    • double d = num / 1d / denom;
    • double d = ( num + 0.0 ) / denom;
    • double d = num; d /= denom;

aber nicht double d = num / denom * 1.0;
und nichtdouble d = 0.0 + ( num / denom );


2

benutze so etwas wie:

double step = 1d / 5;

(1d ist eine Besetzung zum Verdoppeln)


5
1d ist keine Besetzung, es ist nur eine Erklärung.
Sefier Tang

0

Sie könnten erwägen, die Operationen zu verpacken. Beispielsweise:

class Utils
{
    public static double divide(int num, int denom) {
        return ((double) num) / denom;
    }
}

Auf diese Weise können Sie (nur einmal) nachsehen, ob die Besetzung genau das tut, was Sie wollen. Diese Methode kann auch getestet werden, um sicherzustellen, dass sie weiterhin das tut, was Sie wollen. Es spielt auch keine Rolle, mit welchem ​​Trick Sie die Teilung verursachen (Sie können hier eine der Antworten verwenden), solange das richtige Ergebnis erzielt wird. Überall dort, wo Sie zwei Ganzzahlen teilen müssen, können Sie jetzt einfach anrufen Utils::divideund darauf vertrauen, dass es das Richtige tut.



0

Der beste Weg, dies zu tun, ist

int i = 3;
Double d = i * 1.0;

d is 3.0 now.
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.