Newsgroup: it.comp.java
Titolo: Moltiplicare int per 0.1

Salve, devo svolgere un calcolo che moltiplichi degli interi per 0.1,
ho provato ma in certi casi invece di avere come risultato 7.2 ottengo
7.199999999, credo di aver capito che ciò sia dovuto al fatto che il
calcolo viene effettuato in binario dal programma.. ma come posso
risolvere il mio problema?
grazie mille!

Elbrethril ha scritto:

In altra circostanza ho risolto arrotondando il numero subito dopo.
Ciao,
Giulio

> In altra circostanza ho risolto arrotondando il numero subito dopo.
ok, ma io devo calcolare circa 590.000 elementi e stamparli su un file,
non posso mettermi a arrotondarli tutti a mano...

 7.199999999
Mi costringi a riportare l'url :P
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Saluti
CarMas

 non posso mettermi a arrotondarli tutti a mano...
Cosa significa "a mano"? ;-)
Prova questo:
int a = ...;
bouble b = 0.1;
double result = (double)Math.round(a*b*10)/10;
Ciao,
Giulio

 writes:
E> Salve, devo svolgere un calcolo che moltiplichi degli interi per
E> 0.1, ho provato ma in certi casi invece di avere come risultato 7.2
E> ottengo 7.199999999, credo di aver capito che ciò sia dovuto al
E> fatto che il calcolo viene effettuato in binario dal programma
Esatto. Il problema  è tutto lì. Un decimo  rappresentato in binario è
un numero periodico.
E> .. ma
E> come posso risolvere il mio problema?
Devi arrotondare (ovvio che non lo fai tu, lo fa Java per te).
Usualmente  una  precisione   sufficiente  per  l'arrotondamento  alla
i-esima cifra decimale  si ha (se non ricordo  male) moltiplicando per
la  (i-1)esima potenza  di  10, aggiungendo  0.5,  prendendo la  parte
intera e quindi dividendo per la (i-1)esima potenza di 10.
C'è  comunque una  disciplina chiamata  calcolo numerico  che affronta
anche  questo problema  dandoti  le basi  teoriche  per arrotondare  i
valori  in   modo  da  garantirti   che  l'errore  sia   entro  limiti
accettabili.
-- 
 /\           ___
/___/\_|_|\_|__|___Gian Uberto Lauri_____
  //--\| | \|  |   Integralista GNUslamico
\/                 e coltivatore diretto di Software

Elbrethril ha scritto:

Usa java.math.BigDecimal per i calcoli dove richiedi una precisione
arbitraria.

 writes:
VV>  java.math.BigDecimal
Ocio che  anche se la classe  suggerita da Vincent è  Comoda e pratica
(anche se  forse lenta),  da sola non  RISOLVE i problemi  inerenti il
floating point.


 floating point.
Beh, è lì apposta per rappresentare decimali con precisione
arbitraria e implementa le operazioni aritmetiche (con la notazione a
metodi che ti piace tanto... :P).
Questo è quello che gli serve. No?

> Devi arrotondare (ovvio che non lo fai tu, lo fa Java per te).
E ovviamente l'ha fatto Java per me!
Grazie mille ragazzi!

> floating point.
VV> Beh, è lì apposta per rappresentare decimali con precisione
VV> arbitraria e implementa le operazioni aritmetiche (con la
VV> notazione a metodi che ti piace tanto... :P).  Questo è quello che
VV> gli serve. No?
Mig  tant.   Aiuta  a  risolvere  i  problemi  ed  è  sicuramente  più
maneggevole di un double (per non parlare dei float). Ma non ELIMINA i
problemi, e  la frase  "The BigDecimal class  gives its  user complete
control over rounding behavior, forcing the user to explicitly specify
a rounding behavior for operations capable of discarding precision" la
dice lunga a parer mio: o sai quello che fai o rischi di fare errori.
Dipende in ogni caso cosa devi fare. Ma non hanno dedicato libri interi
al calcolo in virgola mobile per il solo gusto di usare \TeX :)
// Esempio stupido, ma non troppo.
import java.math.BigDecimal;
public class ProveFloat {
    public static final void main(final String[] args) {
	float af1=72.0f;
	float bf1=0.1f;
	double ad1 = 72.0;
	double bd1 =0.1;
	BigDecimal ab1= new BigDecimal(72.0);
	BigDecimal bb1=new BigDecimal(0.1);
	System.out.println(af1*bf1);
	System.out.println(ad1*bd1);
	System.out.println(ab1.multiply(bb1).toString());
	float af2=7.2f;
	double ad2 = 7.2;
	BigDecimal ab2= new BigDecimal(7.2);
	System.out.println(af2*bf1);
	System.out.println(ad2*bd1);
	System.out.println(ab2.multiply(bb1).toString());
    }
}
Output:
7.2000003
7.2
7.2000000000000003996802888650563545525074005126953125000
0.71999997
0.7200000000000001
0.7200000000000000577315972805081410881049782669874130146\
  60706603482787091508043886278755962848663330078125
