0Pricing
Java Academy · Lezione

BigDecimal per i calcoli finanziari

Utilizzi BigDecimal per evitare errori di precisione in virgola mobile nei calcoli monetari e fiscali.

BigDecimal per i calcoli finanziari è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.

BigDecimal per i calcoli finanziari

I tipi a virgola mobile (double, float) non possono rappresentare esattamente tutti i valori decimali a causa della rappresentazione binaria. Per il denaro e le imposte, usi BigDecimal.

Il problema della virgola mobile

La rappresentazione binaria a virgola mobile introduce piccoli errori di arrotondamento. Nelle applicazioni finanziarie questi errori si accumulano e causano bug reali.

double price = 0.1 + 0.2;
System.out.println(price);          // 0.30000000000000004 (WRONG!)
System.out.println(price == 0.3);   // false

// Real bug: total never equals expected
double total = 0;
for (int i = 0; i < 10; i++) total += 0.1;
System.out.println(total); // 0.9999999999999999

Creare BigDecimal in modo sicuro

Crei sempre BigDecimal a partire da una String, non da un double. Usare il costruttore che accetta un double eredita l'imprecisione della virgola mobile.

import java.math.BigDecimal;

// WRONG: double constructor
BigDecimal wrong = new BigDecimal(0.1);
System.out.println(wrong); // 0.1000000000000000055511...

// CORRECT: String constructor
BigDecimal correct = new BigDecimal("0.1");
System.out.println(correct); // 0.1

// Or use valueOf (also safe)
BigDecimal safe = BigDecimal.valueOf(0.1);
System.out.println(safe); // 0.1

Aritmetica di base con BigDecimal

BigDecimal usa chiamate a metodi per l'aritmetica: add(), subtract(), multiply(), divide(). Questi metodi restituiscono nuove istanze di BigDecimal (immutabili).

import java.math.BigDecimal;

BigDecimal price = new BigDecimal("19.99");
BigDecimal tax   = new BigDecimal("0.08");
BigDecimal qty   = new BigDecimal("3");

BigDecimal subtotal = price.multiply(qty);
BigDecimal taxAmount = subtotal.multiply(tax);
BigDecimal total = subtotal.add(taxAmount);

System.out.println(subtotal);  // 59.97
System.out.println(taxAmount); // 4.7976
System.out.println(total);     // 64.7676

Modalità di arrotondamento

RoundingMode controlla il modo in cui BigDecimal arrotonda. Modalità principali:

  • HALF_UP — arrotondamento standard (0.5 viene arrotondato per eccesso)
  • HALF_EVEN — arrotondamento del banchiere (0.5 viene arrotondato al numero pari più vicino)
  • DOWN — tronca verso zero
  • CEILING — arrotonda verso l'infinito positivo
import java.math.*;

BigDecimal val = new BigDecimal("2.565");

System.out.println(val.setScale(2, RoundingMode.HALF_UP));   // 2.57
System.out.println(val.setScale(2, RoundingMode.HALF_EVEN)); // 2.56 (banker's)
System.out.println(val.setScale(2, RoundingMode.DOWN));      // 2.56
System.out.println(val.setScale(2, RoundingMode.CEILING));   // 2.57

Divisione e scala

La divisione con BigDecimal richiede di specificare la scala e la modalità di arrotondamento per evitare ArithmeticException nel caso di decimali non terminanti.

import java.math.*;

BigDecimal revenue = new BigDecimal("1000.00");
BigDecimal months  = new BigDecimal("3");

// Without scale → ArithmeticException (non-terminating decimal)
try {
    revenue.divide(months);
} catch (ArithmeticException e) {
    System.out.println("Need to specify scale!");
}

// Correct: specify scale and rounding
BigDecimal monthly = revenue.divide(months, 2, RoundingMode.HALF_UP);
System.out.println(monthly); // 333.33

Confrontare BigDecimal

Usi compareTo() per confrontare i valori, non equals(). equals() considera la scala: 2.0 e 2.00 NON sono uguali secondo equals(), ma SONO uguali secondo compareTo().

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("2.00");

System.out.println(a.equals(b));        // false (different scale)
System.out.println(a.compareTo(b));     // 0 (same value)
System.out.println(a.compareTo(b) == 0); // true

// For sorting in collections
import java.util.*;
List<BigDecimal> prices = Arrays.asList(
    new BigDecimal("3.50"), new BigDecimal("1.00"), new BigDecimal("2.75")
);
Collections.sort(prices);
System.out.println(prices); // [1.00, 2.75, 3.50]

