Newsgroup: it.comp.lang.javascript
Titolo: Arrotondamento Strano!

La seguente funzione usata per arrotondare un numero a 2 cifre decimali:
function round_ecc(number,X)
    {X = (!X ? 2 : X);
    return Math.round(number*Math.pow(10,X))/Math.pow(10,X);}
a volte mi da dei risultati molto strani.
Ad ex:
alert(round_ecc(105.825,2)); //=105.83
alert(round_ecc(115.825,2)); //=115.83
alert(round_ecc(125.825,2)); //=125.83
alert(round_ecc(135.825,2)); //=135.82
alert(round_ecc(145.825,2)); //=145.82
alert(round_ecc(155.825,2)); //=155.82
alert(round_ecc(165.825,2)); //=165.83
a volte per eccesso a volte per difetto.
Ma come è possibile?
Esiste una funzione che arrotonda sempre in eccesso nel caso del 5 finale?
Grazie

 a volte mi da dei risultati molto strani.
Prova a fare:
alert(105.825*100)
alert(135.825*100)
e capirai il perche'.
Si tratta sempre della questione relativa alle operazioni binarie in 
virgola mobile.
-- 
C'ya,
ZER0
  :. job profile - coder.gfxer.webDesigner
"When you have eliminated the impossible, whatever remains,
however improbable, must be the truth." (S.H.)

 ha scritto nel messaggio
news:MPG.18d7c6107...@130.133.1.4...


 è risolvibile?
Non in senso stretto. Senza entrare troppo nello specifico, il tutto e' 
riconducibile all'aritmetica binaria. I numeri a virgola mobile vengono 
rappresentati in sequenza di bit "finiti", ovviamente. E' cio' che 
causa, durante le operazioni il comportamento di cui sopra.
Prova infatti a visualizzare anche solo il esadecimale (in binario 
magari sarebbe meno chiaro) il tuo numero, e renderai conto che la 
macchina lo intepreta come se fosse periodico.
var n=135.825;
alert(n.toString(16));
Nei browser recenti, potresti usare il metodo .toFixed() per ottenere 
cio' che vuoi:
var n=135.825;
alert(n.toFixed(2));
L'unico problema e' che su browser diversi ti da' risultati diversi (IE 
135.83, Mozilla 135.82), senza contare che cosi' escludi tutti i browser 
meno recenti che non supportano tale metodo.
Se fossi al momento lucido, potrei cercare di approfondire la questione, 
ma al momento sono in stato febbrile, ergo rischierei di dirti fischi 
per fiaschi :)


 Ad ex:
Mai usare Math.pow() quando è possibile evitarlo, perché è una funzione che
approssima i calcoli, ma su tutti i computer e tutti i linguaggi, non solo
in JS... hai presenti gli sviluppi di Taylor? Ecco... :)
Un modo molto più preciso per arrotondare alla seconda cifra dopo la
virgola, come introduceva anche ZER0, è questo:
arrotondato = Math.round(numero * 100) / 100
Se devi fare calcoli con i numeri, e vuoi evitare di perdere precisione,
moltiplicali tutti quanti per un fattore (uguale per tutti) tanto grande da
renderti tutti i numeri interi, e pure i risultati che presumibilmente
otterrai. Fai quindi i tuoi calcoli sui numeri interi, e poi dividi il
risultato per il fattore iniziale, volendo anche già arrotondato...
A presto.
Ðarius.
www.darius.it

 otterrai.
Ricorda che pero' la grandezza dei numeri su cui puoi lavorare e' 
"finita". Se i numeri con cui lavori sono abbastanza grandi, rischi di 
avere cmq dati falsati in quanto JS raggiunto il suo limite non opera 
piu' su tali dati (ma non va in "owerflow" in senso stretto, visto che 
non ti avverte).
Bisogna vedere l'ordine di grandezza dei dati che manipoliamo e dei 
risultati che otteniamo.


 risultati che otteniamo.
Già... i numeri minori di 2^1024 risultano dei numeri, da lì in avanti si
arriva ad Infinity... In genere, se non sono *troppo* distanti o troppo
vicini tra di loro, non ci sono problemi, altrimenti si perde precisione e
si arrotonda:
( (10+1000000)  -1000000)  = 10, e va bene
( (10+2e100)       -2e100)  invece fa 0 e non va più tanto bene.... :)
A presto.
Ðarius.
www.darius.it

 non ti avverte).
