2014-12-19 15 views
6

Ho una domanda riguardante l'aritmetica in virgola mobile in java e la sua precisione. Ho fatto le mie ricerche qui e tramite Google e ho trovato alcune soluzioni, ma ho difficoltà ad implementarle nel mio progetto. Quindi in Java sto facendo uso della classe BigDecimal per ottenere i miei calcoli precisi. Si noti che le variabili sono doppie e i valori possono avere una precisione fino a 8 posizioni decimali a destra durante i calcoli. Il risultato (precisione) da visualizzare è noto e questo è ciò che memorizzerò come valore corrente. Inoltre, tutti i valori arrivano in modo dinamico (attraverso un metodo). L'argomento passato dovrebbe essere il valore corrente + la dimensione del passo.Problema di virgola mobile Java Problema

public void newValue(float value) { 

    //Clip to valid range, can't go over minimum/max value 
    value = Math.max(minimumValue, Math.min(maximumValue, value)); 

    // TODO Implement better Floating Point Arithmetic precision 

    MathContext mcI = new MathContext(0, RoundingMode.HALF_UP);  
    MathContext mcF = new MathContext(8, RoundingMode.HALF_UP); 
    BigDecimal valueBD = new BigDecimal(value, mcF); 
    BigDecimal minimumBD = new BigDecimal(minimumValue, mcF); 
    BigDecimal stepBD = new BigDecimal(step, mcF); 
    BigDecimal currentValueBD = new BigDecimal(currentValue, mcF); 


    BigDecimal totalStepsBD = valueBD.subtract(minimumBD, mcF); 

    //Ensure value is divisible by stepsize 
    totalStepsBD = totalStepsBD.divide(stepBD, mcI); 

    valueBD = stepBD.multiply(totalStepsBD, mcF); 

    valueBD = valueBD.add(minimumBD, mcF); 

    // arithmetic without using BigDecimal (old) 
    //int totalSteps = (int) ((value- minimumValue)/ step); 
    //value = totalSteps * step + minimumValue; 

    if(!(valueBD.equals(currentValueBD))) { 
    valueBD = valueBD.setScale(displayPrecision, RoundingMode.HALF_UP); 
    currentValue = valueBD.floatValue(); 
    dispatch(); 
    } 

}

Ora, funziona con alcuni valori, ma non tutti. Soprattutto quando ho problemi con le dimensioni del passo. Quindi se step = 0.1 andava bene. Se ho fatta 0,005, mi piacerebbe avere un AirthmeticException - sviluppo decimale non termina sul gradino dove

totalStepsBD = totalStepsBD.divide(stepBD, mcI); 

Quando .005 è impostato per la variabile passo, dopo aver fatto un BigDeciaml (stepBD) esce a. 0049999999 ... Non so se questo ti aiuta ma se hai qualche idea per favore fammelo sapere. Grazie.

+0

non vedo una che si definisce 'step' da nessuna parte, quindi sto supponendo che è una variabile membro alla la classe. Se è un tipo 'float' e viene assegnato 0.005, verrà salvato come .0049999999 o qualcosa di simile. Quando si assegna 'stepBD' al valore di' step', utilizza i valori 0,00499, non 0,005. Non sono sicuro se questo è il problema, ma potrebbe essere d'aiuto. – Grice

+3

Nota: non usare '.equals()' per confrontare 'BigDecimal's; per esempio, '0' e' 0.00' non sono uguali. Usa '.compareTo()' e controlla '== 0' invece. – fge

risposta

1

Passare uno String step (e uno String value) al costruttore BigDecimal. Non è possibile rappresentare con precisione 0.005 come double (o float).

BigDecimal stepBD = new BigDecimal("0.005"); // <-- works as a `String`. 

Modifica

O come indicato di seguito, utilizzare BigDecimal.valueOf(double)

BigDecimal stepBD = BigDecimal.valueOf(0.005); 
+0

Suppongo che sia meglio usare ['BigDecimal.valueOf (double)'] (http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#valueOf%28double%29) invece, così OP non deve cambiare molto il suo codice. – Tom

+1

Solo una nota qui, BigDecimal.valueOf non ha funzionato per me. Piuttosto, ho dovuto eseguire il cast di una stringa come hai mostrato nella prima soluzione. Grazie mille per il vostro aiuto!! –