Domanda

Ho un galleggiante primitivo e ho bisogno come un doppio primitivo. Basta lanciare il galleggiante di raddoppiare mi dà strano precisione in più. Ad esempio:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

Tuttavia, se invece di casting, ho in uscita il galleggiante come una stringa, e analizzare la stringa come un doppio, ottengo ciò che voglio:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

C'è un modo migliore di andare a String e ritorno?

È stato utile?

Soluzione

Non è che sei effettivamente di ottenere una precisione ancora maggiore - è che il galleggiante non rappresentava con precisione il numero si stava puntando in origine. Il doppio è che rappresenta il galleggiante originale con precisione; toString sta mostrando i dati "extra" che era già presente.

Per esempio (e questi numeri non sono giuste, sto solo facendo le cose) si supponga di avere:

float f = 0.1F;
double d = f;

Quindi il valore di f potrebbe essere esattamente 0,100000234523. d avrà esattamente lo stesso valore, ma quando si converte in una stringa sarà "fiducia" che è preciso per una maggiore precisione, in modo da non concludere quanto prima, e vedrete le "cifre in più", che erano già lì, ma nascosta da voi.

Quando si converte in una stringa e indietro, si sta finendo con un doppio valore che è più vicino al valore della stringa che il galleggiante originale era - ma questo è solo un bene se si crede davvero che il valore della stringa è quello che si voleva davvero.

Sei sicuro che float / double sono i tipi appropriati di utilizzare qui invece di BigDecimal? Se si sta cercando di usare i numeri che hanno valori decimali precisi (ad esempio denaro), poi BigDecimal è un tipo più appropriato IMO.

Altri suggerimenti

Trovo la conversione alla rappresentazione binaria più facile da afferrare questo problema.

float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;

System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));

Si può vedere il galleggiante è espanso al doppio aggiungendo 0s alla fine, ma che la doppia rappresentazione di 0,27 è 'più accurata', quindi il problema.

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

Ciò è dovuto al contratto di Float.toString(float), che dice in parte:

  

Quante cifre deve essere stampato per   la parte frazionaria [...]? Là   deve essere almeno una cifra   rappresentano la parte frazionaria, e   al di là che, come molti, ma solo come tanti,    più cifre per quanto necessario a univocamente   distinguere il valore dell'argomento da   valori adiacenti di tipo float. Tale   è, supponiamo che x è l'esatto   valore matematico rappresentato dalla   rappresentazione decimale prodotto da   questo metodo per un diverso da zero finita   argomento f. Allora f deve essere il galleggiante   valore più vicino a x; o, se due galleggiante   I valori sono ugualmente vicino a x, allora f   deve essere uno di essi e l'almeno   significativo bit della significando di   f deve essere 0.

Ho incontrato questo problema oggi e non poteva usare refactoring per BigDecimal, perché il progetto è davvero enorme. Tuttavia ho trovato soluzione utilizzando

Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

E questo funziona.

Si noti che chiama result.doubleValue () restituisce 5.623,22998046875

Ma chiamando doubleResult.doubleValue () restituisce correttamente 5.623,23

Ma non sono del tutto sicuro se è una soluzione corretta.

Utilizzare una BigDecimal invece di float / double. Ci sono molti numeri che non può essere rappresentato come punto binario galleggianti (per esempio, 0.1). In modo che sia sempre necessario arrotondare il risultato con una precisione noto o utilizzare BigDecimal.

http://en.wikipedia.org/wiki/Floating_point per ulteriori informazioni .

ho trovato la seguente soluzione:

public static Double getFloatAsDouble(Float fValue) {
    return Double.valueOf(fValue.toString());
}

Se si utilizza float e doppia al posto di Float e Doppio utilizzare il seguente:

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}

Galleggianti, per natura, sono imprecisi e hanno sempre "problemi" pulito arrotondamento. Se la precisione è importante allora si potrebbe prendere in considerazione il refactoring l'applicazione per utilizzare decimale o BigDecimal.

Sì, i galleggianti sono computazionalmente più veloce di decimali a causa del sul supporto del processore. Tuttavia, vuoi veloce o accurata?

Per informazioni questo viene alla Voce 48 - Evitare float e double quando sono necessari valori esatti, di Effective Java 2 ° edizione di Joshua Bloch. Questo libro è pieno di roba buona e sicuramente vale la pena dare un'occhiata.

Fa questo lavoro?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top