Newsgroup: it.comp.lang.visual-basic
Titolo: BUG - Floating-point

Ciao a tutti,
SIETE A CONOSCENZA DI BACHI RELATIVI ALLE SOMMATORIE ESEGUITE CON ACCESS (16
bit) E CON DAO:
Uso, da molto tempo, una semplice Query che ha dato sempre risultati
corretti, ora però da risultati imprevedibili,
ma ..... solo se si usano cifre decimali. La query esegue una sommatoria che
doverrebe dare come risultato 0, si tratta del calocolo della giacenza di un
prodotto che viene Caricato o Scaricato.
La tebella è la seguente:
    3 campi: Utente testo 50,
                   Tipo testo 2,
                   Peso double
    Utente Tipo Peso
    a         C     0,02
    a         C     0,3
    a         C     0,005
    a         S      0,1
    a         S      0,225
    b         C     0,02
    b         C     0,3
    b         C     0,005
    b         S     0,12
    b         S     0,205
La query è questa:
SELECT DISTINCTROW Utente, Sum(Peso * IIf(Tipo="c",1,-1)) AS Somma
FROM Tabella1
GROUP BY Utente;
La query raggruppa i records per utente ed esegue la somma di Peso,
l'istruzione IIF restituisce il valore del campo peso se il campo Tipo è
uguale a "C" (carico) oppure -Peso (Scarico).
IL RISULTATO DELLA QUERY E' QUESTO
Utente Somma
    a         0
    b         2,77555756156289E-17
Anche per l'utente "b" la sommatoria da 0, invece il risultato è un numero
molto molto piccolo. NON RIESCO A VENIRNE A CAPO. I risultati errati
emergono solo in pochi casi, e comunque sempre connessi con operazioni su
numeri negativi, e soprattutto, solo quando il risultato EFFETTIVO E' 0. Se
la sommatoria è diverso da 0, positivo o negativo non importa, la query
risultata sempre corretta.
I risultati non cambiano sia che si usi Access 2 che Access 97, sia vb3 che
Vb5.
Fortunato
mad...@tin.it


secondo me si tratta di un errore di conversione da decimale a binario
perche' lui internamente lavora in virgola mobile binaria (o forse
esadecimale) e quindi esiste un errore di conversione dei tuoi dati. Visto
che b e' dell'ordine di E-17 penso che internamente lui rappresenti i numeri
in doppia precisione, ossia su 8 bytes, che danno appunto una precisione di
circa 16 cifre decimali significative (se lavorasse in semplice precisione
avresti appena solo 7 cifre significative esatte). In sostanza dovresti
sostituire i test "esatti" su 0 con dei test "approssimati" del tipo:
abs(b)<E-16. Magari fai una ponzata profonda sul problema per vedere se
veramente b deve assolutamente essere uguale spaccato a zero... in ogni caso
quando si fanno dei calcoli su numeri non interi bisogna tener conto di
questo problema.
A meno di avere la certezza assoluta che lui internamente lavori in
decimale, ma non credo proprio.
Dopo di che rimane il solito problema: ma perche' prima funzionava e adesso
no?
barbi

Grazie per la comprensione: se il problema lo consosci, lo eviti.
Infatti dopo aver cercato invano un mio errore mi sono reso conto che invece
è un GRAVE ERRORE di Microsoft.
Per il momento l'errore lo evito in questo modo:
    cdbl(Format$(Sum(....ecc..), "0.######"))
PERO' TUTTO QUESTO E' ASSURDO!!!
Nonostante continui a cercare documentazione al riguardo, non ho ancora
trovato nulla. La stessa query è stata provata da un amico con Oracle (su
PC) e da risultati corretti. Quindi è il codice di Microsoft che sbaglia.
Sempre lo stesso codice da circa 10 anni, visto che il problema è identico
per il 16 e per il 32 bit. Forse prima, con Windows 3.x funzionava, perchè
il calcolo in virgoila mobile veniva svolto dal software e non
dall'hardware.
Strano che non sia riuscito a trovare alcuna documentazione in proposito.


AVETE RAGIONE!!!
Ci ho messo un po' ma l'ho capito. In effetti questo argomrento è ampiamente
trattato nella documentazione Microsoft.
chiedo agli esperti: ci sarà successore all'IEEE 754 specification?
http://support.microsoft.com/support/kb/articles/Q182/1/96.ASP
Another confusing problem with storing floating point numbers in binary is
that some numbers, which are finite, non-repeating numbers in decimal base
10, are infinite, repeating numbers in binary. The most common example of
this is the value 0.1 and variants thereof. Although these numbers can be
represented perfectly in base 10, the same number in binary format becomes
the following repeating binary number when stored in the mantissa:
000110011001100110011 (and so on)
The IEEE 754 specification makes no special provision for any number; it
stores what it can in the mantissa and truncates the rest. This results in
an error of about -2.8E-17, or 0.000000000000000028 when stored.
Even common decimal fractions, such as decimal 0.0001, cannot be represented
exactly in binary. (0.0001 is a repeating binary fraction with a period of
104 bits). This is similar to why the fraction 1/3 cannot be exactly
represented in decimal (a repeating 0.33333333333333333333).
This explains why a simple example in Microsoft Visual Basic for
Applications
   Sub Main()
      MySum = 0
      For I% = 1 To 10000
         MySum = MySum + 0.0001
      Next I%
      Debug.Print MySum
   End Sub
will PRINT 0.999999999999996 as output. The small error in representing
0.0001 in binary propagates to the sum.
http://msdn.microsoft.com/library/devprods/vs6/visualc/vccore/_core_ieee_flo
ating.2d.point_representation_and_microsoft_languages.htm