Divisione Int: perché è il risultato di 1/3 == 0?


107

Stavo scrivendo questo codice:

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

Il risultato è 0. Perché e come risolvo questo problema?

Risposte:


147

I due operandi (1 e 3) sono numeri interi, quindi viene utilizzata l'aritmetica dei numeri interi (divisione qui). Dichiarare la variabile di risultato come double provoca solo una conversione implicita dopo la divisione .

La divisione intera ovviamente restituisce il vero risultato della divisione arrotondata verso zero. Il risultato di 0.333...viene quindi arrotondato a 0 qui. (Nota che il processore in realtà non esegue alcun arrotondamento, ma puoi ancora pensarlo in questo modo.)

Inoltre, nota che se entrambi gli operandi (numeri) sono dati come float; 3.0 e 1.0, o anche solo il primo , quindi viene utilizzata l'aritmetica in virgola mobile, che ti dà 0.333....


33
+1 e viene sempre arrotondato per difetto. int i = .99999999imposta int a 0. Più specificamente, prende la parte intera e scarta il resto.
Byron Whitlock

37
Arrotonda "verso zero" che è "verso il basso" per valori maggiori di zero. (+0,9 viene arrotondato a 0, anche -0,9 viene arrotondato a 0.)
Adrian Smith

@ Byron: Sì, esattamente. Non credo che il processore esegua effettivamente alcun arrotondamento, poiché la divisione è implementata in modo molto diverso, ma è utile pensarla in questo modo.
Noldorin

15
No, non arrotondamento: Troncamento
Basil Bourque

3
@BasilBourque Nella terminologia Java, l' arrotondamentoDOWN è verso lo zero. L'arrotondamento FLOORè verso l'infinito negativo.
Andreas

23

1/3 utilizza la divisione intera poiché entrambi i lati sono numeri interi.

Hai bisogno che almeno uno di loro sia floatodouble .

Se stai inserendo i valori nel codice sorgente come la tua domanda, puoi farlo 1.0/3; il1.0 è un doppio.

Se ottieni i valori da qualche altra parte puoi usarli (double)per trasformare il file intin un file double.

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

10

Lancialo esplicitamente come file double

double g = 1.0/3.0

Ciò accade perché Java utilizza l'operazione di divisione di interi per 1e 3poiché sono stati immessi come costanti intere.


2

dovresti usare

double g=1.0/3;

o

double g=1/3.0;

La divisione intera restituisce un numero intero.


2

Perché stai facendo la divisione intera.

Come dice @Noldorin, se entrambi gli operatori sono numeri interi, viene utilizzata la divisione intera.

Il risultato 0.33333333 non può essere rappresentato come intero, quindi al risultato viene assegnata solo la parte intera (0).

Se uno degli operatori è una double/ float, verrà eseguita un'aritmetica in virgola mobile. Ma avrai lo stesso problema se lo fai:

int n = 1.0 / 3.0;

1

Perché tratta 1 e 3 come numeri interi, quindi arrotondando il risultato per difetto a 0, in modo che sia un numero intero.

Per ottenere il risultato che stai cercando, dì esplicitamente a java che i numeri sono doppi in questo modo:

double g = 1.0/3.0;

1

Rendi 1 un float e verrà utilizzata la divisione float

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

1

La conversione in JAVA è abbastanza semplice ma richiede una certa comprensione. Come spiegato nel JLS per le operazioni su interi :

Se un operatore intero diverso da un operatore di scorrimento ha almeno un operando di tipo long, l'operazione viene eseguita utilizzando una precisione a 64 bit e il risultato dell'operatore numerico è di tipo long. Se l'altro operando non è lungo, viene prima ampliato (§5.1.5) per digitare long per promozione numerica (§5.6).

E un esempio è sempre il modo migliore per tradurre il JLS;)

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

In caso contrario, l'operazione viene eseguita utilizzando una precisione a 32 bit e il risultato dell'operatore numerico è di tipo int. Se uno degli operandi non è un int, viene prima ampliato per digitare int mediante promozione numerica.

short + int -> int + int -> int

Un piccolo esempio dell'uso di Eclipse per mostrare che anche un'aggiunta di due shortnon sarà così facile:

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

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

Ciò richiederà una fusione con una possibile perdita di precisione.

Lo stesso vale per gli operatori in virgola mobile

