Newsgroup: it.comp.lang.c++
Titolo: 0.2 + 0.2 + 0.2 != 0.6

Salve,
 
non riesco a capire l'output del seguente codice:
 
#include <iostream>
 
using namespace std;
 
int main () {
 
    if (0.2 + 0.2 + 0.2 == 0.6)
        cout << "Uguale" << endl;
    else
        cout << "Diverso" << endl;
 
    if (0.2 * 3 == 0.6)
        cout << "Uguale" << endl;
    else
        cout << "Diverso" << endl;
 
    if (0.2 + 0.2 + 0.2 == 0.2 * 3)
        cout << "Uguale" << endl;
    else
        cout << "Diverso" << endl;
 
    return 0;
}
 
Output:
 
Diverso
Diverso
Uguale (unico caso corretto)
 
Grazie
--
 
Luigi
 

> non riesco a capire l'output del seguente codice:
 
Normale comportamento dei numeri in floating-point. Se vuoi confrontarli 
devi arrotondare entrambe le parti allo stesso numero di cifre decimali 
(possibilmente poche, altrimenti potresti avere ancora risultati errati).
 
EMG
 
--
EMAG Software Homepage:     
http://www.emagsoftware.it
 
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
 
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
 
The EMG Music page:         
http://www.emagsoftware.it/emgmusic
 
 
 

 
 
Si, immaginavo, ma il problema non si pone se provo ad esempio con 0.5 o 
0.7, inoltre sono numeri molto piccoli, pensavo che la precisione di 
default fosse sufficiente.
 
Con che istruzione dovrei arrotondare in questi casi?
 

 default fosse sufficiente.
 
Non è assolutamente questione di precisione. O meglio, è questione di 
MANCANZA di.
 
0.2, 0.7, 0.5 ecc. vengono tutti trasformati in doppia precisione, cioè 
in mantissa (logaritmo di) ed esponente.
In generale è
N != (float)N;
la differenza è minore dell'epsilon macchina, ma non è detto che durante 
le operazioni di somma fra più numeri non venga amplificata. Nel tuo 
caso è esattamente quello che succede, per cui finisci con il test che 
ti restituisce false :-)
 
Per cui, come regola generale, non si fanno MAI test di uguaglianza fra 
float, perché di solito sclerano in modo imprevedibile.
 

 Con che istruzione dovrei arrotondare in questi casi?
 
Con qualcosa tipo (ma probabilmente si puň fare molto meglio):
 
#include <iostream>
 
using namespace std;
 
double dround( double num, int prec )
{
    long mul = 1;
    for ( int i = 0; i < prec; ++i ) mul *= 10;
    return long( num * mul + 0.5 ) / double( mul );
}
 
int main () {
 
    if (dround(0.2 + 0.2 + 0.2, 5) == dround(0.6, 5))
        cout << "Uguale" << endl;
    else
        cout << "Diverso" << endl;
 
    if (dround(0.2 * 3, 5) == dround(0.6, 5))
        cout << "Uguale" << endl;
    else
        cout << "Diverso" << endl;
 
    if (dround(0.2 + 0.2 + 0.2, 5) == dround(0.2 * 3, 5))
        cout << "Uguale" << endl;
    else
        cout << "Diverso" << endl;
 
    return 0;
}
 


 Con che istruzione dovrei arrotondare in questi casi?
 
io faccio sempre qualcosa del tipo:
 
#define     TOL   1.0e-06
 
float a,b ;
 
if(  fabs(a-b) < TOL )
{
   // "praticamente uguali"
}
else
{
   // "praticamente diversi"
}
 
ciao
 
Apx.
 
-- 
"Perché i Clinton hanno una sola figlia?
Perché tutti gli altri sono stati inghiottiti
da Monica Levinsky".
 

 
 
Se vuoi usare i numeri a virgola mobile come si deve, questa lettura è 
indispendabile:
http://perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf
 
 
 
Ciao  Manlio

Manlio Perillo <manlio_p...@SPAMlibero.it> ha scritto:

Addirittura O_O
Ma vale solo per C++ o vale in generale per i vari linguaggi di
programmazione?
 


Per quello che so il problema non è nel linguaggio ma nella 
rappresentazione interna adottata.
Credo che l' unico linguaggio, se non è cosi smentitemi pure, che abbia 
affrontato questo problema e lo abbia risolto adottante alcune tecniche 
tipo delta errore e numero di cifre decimali massime sia ADA
 
 

 
 
Ho visto che lo stesso problema si presenta con il C e C#, ma non con Java.
 
