Division Int: Pourquoi le résultat de 1/3 == 0?


107

J'écrivais ce code:

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

Le résultat est 0. Pourquoi et comment résoudre ce problème?

Réponses:


147

Les deux opérandes (1 et 3) sont des entiers, par conséquent l'arithmétique entière (division ici) est utilisée. Déclarer la variable de résultat comme double provoque simplement une conversion implicite après la division .

La division entière renvoie bien sûr le vrai résultat de la division arrondie vers zéro. Le résultat de 0.333...est donc arrondi à 0 ici. (Notez que le processeur ne fait aucun arrondi, mais vous pouvez toujours y penser de cette façon.)

Notez également que si les deux opérandes (nombres) sont donnés sous forme de flottants; 3.0 et 1.0, ou même juste le premier , puis l'arithmétique à virgule flottante est utilisée, vous donnant 0.333....


33
+1 et il arrondit toujours vers le bas. int i = .99999999met int à 0. Plus spécifiquement, il prend la partie entière et rejette le reste.
Byron Whitlock

37
Il arrondit «vers zéro» qui est «vers le bas» pour les valeurs supérieures à zéro. (+0,9 est arrondi à 0, -0,9 est également arrondi à 0.)
Adrian Smith

@Byron: Oui, exactement. Je ne pense pas que le processeur effectue réellement des arrondis, car la division est mise en œuvre très différemment, mais il est pratique de penser à cela de cette façon.
Noldorin

15
Non, pas d'arrondi: Truncation
Basil Bourque

3
@BasilBourque Dans la terminologie java, l' arrondiDOWN est vers zéro. L'arrondi FLOORest vers l'infini négatif.
Andreas

23

1/3 utilise la division entière car les deux côtés sont des entiers.

Vous avez besoin d'au moins l'un d'entre eux pour être floatou double.

Si vous entrez les valeurs dans le code source comme votre question, vous pouvez le faire 1.0/3; l' 1.0est double.

Si vous obtenez les valeurs ailleurs, vous pouvez les utiliser (double)pour transformer le intfichier double.

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

10

Le projeter explicitement comme un double

double g = 1.0/3.0

Cela se produit parce que Java utilise l'opération de division entière pour 1et 3depuis que vous les avez entrées en tant que constantes entières.


2

Tu devrais utiliser

double g=1.0/3;

ou

double g=1/3.0;

La division entière renvoie un entier.


2

Parce que vous faites une division entière.

Comme le dit @Noldorin, si les deux opérateurs sont des entiers, alors la division entière est utilisée.

Le résultat 0.33333333 ne peut pas être représenté comme un entier, donc seule la partie entière (0) est affectée au résultat.

Si l'un des opérateurs est un double/ float, alors l'arithmétique en virgule flottante aura lieu. Mais vous aurez le même problème si vous faites cela:

int n = 1.0 / 3.0;

1

Parce qu'il traite 1 et 3 comme des entiers, arrondissant donc le résultat à 0, de sorte que ce soit un entier.

Pour obtenir le résultat que vous recherchez, dites explicitement à java que les nombres sont des doubles comme ceci:

double g = 1.0/3.0;

1

Faire du 1 un flotteur et une division flottante sera utilisée

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

1

La conversion en JAVA est assez simple mais nécessite une certaine compréhension. Comme expliqué dans le JLS pour les opérations sur les entiers :

Si un opérateur entier autre qu'un opérateur de décalage a au moins un opérande de type long, alors l'opération est effectuée avec une précision de 64 bits et le résultat de l'opérateur numérique est de type long. Si l'autre opérande n'est pas long, il est d'abord élargi (§5.1.5) pour taper long par promotion numérique (§5.6).

Et un exemple est toujours la meilleure façon de traduire le JLS;)

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

Sinon, l'opération est effectuée avec une précision de 32 bits et le résultat de l'opérateur numérique est de type int. Si l'un des opérandes n'est pas un int, il est d'abord élargi pour taper int par promotion numérique.

short + int -> int + int -> int

Un petit exemple utilisant Eclipse pour montrer que même une addition de deux shorts ne sera pas si simple:

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

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

Cela nécessitera un moulage avec une perte de précision possible.

La même chose est vraie pour les opérateurs à virgule flottante

