Discussione:
moltiplicazioni tra double... sbagliate!
(troppo vecchio per rispondere)
g***@decadence.it
2005-11-20 20:33:13 UTC
Permalink
Ciao a tutti. :)

ditemi che non sono pazzo... come è possibile questo?
dopo una domenica pomeriggio a controllare del codice che produce
risultati errati mi ritrovo a fronteggiare dei problemi di arrotondamento
nelle *moltiplicazioni*...

riassumendo in breve, anche il più semplice dei programmi non genera il
risultato che dovrebbe.
il mio codice esegue 2 conteggi su dati estratti da sql e deve verificare
se il totale dei due conteggi è uguale (un saldo dare e un saldo avere,
insomma)
facendo il debug riga per riga, saltano fuori strane cifre.

allora scrivo del codice da zero tanto per fare una prova, metto due
numeri a caso, il codice deve fare la moltiplicazione di 3.0 * 30.1, che
anche a mente sono in grado di risolvere a 90.3 eppure java mi calcola un
valore diverso, molto prossimo ma diverso.
ma come è possibile?
devo mettermi a controllare tutti i risultati anche delle moltiplicazioni?

questo è il codice che ho eseguito per il test.

public class Prova {
public static void main(String[] args) {
double a = 3.0;
double b = 30.1;
double c = a * b;
double d = 90.3;

System.out.println(c);

if( c == d )
System.out.println("tutto ok");
else
System.out.println("santo cielo... :(");
}
}

e l'output è:

90.30000000000001
santo cielo... :(

stesso risultato con J2SE 5.0 update 5 su Linux e su Windows e anche con
J2SE 6.0 rc61 su Linux, in tutto su tre macchine diverse.

a me non sembra per niente normale, eppure non sto facendo nulla di
speciale... capita solo a me?

ciao e grazie
gl
g***@decadence.it
2005-11-20 21:28:38 UTC
Permalink
ciao ancora :)

mi rispondo da solo citando quello che ho trovato su google.

http://groups.google.it/group/comp.lang.java.programmer/browse_frm/
thread/2c8ac3c0614197d/60282dbeca39b64c

quindi è così che funziona.
non so come mai me ne sono accorto solo ora, ma sta di fatto che non si
possono confrontare con certezza due operandi di un'operazione e il loro
risultato.

ciao
gl :)
Roberto Bagnoli
2005-11-21 07:48:36 UTC
Permalink
Post by g***@decadence.it
Ciao a tutti. :)
ditemi che non sono pazzo... come è possibile questo?
dopo una domenica pomeriggio a controllare del codice che produce
risultati errati mi ritrovo a fronteggiare dei problemi di arrotondamento
nelle *moltiplicazioni*...
Tutto sotto controllo! ;)
E' ben noto che le operazioni tra double risentono di questi
"problemi" di arrotondamento, intrinsechi alla notazione numerica
in virgola mobile su elaboratore (e quindi *non* e' un problema solo di Java).

Per ottenere risultati corretti *devi* usare le classi
java.math.BigInteger e java.math.BigDecimal.


Ciao
Roberto
Gian Uberto Lauri
2005-11-21 10:44:42 UTC
Permalink
RB> Per ottenere risultati corretti *devi* usare le classi
RB> java.math.BigInteger e java.math.BigDecimal.

Oppure smazzarsi la teoria del calcolo numerico e le tecniche per
tenere l'errore sotto controllo :)
--
/\ ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
//--\ | | \| | Integralista GNUslamico
\/ e allevatore di bug da competizione
DKano
2005-11-21 12:08:40 UTC
Permalink
Post by Gian Uberto Lauri
Oppure smazzarsi la teoria del calcolo numerico e le tecniche per
tenere l'errore sotto controllo :)
E' quello che hanno fatto i simpatici amici di java.math.*, no? ;-)

Certo che il numero di domande sui floating point che danno risultati
"errati" è preoccupante... una volta era una delle prime cose che ti
insegnavano.
bye
DKano
Gian Uberto Lauri
2005-11-21 12:49:33 UTC
Permalink
Long count = 12.19.12.14.13; tzolkin = 4 Ben; haab = 11 Ceh.
I get words from the Allmighty Great Gnus that
D> Certo che il numero di domande sui floating point che danno
D> risultati "errati" è preoccupante... una volta era una delle prime
D> cose che ti insegnavano.

Esatto, e prima di farti toccare una tastiera vera :).
--
/\ ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
//--\ | | \| | Integralista GNUslamico
\/ e allevatore di bug da competizione
g***@decadence.it
2005-11-21 15:01:39 UTC
Permalink
Post by Gian Uberto Lauri
D> Certo che il numero di domande sui floating point che danno
D> risultati "errati" è preoccupante... una volta era una delle prime
D> cose che ti insegnavano.
Esatto, e prima di farti toccare una tastiera vera :).
beh, che vi devo dire...
nei tempi che furono sapevo anche eseguire le divisioni in binario (con
l'ausilio di carta e penna)
sta di fatto che da un linguaggio di alto livello, mi sembra lecito
aspettarsi un minimo di sostegno. evidentemente non è così.

grazie a tutti :)