Ora, nel caso specifico di C++, in che modo potre risolvere il problema,
limitatamente al caso che ho posto? Tramite qualche cast?
 


 
come ho detto io no? :D



 
La soluzione di Archaeopterx è una possibile soluzione.
Un' altra potrebbe avvalersi di una libreria esterna che gestisca i 
numeri a numero fisso di cifre e/o floating
 

 
 
Facendo fabs(0.2 + 0.2 + 0.2) < TOL?
 
In pratica ho un array con dei valori decimali, li devo sommare e vedere quali
di essi da come risultato quello fissato (in questo caso 0.6).
 
Se il confronto consiste con l'essere minore di TOL ottengo anche casi in cui la
somma è minore e non è effettivamente 0.6... o forse mi sfugge qualcosa?
 

 effettivamente 0.6... o forse mi sfugge qualcosa?
 
Non so, è più probabile che qualcosa sfugga a me.
 
ciao!
 
Apx.
 
-- 
Una volta ho chiesto la differenza tra
l'incesto e l'incendio. Non credo di aver
capito troppo bene perché dopo un po' ho
dato fuoco a mia sorella (Pippo Franco)
 


 
 
-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
 


ah, P.S. in C++ si può anche fare l'overload di operator ==, 
in modo che dia risultati un po' più elastici come proponi, 
e in modo da fare dietro le quinte quel che scrivi a mano.
In realtà, salvo che uno non conosca bene a priori il 
problema e non si faccia sorprendere, la soluzione di dover 
codificare a mano la patch costringe a pensare dove si 
annidano eventuali errori, mentre l'altra dopo un po' la si 
dimentica, salvo ripresentarsi in un contesto magari un po' 
diverso, tipo un confronto che usa > o < o != e quindi 
aggira operator ==.



e come potrebbe essere una soluzione, l'ultima, se non per 
caso ? Un numero che è banale in decimale e diventa 
periodico in binario, deve comunque essere troncato. NEmmeno 
numeri tipo i BCD a precisione arbitraria (sono stringhe in 
effetti) risolvono, perché un numero periodico non è 
mappabile da nessuna parte. E pure un irrazionale.
Semplicemente, usando i float, bisognerebbe ricordarsi di 
pensare in modo matematico astratto e pensare invece in 
digitale "finito", approssimato. Per cui impostare l'intera 
logica nei punti critici in base alla gestione di 
approssimazione accettabile.


 non riesco a capire l'output del seguente codice:
...
 
La prima cosa che si impara nella programmazione:
I confronti  uguale  e diverso non funzionano con i numeri a 
virgola mobile.
 
Buono studio.

 tipo delta errore e numero di cifre decimali massime sia ADA
 
 
Falso. il problema è insito nella rappresentazione dei numeri
come già ti hanno risposto. Vero che alcuni linguaggi come
COBOL, Mathematica, bc sembrano eliminare il problema però
non lo risolvo, spostano il problema; cambiano il modo di 
rappresentare i numeri reali e cambiano solo il tipo di errori 
che possono verificarsi. E Ada non fa eccezione, sposta il 
problema. Il confronto tra due numeri reali si fa così:
 
if abs ( a - b ) < abstol ...
 
e deve essere fatto esplicitamente da un programmatore che 
sa cosa cosa sta facendo.
 
 
 

Lasciate i confronti tra numeri floating point a chi sviluppa
librerie matematiche: non è roba vostra. aumentate solo
l'entropia dell'universo.
 
Con qualche eccezione naturalmente.


Vabbè dai, obvious troll is obvious - almeno spero :/

 programmazione?
 
Dipende.
 
Vale per i numeri in virgola mobile che usano una rappresentazione 
binaria con un numero fisso di bits, in particolare le implementazioni 
che seguono lo standard IEEE 754.
 
Ma dipende poi dal linguaggio, perchè è il linguaggio che sceglie cosa 
usare per gestire i floats.
Probabilmente il 95% dei linguaggi mappa i floats ai floats gestiti dal 
processore (che nel 99.9% dei casi, credo, segue IEEE 754).
 
Ma un linguaggio può anche scegliere di fare diversamente, oppure di 
affiancare un altro tipo di dato.
 
Ad esempio GNU MP/MPFR offrono un float che usa un numero variabile di 
bits (limitato solo dalla memoria).
Python, per il tipo decimal, usa un numero float a precisione variabile 
usando una rappresentazione decimale, invece che binaria (utile per 
evitare alcuni problemi).
 
 
 
Ciao  Manlio


Aggiungo anche:
http://en.wikipedia.org/wiki/IEEE_floating_point
 
 
per una veloce panoramica.
 
