Divisione intera: come si produce un doppio?


249

Per questo blocco di codice:

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

il valore di dè 0.0. Può essere costretto a lavorare lanciando:

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

Ma c'è un altro modo per ottenere il doublerisultato corretto ? Non mi piace lanciare primitivi, chissà cosa potrebbe succedere.



9
lanciare un 'int' in un doppio è sicuro, otterrai sempre lo stesso valore senza perdita di precisione.
Peter Lawrey,

1
Vorrei sapere se i seguenti sono i passi corretti adottati dal compilatore per la divisione: 1) cast num to float 2) cast denom to float e 2) divide num per denom. Per favore fatemi sapere se non sono corretto.
mannyee,

Risposte:


156
double num = 5;

Ciò evita un cast. Ma scoprirai che le conversioni del cast sono ben definite. Non devi indovinare, basta controllare JLS . int per raddoppiare è una conversione allargata. Da §5.1.2 :

L'ampliamento delle conversioni primitive non perde informazioni sull'entità complessiva di un valore numerico.

[...]

La conversione di un valore int o di un valore lungo da float o di un valore lungo da raddoppiare può comportare una perdita di precisione, ovvero il risultato potrebbe perdere alcuni dei bit meno significativi del valore. In questo caso, il valore in virgola mobile risultante sarà una versione arrotondata correttamente del valore intero, utilizzando la modalità IEEE 754 arrotondata al più vicino (§4.2.4) .

5 può essere espresso esattamente come un doppio.


60
+1. Smetti di aver paura del casting. Scopri come funziona. È tutto ben definito.
Mark Peters,

1
@FabricioPH Funziona in ogni situazione e in modo identico alla soluzione * 1.0.
Vitruvio

3
@Saposhiente Va oltre il lavoro o meno. Cambiare il tipo di una variabile mi sembra un codice sporco. Se hai qualcosa che DEVE ESSERE un numero intero e cambi la rappresentazione per un float solo per poter eseguire l'operazione matematica, potresti rischiare te stesso. Anche in alcuni contesti la lettura della variabile come numero intero rende il codice più semplice da comprendere.
Fabricio PH

2
@FabricioPH, moltiplicando 1.0ancora cambia il tipo di risultato, solo in modo diverso. "Mi sembra un codice sporco" non spiega in quale scenario (s) credi che moltiplicare 1.0sia effettivamente migliore (o perché potrebbe essere).
Matthew Flaschen

4
@FabricioPH Tu e l'OP sembrate lavorare sotto la falsa credenza (dove dite "Cambiare il tipo della variabile") che in (double)numqualche modo cambia num. Non lo fa: crea un doppio temporaneo per il contesto dell'istruzione.
Paul Tomblin,

100

Cosa c'è di sbagliato nel lanciare le primitive?

Se non vuoi lanciare un cast per qualche motivo, potresti farlo

double d = num * 1.0 / denom;

63
... che fa un cast implicito prima della moltiplicazione
Alice Purcell,

2
Nella maggior parte dei casi, è meglio che cambiare il tipo di altra variabile.
Fabricio PH

3
@FabricioPH Nulla suggerisce che questo sia vero, a meno che tu non abbia una fonte da citare.
Vitruvio

1
@Saposhiente ha risposto nel tuo altro commento simile
Fabricio PH

1
Puoi anche usare il postfisso "D" (per eseguire lo stesso cast implicito); - quindi ad esempio:double d = num * 1D / denom;
BrainSlugs83

73

Non mi piace lanciare primitivi, chissà cosa potrebbe succedere.

Perché hai una paura irrazionale di lanciare primitivi? Non accadrà nulla di brutto quando lanci un inta double. Se non sei sicuro di come funzioni, cercalo nelle Specifiche del linguaggio Java . Lanciare un intto doubleè una conversione primitiva allargante .

Puoi sbarazzarti della coppia di parentesi aggiuntiva lanciando il denominatore anziché il numeratore:

double d = num / (double) denom;

2
puoi anche fare double d = (double) num / denom;... (OK, questo dipende dalla precedenza)
user85421

27

Se cambi il tipo di una delle variabili devi ricordare di intrufolarti di nuovo in un doppio se la tua formula cambia, perché se questa variabile smette di far parte del calcolo, il risultato è incasinato. Ho l'abitudine di lanciare all'interno del calcolo e aggiungo un commento accanto.

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

Nota che il cast del risultato non lo farà

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

17

Eseguire il cast di uno degli interi / entrambi dell'intero su float per forzare l'operazione da eseguire con la matematica in virgola mobile. Altrimenti si preferisce sempre la matematica intera. Così:

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

Nota che il cast del risultato non lo farà. Perché la prima divisione viene eseguita secondo la regola di precedenza.

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

Non credo ci siano problemi con il casting in quanto tale a cui stai pensando.


10

Casting di tipo è l'unico modo


Produrre una doubledivisione da intero - non c'è altro modo senza il cast (forse non lo farai esplicitamente ma accadrà).

Ora, ci sono diversi modi in cui possiamo cercare di ottenere precisi doublevalori (dove nume denomsono intil tipo, e di portate con fusione ) -

  1. con casting esplicito:

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

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

  1. con casting implicito:

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

ma non double d = num / denom * 1.0;
e nondouble d = 0.0 + ( num / denom );


2

usa qualcosa come:

double step = 1d / 5;

(1d è un cast da raddoppiare)


5
1d non è un cast, è solo una dichiarazione.
Sefier Tang,

0

Potresti considerare di concludere le operazioni. Per esempio:

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

Questo ti permette di cercare (solo una volta) se il cast fa esattamente quello che vuoi. Questo metodo potrebbe anche essere soggetto a test, per garantire che continui a fare ciò che desideri. Inoltre, non importa quale trucco utilizzi per causare la divisione (puoi utilizzare una delle risposte qui), purché si ottenga il risultato corretto. Ovunque sia necessario dividere due numeri interi, ora puoi semplicemente chiamare Utils::dividee fidarti che fa la cosa giusta.



0

Il modo migliore per farlo è

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

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