2012-12-12 18 views
5

Eventuali duplicati:
How to iterate between 0.1f and 1.0f with 0.1f increments in Java?incrementi doppie in Java

Parte del mio programma deve utilizzare i valori all'interno di un ciclo while come:

0,1

0,2

0,3

...

0,9

quindi ho bisogno di fornire loro dentro quel ciclo. Ecco il codice:

double x = 0.0; 
while (x<=1) 
{ 
// increment x by 0.1 for each iteration 
x += 0.1; 
} 

Ho bisogno dell'uscita essere esattamente:

0,1

0,2

0,3

0,4

0,5

0,6

0,7

0,8

0,9

Ma in realtà mi dà qualcosa di simile:

0,1

0,2

0,300000000000000000000000004

0,4

0,5

0,6

0,79999999999999999999999999

0,89999999999999999999999999

0,99999999999999999999999999

+0

Sembra che tu stia aggiungendo il numero giusto. Non vedo perché questo non avrebbe funzionato. – Mukus

+2

@TejaswiRana: Non funziona perché 0.1 è in realtà qualcosa come 0.0999999999999999999999 o 0.10000000000000000001. Le frazioni decimali non possono essere rappresentate senza perdite da un doppio. – cHao

risposta

10

Benvenuti nel mondo di virgola mobile, in cui 0,1 non è 0,1. Il problema è che molti numeri, incluso 0.1, non può essere rappresentato esattamente in un double. Quindi non stai aggiungendo esattamente da 0,1 a x ogni volta attraverso il ciclo.

Un approccio è quello di utilizzare l'aritmetica intera e dividere per 10:

int i = 0; 
while (i <= 10) { 
    double x = i/10.0; 
    . . . 
    i++; 
} 

Un altro approccio è quello di fare un xBigDecimal, in cui è possibile specificare che si desidera una particolare precisione. Fondamentalmente sta facendo quello che fa il ciclo precedente (un numero intero più una scala), ma confezionato in una bella classe con un sacco di campane e fischietti. Oh, e ha una precisione arbitraria.

+0

Davvero? Quando aggiungi 0.1, non stai effettivamente aggiungendo 0.1? Ciò può comportare molti calcoli in molte applicazioni esistenti fino alla data. – Mukus

+0

@TejaswiRana: Sì. Ecco perché 'double' è solo una buona idea per i calcoli che possono tollerare l'errore di arrotondamento. Calcoli di fisica del gioco? Sicuro. I soldi? Diavolo, no. Fondamentalmente se il numero è una * misura *, i doppi sono generalmente ok; se è un * numero *, usa invece un BigDecimal o interi. – cHao

+0

Quindi, se dovessi creare un'app per le attività bancarie, che cosa utilizzerei come tipo di dati? Galleggiante? – Mukus

1

Utilizzando BigDecimal

double x = 0.0; 
    int decimalPlaces = 2;   

    while (x<=1) 
    { 

    x += 0.1; 
    BigDecimal bd = new BigDecimal(x); 
    bd = bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP); 
    x = bd.doubleValue();   

    System.out.println(x); 
    } 
0

Questo perché è possibile utilizzare il virgola mobile binario per eseguire un'aritmetica decimale precisa perché FP non può rappresentare con precisione tutti i valori decimali.

È necessario utilizzare un valore intero che rappresenta un'unità decimale decimale come centesimi o millesimi o utilizzare qualcosa come BigDecimal.

0

doppia è memorizzato in binario

galleggiante e doppie memorizzare numeri da un certo numero di cifre significative e un punto radice (come tipo di notazione scientifica). La parte delle figure significative non è sempre perfetta, perché è memorizzata come un certo numero di cifre binarie, quindi non puoi aspettarti che funzioni nel modo in cui ti aspetti. (Per una spiegazione migliore vedere http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)

considerare l'utilizzo di una classe, come BigDecimal o di una classe che implementa numeri razionali, come quelli menzionati qui - Is there a commonly used rational numbers library in Java?

Si potrebbe anche solo girare i in un intero, e il cambiamento da 1 a 10 e compensare questo nel codice.

+0

La frase di apertura è un po 'fuorviante. Ogni 'double' è un valore razionale; il problema è l'opposto: non ogni valore razionale è un valore "doppio". –

+0

Si potrebbe anche arrotondare a una cifra significativa utilizzando il codice disponibile qui. http://stackoverflow.com/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits – Shariq

+0

@TedHopp - ha cambiato la mia risposta; hai ragione. Non ho spiegato cosa intendevo per razionale - intendevo nella memoria, il numero non è rappresentato come un rapporto tra un numeratore e un denominatore. – Shariq

1

Per ottenere l'output desiderato, è possibile utilizzare DecimalFormat. Ecco alcuni esempi di codice.

import java.text.DecimalFormat; 

public class DF { 

    public static void main(String [] args) { 

    double x = 0.1; 
    DecimalFormat form = new DecimalFormat("#.#"); 
    while (x <= .9) { 
     System.out.println(Double.valueOf(form.format(x))); 
     x += 0.1; 
    } 

    } 

} 

Per quanto riguarda l'attuazione che hai ora, non v'è alcuna garanzia circa la precisione di ciò che viene stampato a causa della natura dei numeri in virgola mobile.

1

è necessario utilizzare il formattatore decimale per ottenere l'output previsto.

Di seguito si riporta il codice per la generazione l'uscita prevista:

import java.text.DecimalFormat; 


public class FloatIncrement { 

    public static void main (String args[]){ 

     double x= 0.0; 
     DecimalFormat form = new DecimalFormat("#.#");  
     while(x<0.9){ 
      x= x+0.1; 
      System.out.println("X : "+Double.valueOf(form.format(x)));   

     } 

    } 
} 
+0

Questo è un codice bello :) – squiguy

+0

@squiguy grazie per il tuo suggerimento – simbu94

Problemi correlati