Lavorare con i BigDecimal

di il
1 risposte

Lavorare con i BigDecimal

Ciao,
ho letto un po' di cose su questa classe, come eseguire le operazioni, ed altro, ma ho difficoltà con le formattazioni.
Dovrei prendere di una cifra solo le prime due decimali, evitando arrotondamenti per eccesso o per difetto, che mi torna un Double, ma è possibile?

Il mio metodo:
	public static Double formatDouble(Double value) {
		if (value==null) return 0.0;
		return new BigDecimal(value).setScale(2 , BigDecimal.ROUND_DOWN).doubleValue();
	}
ho fatto dei test ma non vorrei perdere qualche casistica, così funzionerà in ogni caso?

Qui invece devo formattare a stringa un Double, sempre con 2 decimali e senza arrotondamenti per eccesso o difetto, anche qui dai test fatti mi sembra ok ma ho dei dubbi:
	ft.setImporto(metodo.getFormatter().format(dto.getImporto()));
	
	public static DecimalFormat getFormatter() {
		DecimalFormat d = new DecimalFormat();
		d.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ITALIAN));
		d.applyLocalizedPattern("###0,00");
		return d;
	}
cosa ne pensate?

1 Risposte

  • Re: Lavorare con i BigDecimal

    WinstonSmith ha scritto:


    Il mio metodo:
    	public static Double formatDouble(Double value) {
    		if (value==null) return 0.0;
    		return new BigDecimal(value).setScale(2 , BigDecimal.ROUND_DOWN).doubleValue();
    	}
    Attenzione ad alcune cose (per dire, in generale):

    1) Quando crei un BigDecimal da un double, il valore double rappresentato nel BigDecimal ha TUTTA la precisione possibile per il numero di bit del double.

    Se provi:
    double d = 12.46;
    System.out.println(d);
    System.out.println(new BigDecimal(d));
    Il primo stampa 12.46
    Ma il secondo stampa 12.46000000000000085265128291212022304534912109375 !!!

    Perché? Perché BigDecimal essendo a precisione arbitraria è in grado di rappresentare con esattezza il valore del double, che NON è 12.46 (non può esserlo) ma esattamente quello dato dal BigDecimal.

    2) Il metodo setScale(int newScale, int roundingMode) è "deprecato" dal JDK 9. Dovresti usare l'altro:
    setScale?(int newScale, RoundingMode roundingMode)

    Se usi <= JDK 8 ok, lì non è ancora deprecato ma se aggiorni già, è meglio.

    Detto questo, sì tecnicamente è corretto, perché il round DOWN sostanzialmente "tronca" i decimali senza mai fare alcuna altra logica particolare.

    Una alternativa per non usare BigDecimal è quella più classica: il double * 100, poi fai floor() poi dividi per 100. Ma ovviamente entrano in gioco i limiti del double e delle operazioni in floating-point (che comunque va ragionevolmente sempre bene).

    Nota bene che i rounding DOWN e FLOOR si comportano in maniera differente sui numeri negativi.

    WinstonSmith ha scritto:


    Qui invece devo formattare a stringa un Double, sempre con 2 decimali e senza arrotondamenti per eccesso o difetto, anche qui dai test fatti mi sembra ok ma ho dei dubbi:
    Attenzione perché se vuoi "senza arrotondamenti per eccesso o difetto", non basta. I DecimalFormat per default arrotondano con logica HALF_EVEN (è scritto nel javadoc). Quindi se vuoi arrotondare diversamente (es. DOWN), va impostato appositamente.

    P.S. nota finale: va bene riusare il DecimalFormat fornito dal tuo getFormatter() ma solo nel contesto di un singolo thread. I Number/DecimalFormat non sono thread-safe. Per usarli concorrentemente da più thread ci vuole sincronizzazione apposita.
Devi accedere o registrarti per scrivere nel forum
1 risposte