Se almeno uno degli operandi di un operatore numerico è di tipo double, l'operazione viene eseguita utilizzando l'aritmetica a virgola mobile a 64 bit e il risultato dell'operatore numerico è un valore di tipo double. Se l'altro operando non è un double, viene prima ampliato (§5.1.5) per digitare double per promozione numerica (§5.6).

Quindi la promozione viene fatta sul float in double.

E la combinazione di valori interi e variabili risulta in valori mobili come detto

Se almeno uno degli operandi di un operatore binario è di tipo a virgola mobile, l'operazione è a virgola mobile, anche se l'altra è integrale.

Questo è vero per gli operatori binari ma non per gli "Operatori di assegnazione" come +=

Un semplice esempio funzionante è sufficiente per dimostrarlo

int i = 1;
i += 1.5f;

Il motivo è che qui viene eseguito un cast implicito, verrà eseguito come

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

1

1 e 3 sono numeri interi e quindi Java esegue una divisione intera il cui risultato è 0. Se vuoi scrivere doppie costanti devi scrivere 1.0e 3.0.


1

La soluzione più semplice è fare solo questo

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

Ciò che fa, dal momento che non hai inserito 1.0 / 3.0, ti consente di convertirlo manualmente in un tipo di dati double poiché Java ha assunto che fosse una divisione Integer, e lo farebbe anche se ciò significasse restringere la conversione. Questo è ciò che viene chiamato un operatore di cast.


1

L'ho fatto.

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

Usa .0 mentre esegui doppi calcoli, altrimenti Java presumerà che tu stia utilizzando numeri interi. Se un calcolo utilizza una quantità qualsiasi di valori doppi, l'output sarà un valore doppio. Se sono tutti numeri interi, l'output sarà un numero intero.


0

(1/3) significa divisione intera, ecco perché non puoi ottenere un valore decimale da questa divisione. Per risolvere questo problema usa:

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

Poiché sia ​​1 che 3 sono interi, il risultato non è arrotondato ma viene troncato. Quindi ignori le frazioni e prendi solo interi.

Per evitare ciò, utilizza almeno uno dei tuoi numeri 1 o 3 come forma decimale 1.0 e / o 3.0.


0

Prova questo:

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

Si prega di non inserire risposte di solo codice, includere una spiegazione su cosa fa il codice e su come (e perché) risolve il problema della domanda. Considera anche che questa è una domanda vecchia di 8 anni che ha già risposte votate e se la tua risposta aggiunge valore rispetto alle risposte esistenti.
Mark Rotteveel

-1

Do "double g = 1.0 / 3.0;" anziché.


Solo curioso ... cosa c'è di sbagliato in questa risposta? Ho utilizzato questo approccio la prima volta che ho riscontrato il problema. Sarebbe gradita una spiegazione di cosa c'è di sbagliato in questa soluzione. Grazie in anticipo.
Mr. Port St Joe

@ Mr.PortStJoe Non fornisce alcun dettaglio alla persona che pone la domanda. Guardando la risposta più votata, possiamo vedere che hanno spiegato anche PERCHÉ sta accadendo. Sebbene la risposta possa essere tecnicamente corretta, la sua utilità può essere vista come limitata.
Andrew T Finnell,

-1

Molti altri non sono riusciti a sottolineare il vero problema:

Un'operazione solo su numeri interi esegue il cast del risultato dell'operazione su un numero intero.

Ciò significa necessariamente che i risultati in virgola mobile potrebbero essere visualizzati come un numero intero, verranno troncati (separa la parte decimale).

Cosa sta trasmettendo (typecasting / conversione del tipo) che chiedi?

Dipende dall'implementazione del linguaggio, ma Wikipedia ha una visione abbastanza completa e parla di coercizione , che è un'informazione fondamentale per rispondere alla tua domanda.

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


Questa risposta è viziata. Non vi è alcun tipo di casting o conversione di tipo coinvolto in una concezione di tutti i numeri interi come 1/2, non nella lingua di destinazione (java). Si richiama semplicemente una divisione intera, che risulterà in un risultato intero. Il Type Casting è solo a causa della conversione da inta a doubledurante l'assegnazione.
YoYo

@YoYo Stai dicendo che 0,5 è un numero intero? Non credo proprio, amico.
sova

1
questo amico non ha detto niente 0.5. Semplicemente, in Java, 1/2è una divisione intera, che risulta in un numero intero zero. Puoi assegnare uno zero a un doppio, sarà comunque uno zero, anche se un 0.0doppio.
YoYo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.