ciao
gl :)
Gian Uberto Lauri
2005-11-21 15:21:02 UTC
Permalink
gi> beh, che vi devo dire... nei tempi che furono sapevo anche
gi> eseguire le divisioni in binario (con l'ausilio di carta e penna)
gi> sta di fatto che da un linguaggio di alto livello, mi sembra
gi> lecito aspettarsi un minimo di sostegno. evidentemente non è così.

Non può essere così.

Le operazioni sugli interi sono una cosa, quelle in floating point
un'altra. Ma proprio un'altra. Cominciamo col fatto che i computer
lavorano in una base che è una potenza di due, per cui già
rappresentare un valore banale com 0.1 in decimale da qualche
problemino:

Decimale: 0.1
Binario : 0.00011001100110011001100110011001100110011

che come vedi è periodico, quindi non può essere rappresentato
correttamente.

Poi ci sono i problemi di perdita di precisione con le
moltiplicazioni, il fatto che i numeri floating point non sono
distribuiti uniformemente (tra 1e-28 e 2e-20 non c'è la stessa
distanza che c'è tra 1e28 e 2e28).

A Ingegneria, e presumo anche a Fisica e nelle altre facoltà
scientifiche dove fanno risolvere per problemi per via numerica,
venivano dibattute in un corso apposta che peraltro era il primo che
si affrontava sulle cose relative alla programmazione.

Quando si fanno programmi scientifici si considerano valide solo poche
cifre decimali e si procede ad arrotondamenti applicando tecniche
apposite per contenere l'errore entro limiti previsti (quelli che
appunto ti fanno considerare buone solo alcune delle cifre decimali).

Dicevo, con gli interi è una cosa, con i decimali un'altra. Quando si
fanno calcoli finanziari non si usano i floating point, ma
rapprezentazioni con un numero finito di cifre decimali, praticamente
deli interi "con la virgola spostata".
--
/\ ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
//--\ | | \| | Integralista GNUslamico
\/ e allevatore di bug da competizione
CarMas
2005-11-21 16:06:22 UTC
Permalink
Post by Gian Uberto Lauri
Non può essere così.
Le operazioni sugli interi sono una cosa, quelle in floating point
un'altra.
Aggiungiamoci anche un altro esempietto:

double a=2.0;
double b=Double.MAX_VALUE;
double m=(a*b)/a;
System.out.println(m);

Prova a farlo girare e te ne accorgi :D

Saluti
CarMas
Gian Uberto Lauri
2005-11-22 10:21:20 UTC
Permalink
Long count = 12.19.12.14.14; tzolkin = 5 Ix; haab = 12 Ceh.
I get words from the Allmighty Great Gnus that
C> double a=2.0; double b=Double.MAX_VALUE; double m=(a*b)/a;
C> System.out.println(m);

Questa è crudelitudinevolezza! :), anche gli interi, una volta che
sono andati in overflow non sanno più da dove sono partiti e
moltiplicanto Double.MAX_VALUE per 2 ottieni Inf perché vai in
overflow.
--
/\ ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
//--\ | | \| | Integralista GNUslamico
\/ e allevatore di bug da competizione
CarMas
2005-11-22 13:04:19 UTC
Permalink
Post by Gian Uberto Lauri
anche gli interi, una volta che
sono andati in overflow non sanno più da dove sono partiti
Vero, ma si era partiti dai double e io ho creato l'esempio sui double :P