I processori più diffusi al momento non implementano la rappresentazione 
decimale.
 
 
 
Ciao  Manlio

 programmazione?
 
In generale.
Dipende dalla rappresentazione FP, non dal linguaggio.
 
  bye
	av.
 

 Ho visto che lo stesso problema si presenta con il C e C#, ma non con Java.
 
Anche in Java.
 
  bye
	av.
 

 le quinte quel che scrivi a mano.
 
:-O
 
A parte che significherebbe avere una tolleranza fissa... mi sembra solo 
un modo di nascondere il problema.
Francamente non vorrei mai avere a che fare con codice simile.
 
  bye
	av.


Ho solo affermato che Ada ha adottato alcune tecniche come il delta 
errore e numero cifre decimali e questo direi che non puoi smentirmi.
Non ho mai affermato che Ada abbia risolto il problema usando la 
rappresentazione interna floating secondo lo standard IEEE, cosa 
assolutamente impossibile direi.
Se per tè non è un risolvere, ma solo un aggirare il problema, direi che 
una questione puramente filosofica
 
 
 
 
 
 

 Ho visto che lo stesso problema si presenta con il C e C#, ma non con Java.
 
In C# oltre a float e double (formato IEEE 754 a 32 e 64 bit) c'è il 
formato decimal pensato principalmente per rappresentare valute: è a 128 
bit e migliora la precisione a scapito del range. Stando alla 
documentazione la rappresentazione è esatta per numeri fino a 28 cifre.
 
E in effetti in questo caso è efficace:
 
(0.2f + 0.2f + 0.2f == 0.6f) -> False
(0.2d + 0.2d + 0.2d == 0.6d) -> False
(0.2m + 0.2m + 0.2m == 0.6m) -> True
 

 Ciao  Manlio


 av.



 
 


 
 
In haskell c'è il tipo "Rational" ;)
 
Ciao!

 Ciao!


 virgola.
 
L'avevo sentito dire anch'io, ma nell'MSDN è riportato questo:
 
"The binary representation of a Decimal value consists of a 1-bit sign, 
a 96-bit integer number, and a scaling factor used to divide the 96-bit 
integer and specify what portion of it is a decimal fraction. The 
scaling factor is implicitly the number 10, raised to an exponent 
ranging from 0 to 28."
 
Quindi il fattore di scala dovrebbe essere variabile.

 numerico (gli indici degli array sono ovviamente a caso).
 
Ho ripensato a quanto hai scritto e la tua idea va bene, in pratica il valore
con cui confrontare fabs(a, b) è il minimo dei valori dell'array che considero,
ovvero fabs(a, b) < 0.1.
 
Ciao
 


giusto ... a questo punto mi incasino anche io
Allora un esponente decimale 28, significa se non sbaglio 93 
in binario. Il che è bizzarro, perché 93 consuma 7 bit (e 
che in teoria potrebbero mappare anche 128, ossia in 
esponente decimale, 38) ... boh
 
ora 96+7+1=104 bits, che è un altra cosa bizzarra. Sono 
esattamente 13 BYTE, questo è assurdo, per qualunque 
architettura binaria, un numero primo del genere ha un 
efficienza da ridere.
 
Assumiamo allora che il layout sia di 12 BITE, che porta a 
96 bit totali.
Se questo è vero, la descrizione del numero intero deve 
limitarsi a 96-1-7 bits, o 88 (11 byte di pseudomantissa)
 
2^88 = 309'485'009'821'345'068'724'781'056.
Torna come massimo numero di cifre significative ?
 
Se il fattore di scaling è 10^28, matcha con esattamente 
tutte le cifre significative presenti, e non consente di 
avere numeri minori di 0,0309485009821345068724781056
 
tuttavia non mi torna la precisione assoluta, perché se 
sommo due tipi a virgola mobile, posso subito andare in 
underflow giocando sull'esponente, cio' che mi pareva 
dovesse essere proprio il pregio dei decimal.
 
Se sono diventati questo, sono soltanto come dei 
superdouble, a precisione più alta ancora dei long double (a 
80 bit) ma a range ristretto.
In VB ed OLE un tempo c'erano le Currency, altro numero 
analogo (lento come una lumaca nei calcoli).
 
Boh ... sono perplesso
ciao


 una questione puramente filosofica
 
Tre.
 
Tre frasi tre cose in contrasto tra loro.
 
Me ne vado, oggi ho sentito troppe cazzate.
 
 
 

 Me ne vado, oggi ho sentito troppe cazzate.
 