MathContext per le cifre significative

MathContext specifica la precisione (cifre significative) e la modalità di arrotondamento. Lo usi quando ha bisogno di una precisione coerente in cifre significative anziché in posizioni decimali.

import java.math.*;

MathContext mc = new MathContext(4, RoundingMode.HALF_UP);

BigDecimal a = new BigDecimal("1234567");
BigDecimal b = new BigDecimal("3");

BigDecimal result = a.divide(b, mc);
System.out.println(result); // 4.115E+5 (4 significant digits)

// DECIMAL32, DECIMAL64, DECIMAL128 are standard MathContexts
BigDecimal precise = new BigDecimal("355").divide(
    new BigDecimal("113"), MathContext.DECIMAL64);
System.out.println(precise); // 3.141592920353982...

Esempio di carrello

Un calcolo completo del carrello della spesa con BigDecimal: voci, imposta, sconto e totale finale.

import java.math.*;

record LineItem(String name, BigDecimal price, int qty) {
    BigDecimal subtotal() {
        return price.multiply(new BigDecimal(qty));
    }
}

var items = List.of(
    new LineItem("Laptop",  new BigDecimal("999.00"), 1),
    new LineItem("Case",    new BigDecimal("29.99"),  2),
    new LineItem("Charger", new BigDecimal("49.99"),  1)
);

BigDecimal subtotal = items.stream()
    .map(LineItem::subtotal)
    .reduce(BigDecimal.ZERO, BigDecimal::add);

BigDecimal taxRate = new BigDecimal("0.09");
BigDecimal tax = subtotal.multiply(taxRate).setScale(2, RoundingMode.HALF_UP);
BigDecimal total = subtotal.add(tax);

System.out.println("Subtotal: " + subtotal);
System.out.println("Tax:      " + tax);
System.out.println("Total:    " + total);

Stripe: valuta in centesimi

I gestori dei pagamenti come Stripe memorizzano gli importi come centesimi interi per evitare completamente i problemi dei decimali. La conversione tra centesimi e importi da visualizzare è un modello comune.

import java.math.*;

// Store as cents (long) for database / API
long amountCents = 999_99L; // $999.99

// Convert to BigDecimal for display
BigDecimal amount = BigDecimal
    .valueOf(amountCents)
    .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);

System.out.println("Amount: $" + amount); // Amount: $999.99

// Convert user input back to cents
BigDecimal input = new BigDecimal("49.95");
long cents = input.multiply(new BigDecimal("100"))
    .setScale(0, RoundingMode.HALF_UP).longValueExact();
System.out.println("Cents: " + cents); // Cents: 4995

Quando usare BigDecimal invece di double

Scelga il tipo adatto al caso d'uso:

  • BigDecimal: importi finanziari, imposte e fatture, quando è importante una rappresentazione decimale esatta
  • double: calcoli scientifici, grafica e ML, quando la velocità è importante e piccoli errori sono accettabili
  • int/long in centesimi: API di pagamento e memorizzazione del denaro nei database

Verifica rapida

Quale metodo di confronto di BigDecimal dovrebbe usare per verificare se due valori BigDecimal sono numericamente uguali, indipendentemente dalla scala?

Riepilogo: BigDecimal per i calcoli finanziari

Punti chiave:

  • double/float causano errori di arrotondamento: non li usi mai per il denaro
  • Crei BigDecimal da String o con BigDecimal.valueOf(), non da double
  • Usi add(), subtract(), multiply() e divide() per l'aritmetica
  • Specifichi sempre la scala e RoundingMode durante la divisione
  • Usi compareTo() per verificare l'uguaglianza, non equals()
  • Valuti la possibilità di memorizzare il denaro come centesimi interi per database e API

Domande Frequenti

La lezione «BigDecimal per i calcoli finanziari» è gratuita?

Sì — il testo completo di «BigDecimal per i calcoli finanziari» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.

Cosa imparerò in «BigDecimal per i calcoli finanziari»?

Utilizzi BigDecimal per evitare errori di precisione in virgola mobile nei calcoli monetari e fiscali. Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Java Academy?

Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «BigDecimal per i calcoli finanziari»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Java Academy?

Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Elementi essenziali della classe Math
  2. Aritmetica degli interi e overflow
  3. BigDecimal per i calcoli finanziari
  4. NumberFormat e printf
← Torna a Java Academy