Si au moins l'un des opérandes d'un opérateur numérique est de type double, alors l'opération est effectuée en utilisant l'arithmétique à virgule flottante 64 bits, et le résultat de l'opérateur numérique est une valeur de type double. Si l'autre opérande n'est pas un double, il est d'abord élargi (§5.1.5) pour taper double par promotion numérique (§5.6).

La promotion se fait donc sur le flotteur en double.

Et le mélange de valeurs entières et flottantes donne des valeurs flottantes comme dit

Si au moins l'un des opérandes d'un opérateur binaire est de type à virgule flottante, alors l'opération est une opération à virgule flottante, même si l'autre est intégral.

Ceci est vrai pour les opérateurs binaires mais pas pour les "opérateurs d'affectation" comme +=

Un simple exemple de travail suffit à le prouver

int i = 1;
i += 1.5f;

La raison est qu'il y a un cast implicite fait ici, ce sera exécuté comme

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

1

1 et 3 sont des nombres entiers et donc Java effectue une division entière dont le résultat est 0. Si vous voulez écrire des constantes doubles, vous devez écrire 1.0et 3.0.


1

La solution la plus simple est simplement de faire ceci

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

Ce que cela fait, puisque vous n'avez pas entré 1.0 / 3.0, vous permet de le convertir manuellement en type de données double puisque Java a supposé qu'il s'agissait d'une division Integer, et il le ferait même si cela signifiait réduire la conversion. C'est ce qu'on appelle un opérateur de cast.


1

J'ai fait ça.

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

Utilisez .0 tout en faisant des calculs doubles, sinon Java supposera que vous utilisez des nombres entiers. Si un calcul utilise une quantité de valeurs doubles, la sortie sera une valeur double. Si le sont tous des nombres entiers, alors la sortie sera un entier.


0

(1/3) signifie division entière, c'est pourquoi vous ne pouvez pas obtenir de valeur décimale à partir de cette division. Pour résoudre ce problème, utilisez:

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);
}

Étant donné que 1 et 3 sont des entiers, le résultat n'est pas arrondi mais tronqué. Vous ignorez donc les fractions et ne prenez que des entiers.

Pour éviter cela, utilisez au moins un de vos nombres 1 ou 3 sous forme décimale 1.0 et / ou 3.0.


0

Essayez ceci:

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

Veuillez ne pas publier de réponses contenant uniquement du code, inclure une explication de ce que fait votre code et comment (et pourquoi) il résout le problème de la question. Considérez également qu'il s'agit d'une question vieille de 8 ans qui a des réponses votées et si votre réponse ajoute une valeur par rapport aux réponses existantes.
Mark Rotteveel

-1

Faites "double g = 1.0 / 3.0;" au lieu.


Juste curieux ... qu'est-ce qui ne va pas avec cette réponse? J'ai utilisé cette approche lorsque j'ai rencontré le problème pour la première fois. Une explication de ce qui ne va pas avec cette solution serait appréciée. Merci d'avance.
Mr.Port St Joe

@ Mr.PortStJoe Il ne fournit aucun détail à la personne qui pose la question. En regardant la réponse la mieux notée, nous pouvons voir qu'ils ont expliqué POURQUOI cela se produit également. Bien que la réponse puisse être techniquement correcte, son utilité peut être considérée comme limitée.
Andrew T Finnell

-1

Beaucoup d'autres n'ont pas souligné le vrai problème:

Une opération sur uniquement des entiers convertit le résultat de l'opération en entier.

Cela signifie nécessairement que les résultats en virgule flottante, qui pourraient être affichés sous forme d'entier, seront tronqués (coupez la partie décimale).

Qu'est-ce que le casting (conversion de type / conversion de type) vous demandez-vous?

Cela varie selon l'implémentation du langage, mais Wikipédia a une vue assez complète, et il parle également de coercition , qui est une information essentielle pour répondre à votre question.

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


Cette réponse est imparfaite. Il n'y a pas de conversion de type ou de conversion de type impliquée dans une division de type entier comme 1/2, pas dans la langue cible (java). Vous appelez simplement une division entière, qui se traduira par un résultat entier. La conversion de type est uniquement due à la conversion ascendante de inten a doublependant l'affectation.
YoYo

@YoYo Vous dites que 0,5 est un entier? Je ne pense pas, mon pote.
sova

1
ce pote n'a rien dit 0.5. Simplement, en Java, 1/2est une division entière, qui se traduit par un entier nul. Vous pouvez attribuer un zéro à un double, ce sera toujours un zéro, bien qu'un 0.0double.
YoYo
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.