Division entière: Comment produit-on un double?


249

Pour ce bloc de code:

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

la valeur de dest 0.0. Il peut être forcé de fonctionner en lançant:

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

Mais existe-t-il un autre moyen d'obtenir le doublerésultat correct ? Je n'aime pas lancer des primitives, qui sait ce qui peut arriver.



9
lancer un 'int' dans un double est sûr, vous obtiendrez toujours la même valeur sans perte de précision.
Peter Lawrey

1
Je voudrais savoir si les étapes suivantes sont correctes prises par le compilateur pour la division: 1) cast num to float 2) cast denom to float as well 2) div num by denom. Veuillez me faire savoir si je me trompe.
mannyee

Réponses:


156
double num = 5;

Cela évite un casting. Mais vous constaterez que les conversions de cast sont bien définies. Vous n'avez pas à deviner, vérifiez simplement le JLS . int à double est une conversion élargie. Du §5.1.2 :

L'élargissement des conversions primitives ne perd pas d'informations sur l'ampleur globale d'une valeur numérique.

[...]

La conversion d'une valeur int ou longue en float, ou d'une valeur longue en double, peut entraîner une perte de précision, c'est-à-dire que le résultat peut perdre certains des bits les moins significatifs de la valeur. Dans ce cas, la valeur en virgule flottante résultante sera une version correctement arrondie de la valeur entière, en utilisant le mode arrondi au plus proche IEEE 754 (§4.2.4) .

5 peut être exprimé exactement comme un double.


60
+1. Arrêtez d'avoir peur de lancer. Apprenez comment cela fonctionne. Tout est bien défini.
Mark Peters

1
@FabricioPH Cela fonctionne dans toutes les situations et à l'identique de la solution * 1.0.
Vitruve

3
@Saposhiente Cela va au-delà du travail ou non. Changer le type d'une variable me semble un code sale. Si vous avez quelque chose qui DOIT ÊTRE un entier et que vous modifiez la représentation d'un flottant juste pour pouvoir effectuer l'opération mathématique, vous risquez de vous risquer. Dans certains contextes également, la lecture de la variable sous forme d'entier facilite la compréhension du code.
Fabricio PH

2
@FabricioPH, en multipliant par 1.0change toujours le type du résultat, juste d'une manière différente. «Cela me semble sale» n'explique pas dans quel (s) scénario (s) vous pensez que la multiplication 1.0est en fait meilleure (ni pourquoi cela pourrait être).
Matthew Flaschen

4
@FabricioPH Vous et l'OP semblez travailler sous la fausse croyance (où vous dites "Changer le type de la variable") que cela (double)numchange en quelque sorte num. Ce n'est pas le cas - cela crée un double temporaire pour le contexte de l'instruction.
Paul Tomblin

100

Qu'y a-t-il de mal à lancer des primitives?

Si vous ne voulez pas lancer de casting pour une raison quelconque, vous pouvez le faire

double d = num * 1.0 / denom;

63
... qui fait un casting implicite avant la multiplication
Alice Purcell

2
Dans la plupart des cas, cela vaut mieux que de changer le type d'une autre variable.
Fabricio PH

3
@FabricioPH Rien ne suggère que cela soit vrai, sauf si vous avez une source à citer.
Vitruve

1
@Saposhiente a répondu dans votre autre commentaire similaire
Fabricio PH

1
Vous pouvez également utiliser le suffixe "D" (pour effectuer la même conversion implicite); - donc par exemple:double d = num * 1D / denom;
BrainSlugs83

73

Je n'aime pas lancer des primitives, qui sait ce qui peut arriver.

Pourquoi avez-vous une peur irrationnelle de lancer des primitifs? Rien de mauvais ne se produira lorsque vous lancerez un intvers un double. Si vous n'êtes tout simplement pas sûr de son fonctionnement, recherchez-le dans la spécification du langage Java . La conversion d' un intvers doubleest une conversion primitive élargie .

Vous pouvez vous débarrasser de la paire de parenthèses supplémentaire en transtypant le dénominateur au lieu du numérateur:

double d = num / (double) denom;

2
vous pouvez aussi bien faire double d = (double) num / denom;... (OK, celui-ci dépend de la priorité)
user85421

27

Si vous changez le type de l'une des variables, vous devez vous rappeler d'introduire à nouveau un double si votre formule change, car si cette variable cesse de faire partie du calcul, le résultat est foiré. Je prends l'habitude de lancer le calcul et d'ajouter un commentaire à côté.

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

Notez que lancer le résultat ne le fera pas

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

17

Cast un des entiers / les deux de l'entier à flotter pour forcer l'opération à effectuer avec Math à virgule flottante. Sinon, les mathématiques entières sont toujours préférées. Alors:

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

Notez que la diffusion du résultat ne le fera pas. Parce que la première division se fait selon la règle de priorité.

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

Je ne pense pas qu'il y ait de problème avec le casting en tant que tel auquel vous pensez.


10

Le casting de type est le seul moyen


Produire une doubledivision entière - il n'y a pas d'autre moyen sans lancer (peut-être que vous ne le ferez pas explicitement mais cela se produira).

Maintenant, il existe plusieurs façons d'essayer d'obtenir une doublevaleur précise (où numet denomsont le inttype, et bien sûr avec le casting ) -

  1. avec un casting explicite:

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

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

  1. avec casting implicite:

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

mais pas double d = num / denom * 1.0;
et pasdouble d = 0.0 + ( num / denom );


2

utilisez quelque chose comme:

double step = 1d / 5;

(1d est un casting à doubler)


5
1d n'est pas un casting, c'est juste une déclaration.
Sefier Tang

0

Vous pourriez envisager de boucler les opérations. Par exemple:

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

Cela vous permet de rechercher (une seule fois) si le casting fait exactement ce que vous voulez. Cette méthode pourrait également être soumise à des tests, afin de s'assurer qu'elle continue à faire ce que vous voulez. Peu importe la astuce que vous utilisez pour provoquer la division (vous pouvez utiliser n'importe laquelle des réponses ici), tant qu'elle aboutit au résultat correct. Partout où vous avez besoin de diviser deux entiers, vous pouvez maintenant simplement appeler Utils::divideet avoir confiance qu'il fait la bonne chose.


0

il suffit de l'utiliser.

int fxd=1;
double percent= (double)(fxd*40)/100;

0

La meilleure façon de le faire est

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

d is 3.0 now.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.