Newsgroup: it.comp.lang.delphi
Titolo: Approssimazione Decimali Errata

E' possibile che con Delphi 3, su macchina che monta Windows XP, il seguente
comando:
Str (B:3:2, T)
dove B := 0.935
dia come risultato:
T = 0.93
e non come sarebbe corretto visto che la 3^ cifra decimale è 5:
T =0.94
Grazie, Federico


ABLS Team - 
www.abls.it
SINTESI S.r.l. - 
www.sintesi.com

OK ho Agguantato il Thread!!! Mi era sfuggiten....
Thanks

due casi.
Secondo me (smentitemi, vi prego) e' una logica sbagliata.
La scelta di questa logica da' come risultato
l'inaffidabilita' di Round().  Dalle funzioni e' bene
attendersi un comportamento non ambiguo.
D'altra parte, se si considerano le cifre decimali:
01234 56789
E' facile capire perche' le prime 5 approssimano normalmente
per difetto e le altre 5 per eccesso.
-- 
Andrea Laforgia - walkietalkie(at)
libero.it
"Meglio cieco che negro" (Stevie Wonder)


Ti dirò che qui in ufficio si è scatenato un vero e proprio "brainstorming"
sull'argomento :-), sulla sua validità e sulla scelta di applicare questo
metodo particolare per la funzione Round() di Delphi, che poi è lo stesso
algoritmo utilizzato da Visual Basic e InterBase (verificati)...per gli
altri linguaggi, non lo so, dovrei provare.
Più che ambiguo, definirei questo metodo di arrotondare "fuorviante". :-)
Infatti, sono sempre stato convinto che l'arrotondamento venisse applicato
con il metodo convenzionale (per eccesso quando la cifra da scartare è
uguale o maggiore di 5).
Comunque, l'esempio che hai proposto mostra solo una scelta convenzionale.
Mi spiego: supponiamo di voler arrotondare il valore 1,5 all'intero; si
tratta quindi di decidere se arrotondare a 1 o a 2. Essendo 1,5 esattamente
a metà tra 1 e 2 (poichè [1.5 - 1 = 0.5]  e  [2 - 1.5 = 0.5], distanza
uguale), la scelta di arrotondare a 1 oppure a 2 è puramente soggettiva,
poichè entrambi i metodi generano un valore che si trova alla stessa
distanza da quello intermedio.
Applicando il tuo metodo, si arrotonderebbe a 2, poichè la suddivisione è
fatta così
[...]
1.0, 1.1, 1.2, 1.3, 1.4
1.5, 1.6, 1.7, 1.8, 1.9
2.0, 2.1, 2.2, 2.3, 2.4
[...]
Siccome il valore 1.5 appartiene alla seconda metà, si arrotonda a 2.
Però, io potrei suddividere il mio intervallo di valori in questo modo:
[...]
1.1, 1.2, 1.3, 1.4, 1.5
1.6, 1.7, 1.8, 1.9, 2.0
2.1, 2.2, 2.3, 2.4, 2.5
[...]
Secondo questa suddivisione, dovrei arrotondare a 1 poichè il valore 1.5
ricade nel primo intervallo.
In conclusione, non è possibile dimostrare quale dei due metodi è corretto,
poichè la distanza tra il valore da arrotondare (1.5) e i due possibili
valori interi (1 o 2) a cui arrotondare, come detto precedentemente, è
uguale (0.5). La suddivisione degli intervalli determina la scelta del
metodo di arrotondamento (difetto o eccesso). Arrotondando per eccesso o per
difetto, supponendo di avere un numero elevato di valori intermedi da
sommare - ad esempio - porta ad un valore che si discosta, in misura minore
o maggiore, dal valore reale. L'algoritmo applicato dalla Round() di Delphi
permette, privilegiando alternativamente i due metodi, di ottenere un valore
*statisticamente* (con maggiore probabilità) vicino a quello verace e
quindi, al contrario di quello che sostieni nel messaggio quotato,
certamente più affidabile.
Sono comunque PIENAMENTE d'accordo con te che questa ambiguità, considerando
che in genere si sceglie un metodo preciso che è quello dell'arrotondamento
per eccesso, genera non poca confusione!! :-)


 per difetto e le altre 5 per eccesso.