:)
Se metti da parte un secondo la discussione sui FP (che, IMHO, non ha senso,
visto che si sono dette un sacco di stupidaggini quando l'ovvio è lampante),
siamo su un NG di C++, per cui è naturale che di ADA non si sappia un tubo:
basta correggere e, se si ritiene il caso, dare qualche riferimento.
Come al solito, non prendo le difese di nessuno, solo che mi piace il tono
costruttivo che i.c.l.c. e i.c.l.c++ hanno sempre avuto per cui questi post
un po' stonano ;)
Ciao!


Va pure se non spieghi perchè le tre cose sono in contrasto fra loro
 


Non farci caso, probabilmente non gli sono molto simpatico
 


Anche in Common Lisp; anzi Haskell non ha fatto altro che "copiare" 
Common Lisp e Scheme:
http://www.haskell.org/onlinereport/basic.html
 
 
 
Ciao  Manlio

 
 
Ovviamente no.
Hanno una precisione di default, che puoi cambiare come vuoi.
 
 
 
Ciao  Manlio

 ragionevolmente generale. CCCP
 
Troppo buono... senti, a parte le scuse per l'OT: ma
perché hai chiesto "di là" sul confronto tra secanti e
Newton? Sarebbe un problema quasi più pertinente qui, o
poco ci manca.
 
Di là non me la sento di partecipare perché direi cose
troppo scontate per i mostri di scienza, ma se la domanda
"maschera" la richiesta di un metodo a prova di bomba,
quello è la sezione aurea. Non fallisce mai. Ma sarei
sbalordito se tu non lo conoscessi...
 
-- 
Una volta ho chiesto la differenza tra
l'incesto e l'incendio. Non credo di aver
capito troppo bene perché dopo un po' ho
dato fuoco a mia sorella (Pippo Franco)
 

 riferimento. 
 
Come detto prima il problema non riguarda Ada ma esiste con 
qualsiasi linguaggio, anche col linguaggio naturale, anche con
carta e penna. Non posso dare riferimenti bibliografici (a parte 
che già ne sono stati dati un paio, vedi quelli, sono una delle 
poche cose intelligenti che sono state dette) perché 
semplicemente nessun linguaggio di programmazione, nessuna 
rappresentazione dei numeri reali risolve il problema.
Il problema si risolve con la matematica, non posso mettermi 
a fare un corso di metodi numerici qui ed ora.
 
Addio.
 
 

Il 2012-12-11 00:31, Archaeopterx ha scritto:
 
 
Oddio scusa, ero tornato tardi e con un po' di alcoolici
in circolo. Non ti serve il minimo ma lo zero... come non
detto.


 Addio.
 
Ciao.

 sbalordito se tu non lo conoscessi...
 
non lo conosco ... e nemmeno capisco lo sbalordimento. Non 
sono un programmatore se non per hobby, e non sono né fisico 
né ingegnere né matematico, ma uno pseudochimico.
 
Ora googlo un po'. Se nel frattempo me lo esplichi e ne 
decanti i pregi, lo metterò nei ferri del mestiere :-)
Ciao
CCCP


 Non hai capito il senso del mio post. 
 
Probabile. Ma ormai siamo partiti per le tangenti e le secanti.
 
 
 
 

 Probabile. Ma ormai siamo partiti per le tangenti e le secanti.
 
 
PS mi scuso del linguaggio un po' duro e del doppio invio.

 pseudochimico.
 
Invece la sai lunga, e io lo so... Comunque, ulteriormente
smaltiti l'alcool e le benzodiazepine, la sezione aurea è
il mio nome sbagliato per il metodo di Brent. Ecco qua la
prima cosa capitata con gugl:
 
http://linneus20.ethz.ch:8080/1_5_2.html
 
 
ciao!
 
Apx.



 
Tutta questa polemica č nata in quanto Nightmare aveva chiesto se questo 
problema e valido solo per C/C++ ma non in altri linguaggi
Gli ho risposto dicendo che Ada lo aveva risolto adottando alcune tecniche.
Quello che non avevo specificato č che Ada lo ha fatto cambiando il 
formato interno in quando non credo sia possibile risolvere questo tipo 
di problemi usando il classico formato float dello standard IEEE.
Secondo Neonano questo non č un modo di risolvere ma di aggirare il 
problema.
Gli ho risposto che per me puň pensarla come vuole in quanto ritengo ciň 
una disquisizione piů che altro di tipo filosofica.
Non capisco perchč continua ad accanirsi (guarda la risposta che mi ha 
dato)   su questa questione.
L' importante credo sia chiarire il problema, obiettivo raggiunto grazie 
proprio anche a Neonano che ha fatto notare la mia dimenticanza (cambio 
del formato interno) in Ada per risolvere questo problema.
Perň continuare ad accanirsi mi sembra esagerato.
 
 

 
 