Poi, ad essere precisi, non si tratterebbe nemmeno proprio di overflow, che
nel floating point č un concetto che viene un po' a mancare rispetto alla
gestione dei numeri interi... č piuttosto un arrotondamento quello che
avviene, tale che le cifre meno significative vanno perse...
Coi numeri interi, invece, ci sono i bit che ci sono, e quando si fanno dei
calcoli con numeri troppo grossi, si arriva al punto in cui non bastano piů
i bit e si perdono le cifre *piů* significative del numero, il che č invece
un problema molto piů grave, infatti si piantano i programmi con overflow
error.... :)
buona giornata.. :)
Đarius.
www.darius.it

 gestione dei numeri interi..
Riferito alla parte in virgola mobile ovviamente.
Ma io parlavo della grandezza dei dati da manipolare.
La parte mobile e' sempre una questione di arrotondamento, quello a cui 
pero' facevi accenno tu era di moltiplicare i numeri per un altro numero 
sufficientemente grande da far risultare il primo intero. La 
fattibilita' di questo metodo, pero', dipende appunto dall'ordine di 
grandezza dei dati e dei loro risultati cosi' ottenuti. Perche' si 
rischia di andare in "overflow" (sempre tra virgolette).


 vicini tra di loro, non ci sono problemi,
D'accordo, ma e' un po' empirica la cosa. :) Per me gia' quando un:
n++;
Mi da' lo stesso risultato di "n", significa che c'e' qualcosa che non 
va, e che non posso "permettermi" di continuare oltre con i calcoli.
Poco m'importa se poi un:
n+=1000;
Da' un risultato corretto.. Qualche certezza di cui servirsi in 
programmazione serve. ;)


 va, e che non posso "permettermi" di continuare oltre con i calcoli.
Non è empirica, si può calcolare lo scarto massimo tra i due numeri su cui
lavori, per sapere con certezza quando i tuoi calcoli saranno precisi e
quando no, in base al numero di bit che usi per tenere il numero in  FP:
precisione singola, o doppia, etc...
Diciamo che il floating point è stato inventato per far felici i fisici o
gli astronomi, a cui poco importa se il Sole e la Terra distano 150mln di KM
oppure 150mln e 100 metri tra loro, oppure se li si paga 1 milione al mese,
oppure un milione e 100 mila, tanto hanno sempre la testa tra le stelle...
:-P
cya! :))
Ðarius.
www.darius.it

 rischia di andare in "overflow" (sempre tra virgolette).
Ah.. si... in questo senso si...
Se comunque si va a finire in queste situazioni, sarà il momento di pensare
di modificare soltanto alcuni dei numeri (o l'ordine di grandezza) su cui si
lavora, in modo da non avere perdita di precisione durante i calcoli, e poi
ripristinare gli ordini di grandezza solo alla fine... ma è più facile
esaminare il caso specifico di volta in volta.... :)
se sarò mai ricco come Bill Gates e dovrò contare i miei fondi in qualche
moneta vittima dell'inflazione come un tempo i Dinari yugoslavi, ci farò di
nuovo un pensierino.. ^___^
Tchüß.
Ðarius.
www.darius.it

 quando no, in base al numero di bit che usi per tenere il numero in  FP:
Parlavo di numeri in generis, non necessariamente in FP.


 nuovo un pensierino.. ^___^
Se mai dovesse accadere anche a me, sicuramente non usaro' JS ne' 
tantomeno una piattaforma Wintel :)
(Mi faro' fare un hw ad hoc, ovviamente :D )


 (Mi faro' fare un hw ad hoc, ovviamente :D )
Iniziamo a farci i soldi, intanto..... :)))))
BP!
Šarius.
www.darius.it

 in JS... hai presenti gli sviluppi di Taylor? Ecco... :)
Eh, vabbe'.... per la serie "prendiamola larga" :-))
-- 
Ciao, Riccardo
------------------------------------------------------------------------
http://www.jsdir.com
 ---- Bring Your Site To Life!!!!
------------------------------------------------------------------------
http://www.dev2dev.it
 - La rete ha connesso nuove particelle - D2D006
------------------------------------------------------------------------
Per rispondere: togli il PUNTO e metti un .