2016-06-24 28 views
5

Come spiegato in molti punti (come ad esempio Why can't decimal numbers be represented exactly in binary?), non tutte le frazioni decimali possono essere rappresentate come valori in virgola mobile (come memorizzato in un float in Java).Come può Java round-trip String -> float -> String anche per (alcuni) valori non rappresentabili come float?

L'esempio tipico fornito è "0,2". Secondo questo elegante IEEE 754 Converter, lo float più vicino a 0,2 è approssimativamente 0,20000000298023224, pertanto l'analisi di "0,2" come float dovrebbe produrre questo risultato.

Tuttavia, ho notato che Java sembra essere in grado di fare l'impossibile:

String number="0.2"; 
float f = Float.parseFloat(number); 
System.out.println("Result of roundtrip String -> float -> String: "+f); 

stampe:

Risultato di String andata e ritorno -> float -> Stringa: 0.2

Test on IDeone.com

Come fa Java sapere che volevo l'uscita (arrotondata) "0,2", anziché l'uscita precisa "0,20000000298023224" come spiegato sopra?

La Javadocs of Float.toString() cercare di spiegare questo:

Quante cifre devono essere stampati per la parte frazionaria di m o di un? Ci deve essere almeno una cifra per rappresentare la parte frazionaria, e oltre a tante quante, ma solo quante più cifre necessarie per distinguere in modo univoco il valore dell'argomento dai valori adiacenti del tipo float.

Sfortunatamente, questo mi confonde ancora di più. Perché "stampare tante cifre quante sono necessarie per distinguere in modo univoco il valore dell'argomento" consente a Java di stampare "0,2"?

Idealmente, la risposta spiegherebbe anche perché è stato scelto questo algoritmo di stampa. Si tratta di fare (alcuni) viaggi di andata e ritorno, come in questo esempio? C'è un'altra motivazione?

+1

Dove è Jon Skeet quando hai bisogno di lui? Ha fatto BREXIT? – GhostCat

+0

Sapete che anche inserire 0,21 o 0,2000001 o qualcosa di simile restituisce anche 0,2? Vedi http://stackoverflow.com/questions/17464675/convert-string-to-decimal-number-with-2-decimal-places-in-java – mylenereiners

+0

Ci sono 7 zeri, 10^7 = 2^23 quindi probabilmente il Raggiunta una mantissa di 3 byte di un float di 4 byte. Quindi qui potrebbe essere ancora normale. È più spesso C e C++ che imbrogliano un po 'per avere risultati migliori (la mia impressione). –

risposta

1

Immagino che 0.2 appartenga allo "Value Set Conversion".

+0

Hm, penso che sia un'area diversa (anche se correlata). Le conversioni di set di valori sembrano essere applicabili ai risultati intermedi nei calcoli FP, non alle conversioni. – sleske

+0

Vedere §5.2 della stessa pagina. – mauretto

2

L'arrotondamento dell'output non dipende da un algoritmo di stampa. È a causa delle dimensioni di float. Se lo fai:

String fs = "0.2"; 
double f = Float.parseFloat(fs); 
System.out.println(f); 

Si ottiene:

0,20000000298023224

Test on Ideone.com

Ciò dimostra chiaramente che la stringa "0.2" viene analizzato come ,20000000298023224, ma i dati del galleggiante -type non è in grado di tenerlo, e arrotonda fino a 0,2. Il tipo di dati double è in grado di contenere questi dati e, pertanto, quando si analizza il valore come float, ma in un doppio, si ottiene l'output previsto.

+0

Quando l'ho analizzato come doppio, risultava comunque in 0.2 – 4castle

+0

No. Sul mio IDE è questo. Aspetta, ci proverò online per mostrarti. – Hackerdarshi

+0

@ 4castle Vedi questo: http://ideone.com/sjWAZS – Hackerdarshi

Problemi correlati