Visto che il ramo è marcato come OT mi permetto...
Visto che sembrate entrambi appassionati di questo tipo di cose, e non so se
leggete it.comp.programmare, ho aperto lì un thread ("puzzles... a modo nostro")
qualche giorno fa dove suggerimenti del genere sarebbero preziosi! ;)
Ciao!

 Apx.


 sinora. ciao
 
Un problema così mi sa che si risolve solo con un po' di
euristica, ovvero una prima passata "zozza" a passo
costante, nel caso abbastanza fino e poi una volta
raccolte le info, cercare di partire quanto più possibile
vicino alle radici.
 
In ogni caso, questo credo potrà esserti utile, c'è un
paragrafo proprio sulle radici dei polinomi.
 
http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CDEQFjAA&url=http%3A%2F%2Fwww.mpi-hd.mpg.de%2Fastrophysik%2FHEA%2Finternal%2FNumerical_Recipes%2Ff9-0.pdf&ei=Xl3HULjuCtO38gGb74G4Cg&usg=AFQjCNEkCwJuZVY-P8GQxqlnpisOXlZtRg&sig2=1OPRFngkXHdNWC1Ps7E5XQ
 


 paragrafo proprio sulle radici dei polinomi.
 
OK, non sono le mie giornate... è uscito quello in
fortran, in ogni caso quel che ti serve sta su "numerical
recipes in c", il capitolo 9. Se non lo trovi in rete vedo
se sta da qualche parte dei miei HD ma non garantisco.
Devo smetterla con il diazepam e la birra :D


 Devo smetterla con il diazepam e la birra :D
 
mmm ... direi che è una buona idea. A prescindere eh


 
 
Smetti di prenderli in contemporanea: se fai jump in un branch puoi avere
side-effects.. meglio n-branches su un albero di function-pointers (spero il
paragone si capisca (e poi il mio psichiatra diceva che i paragoni tra la vita
reale e la programmazione era deleteri.. mah!))
;-)
 
Ciao!

 mah!))
 
Ahahahaha fighissimo il parallelo con il linguaggio della
programmazione :D In realtà io li mescolo appositamente,
proprio per perdere coscienza a una certa ora. So che
frigge un po' i neuroni ma tanto faccio così proprio
perché non ne ho mai avuti a sufficienza :D


Il 2012-12-11 18:29, Soviet_Mario ha scritto:
 
 
l'ho trovato, tutto il PDF, sono circa 30 MB. Ora il
problema è: come te lo faccio avere? Ti assicuro che
diventerà il tuo breviario, ormai un po' ti conosco ^_^


 
 
Un mio amico-collega mi diceva sempre: "francé, non importa quanti neuroni
hai e quanti ne perdi: in testa a te son tutti inutili!" ;)
 
Ciao!


Per quanto riguarda tangenti e secanti (sia che siano cercate su curve o post)
tutti qui sono in possesso delle conoscenze (matematiche, sociologiche o 
internet-related) sufficienti per capirle, quindi nessun problema ;)
Per il resto... in PS :)
Ciao!
 
P.S. Non è che son matto, è che per il resto mi spiace vedere qualcuno che sa
quel che dice comportarsi come se usenet fosse quella di dieci anni fa. Ormai
siamo gli ultimi utenti rimasti di una tecnologia facile e immediata che è
destianata ad essere sostituita da chissà cosa: tra "noi" dinosauri tutti
cercano di portare la bandiera, ma a volte i newbies non possono capire :)


 
orbene, visto che ti sei sbattuto in ricerche, ti darei una 
mail valida (a parte che già l'avevi, ci eravamo già sentiti 
qualche volta). Tipo questa :
 
"pasquale__esposito ChIoCcIoLa infinito PuNtO it"
 
senza virgolette e senza spazi
E grazie in anticipo.
Nel frattempo mi sto ubriacando di moltiplicazioni "formali" 
e potenze di polinomi. Minchia che bello farsi fare tutti i 
passaggi dal macinino :-))
 
A sproposito ... degenero nell'OT : tu sai come convertire 
un polinomio di grado "n" in una variabile, in un sistema 
lineare di "n" variabili ? E viceversa ? Me lo aveva 
spiegato Elio Fabri anni fa, ma non ritrovo più il post, 
accidenti a me.
 
Ciao
CCCP