Saluti
CarMas
Dimitri De Franciscis
2005-11-21 08:40:05 UTC
Permalink
Breve ma ottimo articolo:
http://www.nvitalia.com/articoli/Floating_Point/4.htm

E un po' di (s)considerazioni personali:
http://www.megadix.org/calcoli_impossibili.html
--
-- + Setaceous Pig + --
http://www.megadix.org/
http://www.jroller.com/page/megadix/
CarMas
2005-11-21 09:54:59 UTC
Permalink
Post by g***@decadence.it
santo cielo... :(
http://docs.sun.com/source/806-3568/ncg_goldberg.html

Saluti
CarMas
Blade
2005-11-21 15:50:12 UTC
Permalink
Il problema e' che credi che i double siano numeri reali. In questo ti
sbagli ed il problema sta' li'.
Luca
2005-12-03 11:54:41 UTC
Permalink
Anche a me dava lo stesso errore, poi ho usato i float e ho risolto... ma
non so perché.
Post by g***@decadence.it
Ciao a tutti. :)
ditemi che non sono pazzo... come è possibile questo?
dopo una domenica pomeriggio a controllare del codice che produce
risultati errati mi ritrovo a fronteggiare dei problemi di arrotondamento
nelle *moltiplicazioni*...
riassumendo in breve, anche il più semplice dei programmi non genera il
risultato che dovrebbe.
il mio codice esegue 2 conteggi su dati estratti da sql e deve verificare
se il totale dei due conteggi è uguale (un saldo dare e un saldo avere,
insomma)
facendo il debug riga per riga, saltano fuori strane cifre.
allora scrivo del codice da zero tanto per fare una prova, metto due
numeri a caso, il codice deve fare la moltiplicazione di 3.0 * 30.1, che
anche a mente sono in grado di risolvere a 90.3 eppure java mi calcola un
valore diverso, molto prossimo ma diverso.
ma come è possibile?
devo mettermi a controllare tutti i risultati anche delle moltiplicazioni?
questo è il codice che ho eseguito per il test.
public class Prova {
public static void main(String[] args) {
double a = 3.0;
double b = 30.1;
double c = a * b;
double d = 90.3;
System.out.println(c);
if( c == d )
System.out.println("tutto ok");
else
System.out.println("santo cielo... :(");
}
}
90.30000000000001
santo cielo... :(
stesso risultato con J2SE 5.0 update 5 su Linux e su Windows e anche con
J2SE 6.0 rc61 su Linux, in tutto su tre macchine diverse.
a me non sembra per niente normale, eppure non sto facendo nulla di
speciale... capita solo a me?
ciao e grazie
gl
Gian Uberto Lauri
2005-12-12 10:07:24 UTC
Permalink
Long count = 12.19.12.15.14; tzolkin = 12 Ix; haab = 12 Mac.
I get words from the Allmighty Great Gnus that
L> Anche a me dava lo stesso errore, poi ho usato i float e ho
L> risolto... ma non so perché.

Magari studiandosi la teoria che c'è sotto il calcolo numerico
(personalmente la trovo pallosetta) si capisce che diavolo succede.

Non è roba banale, per nulla.
--
/\ ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
//--\ | | \| | Integralista GNUslamico
\/ e allevatore di bug da competizione
Loading...