(l'ultimo risultato è una riga sola molto lunga, ho inserito un \ ed
un paio di spazi per rimanere nei margini e renderlo un po' meno
sgradevole agli occhi)


 Mig  tant.   Aiuta  a  risolvere  i  problemi  ed  č  sicuramente  piů
perche' non devi usare il costruttore che prende i double altrimenti
erediti l'imprecisione.
#  The results of this constructor can be somewhat unpredictable. One might
assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which
is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it
is actually equal to
0.1000000000000000055511151231257827021181583404541015625. This is because
0.1 cannot be represented exactly as a double (or, for that matter, as a
binary fraction of any finite length). Thus, the value that is being passed
in to the constructor is not exactly equal to 0.1, appearances
notwithstanding.
# The String constructor, on the other hand, is perfectly predictable:
writing new BigDecimal("0.1") creates a BigDecimal which is exactly equal
to 0.1, as one would expect. Therefore, it is generally recommended that
the String constructor be used in preference to this one. 
ripeti l'esercizio con il costruttore che prende uno String e i risultati
saranno molto migliori.

 // Esempio stupido, ma non troppo.
Attenzione: io ho parlato di "decimali con precisione arbitraria", la
classe serve a questo. Nell'esempio non fai uso di precisione
arbitraria.

 saranno molto migliori.
In alternativa specifichi la precisione del numero.

> // Esempio stupido, ma non troppo.
VV> Attenzione: io ho parlato di "decimali con precisione arbitraria",
VV> la classe serve a questo. Nell'esempio non fai uso di precisione
VV> arbitraria.
No.  Non e` quello il problema.
Il  problema è  quello indicato  nell'altra risposta  al  messaggio di
marcopar, ed è dovuto al fatto che la rappresentazione di 0.1 e 7.2 in
floating  point  è  periodica  e  quindi  quando  vengono  generati  i
BigDecimal  si parte già  da rappresentazioni  non esatte  del numero.
Avrei dovuto  avere un  po' di  più di tempo  per leggere  la documen-
tazione.


> Mig tant.  Aiuta a risolvere i problemi ed č sicuramente piů
m> perche' non devi usare il costruttore che prende i double
m> altrimenti erediti l'imprecisione.
m> # The results of this constructor can be somewhat
m> unpredictable.
Unpredictable non direi :), comunque hai pienamente ragione.


... il corsino di Calcolo numerico l'avrei anche fatto...
ma se ti dovessi dire quello che mi è rimasto in testa  ....
ho provato con il metodo
b=0.1
((double1 - double2)*b*10)/10
e va tutto bene se necessito di un'approssimazione alla prima cifra
decimale..
però in un'altra formula dovrei avere un'approssimazione maggiore..
ho provato con:
((double1 - double2)*b*100)/100
però in certi casi mi ritorna il problema che invece di darmi come
soluzione 1.75 mi da 1.749999999999...
ma allora quella formula funziona solo con una cifra?

 ma se ti dovessi dire quello che mi è rimasto in testa  ....
Neanche l'arrotondamento?

> Neanche l'arrotondamento?
mmm.... sinceramente no.. cambia molto?

 mmm.... sinceramente no.. cambia molto?
Ripeto, usa BigDecimal scalando ad una precisione arbitraria.
E' quello che ti serve.

 E' quello che ti serve.
ok, ho guardato la documentazione sun per BigDecimal, ma non ho capito
una cosa,
se devo applicare funzioni tipo log(n) oppure e^(n)  non le posso usare
con BigDecimal?

> E' quello che ti serve.
E> ok, ho guardato la documentazione sun per BigDecimal, ma non ho
E> capito una cosa, se devo applicare funzioni tipo log(n) oppure
E> e^(n) non le posso usare con BigDecimal?
Ti devi  riscrivere la funzione  replicando il lavoro che  viene fatto
nei  processori :),  si usano  approssimazioni  polinomiali.  Dovresti
trovare tutto sul testo che hai usato per il corso di calcolo numerico.
E  BigDecimal o  non BigDecimal,  nel calcolo  FP  scientifico bisogna
stare attenti.


 risolvere il mio problema?
La butto li', che ne dici usare un CAS (Computer Algebra System) ?
Per java mi e' piaciuto molto yacas:
http://www.xs4all.nl/~apinkus/yacas.html
Puoi provare anche online:
http://yacas.sourceforge.net/yacasconsole.html
In> 72 * 0.1
7.2
--
Marco
-- 
Posted via a free Usenet account from 
http://www.teranews.com