AMP una funzione di arrotondamento dovrebbe minimizzare l'errore. Dato
un ultimo decimale di 5, e' una convenzione che venga approssimato
all'intero superiore, inferiore, o, come nel caso di Round, al numero
pari.
In Delphi 6 segnalo la presenza di Math.RoundTo e Math.SimpleRoundTo.
Suppongo, in ogni caso, che si stia parlando di unita' monetarie. In tal
caso non e' meglio usare un tipo intero come Currency? dopotutto
fornisce una risoluzione al decimillesimo.
Saluti
Paolo Arosio

 certamente più affidabile.
Secondo me bisogna distinguere gli ambiti di applicazione.
Non credo si possa parlare di "affidabilita'", quanto invece
di organicita' nel distribuire gli arrotondamenti.
Ma l'affidabilita' dipende dall'ambito di applicazione.
Per esempio, se voglio calcolare le coordinate di un cerchio e 
disegnarlo, non mi interessa che le coordinate intere calcolate
da passare alla mia putpixel() siano precise, mi basta che, nel
complesso, l'arrotondamento sia ben proporzionato.
Se, invece, ho bisogno di un particolare, preciso, arrotondamento,
allora la Round() si rivela del tutto inaffidabile.
In parole povere: Round() va bene per quelle applicazioni in 
cui c'e' bisogno di arrotondamenti grossolani, possibilmente
applicati a una quantita' consistente di dati.
Per arrotondamenti precisi, bisogna usare qualcosa di meglio.
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG


Concordo. Ho anche avuto una prova pratica di ciò. Tempo fa ho dovuto
realizzare un programma in cui mi serviva rappresentare una griglia a video;
la larghezza dell'area visuale e la distanza tra i punti della griglia erano
determinati da fattori meccanici di un impianto industriale. Ovviamente, la
rappresentazione a video, trattandosi di pixel, richiedeva un arrotondamento
di alcune variabili fisiche combinate tra loro e rappresentate da valori a
virgola mobile. Usavo sempre la Round(). L'effetto ottenuto? Una griglia che
non aveva punti equidistanti, ma che alternava distanze lunghe e corte.
Molto brutta da vedere, però la griglia terminava esattamente al bordo
dell'area visuale. Avevo risolto il problema usando una funzione di
arrotondamento personalizzata: i punti della griglia erano finalmente
equidistanti, ma terminavano prima o dopo il bordo che delimitava l'area
visuale, a seconda dell'arrotondamento scelto.
Inizialmente, non mi sono posto il problema; in seguito, comprendendo il
funzionamento della Round(), ho avuto una spiegazione logica dell'effetto
visivo che ottenevo, poichè pensavo (erroneamente) che la Round() applicasse
il "classico" arrotondamento per eccesso.
Non so perchè i linguaggi di programmazione scelgano tale algoritmo come
predefinito. Evidentemente, ci sono casi reali in cui si utilizza un tipo di
arrotondamento oppure un altro, e gli ingegneri hanno preferito scegliere
una forma neutrale.
Sono d'accordo con te nel fatto che l'algoritmo favorito dipenda dal campo
di applicazione. A livello grafico, posso assicurare che i risultati visuali
sono stati disastrosi! :-)


 una forma neutrale.
Personalmente uso Trunc dopo aver sommato 0.5 (ed eventualmente
moltiplicato per una potenza di dieci).
Saluti
Paolo Arosio

 wrote in message
fiy%7.3419$sW5.1...@news2.tin.it...

Io ti consiglio di usare un metodo di arrotondamento tutto tuo, così scegli
tu il miglior modo per arrotondare e non te la prendi con nessuni :)
Quello che io trovo più giusto è:
X.5  => Da arrotondare a X o a X+1?
Allora se la cifra prima del 5 è pari la si lascia così e quindi diviene per
difetto; se la cifra prima del 5 è dispari allora la si arrotonda per
eccesso, quindi a X+1.
Esempi:
1) 38.345  >>  diventa 38.34 perchè il 5 finale è preceduto da una cifra
pari
2) 96.655  >>  diventa 96.66 perchè il 5 finale è preceduto da una cifra
dispari
3) 3.5        >>  diventa 4 perchè il 5 è preceduto da una cifra dispari
Io all'università sia in chimica che in analisi matematica ho avuto questa
regoletta, che in fondo è una convenzione. L'importante è non affidarsi a
funzioni randomizzate perchè l'arrotondamento di uno stesso valore, eseguito
più volte, ti restituirà valori diversi. Questo potrebbe dare problemi con
valori conservati e arrotondati più volte nel tempo... con relativo
sfasamento dei risultati.