Newsgroup: it.comp.lang.c
Titolo: Problemi di conversione strtof, strtod

Ciao a tutti!
Seguendo la moda del momento :P vi sottopongo un altro problema di 
conversione da stringhe a numeri.
In particolare avrei bisogno di convertire a float; nelle librerie C ho 
trovato la funzione strtof, ma ho riscontrato dei comportamenti anomali 
se non si compila secondo lo standard c99. (*)
Mi hanno chiesto di evitare di compilare in c99, così ho provato ad 
usare strtod e fare un cast, ma anche qui ottengo dei comportamenti strani:
stringa cStr è "0.0003:   (eccetera) \n"
d =  strtod(cStr,&endptr); dà 0.00029999999999999997
m  = (float) d;  dà 0.000300000014
suggerimenti??? qualcuno sa spiegare questo comportamento??
non credo sia un problema di granularità
dimenticavo uso gcc 4.0.1 su fedora ( ma non sembra essere un problema 
di distro)
grazie
ciao
aL
(*) provato con un programma ad hoc
Stringa = "0.00003\n"
(strtod) è 0.000030
(strtof) 8104066.000000
cast da double a float è 0.000030
con flag std=c99
(strtod) è 0.000030
(strtof) 0.000030
cast dal double è 0.000030

 non credo sia un problema di granularità
Non ci vedo assolutamente niente di strano (nella parte numerica, nel discorso del c99
non mi pronuncio, considera anche le funzioni atoff e sscanf. Comunque
convertire prima in double e poi in float non e' sbagliato.)
Come presumo tu sappia 0.0003 non e' un numero rappresentabile esattamente
ne in un float ne in un double, perche' corrisponde, in binario,
ad un numero periodico.
Quindi qualunque troncamento ad un numero
specifico di bit produrra' una lieve discrepanza tra il numero ideale,
0.00003 ed il numero di macchina. A seconda di dove tronchi e del metodo
di arrotondamento usato, potrai avere un numero un pelino piu' grande o un
pelino piu' piccolo di 0.0003, anche se stampando le prime cifre decimali
di solito ottieni da capo 0.0003, per effetto dell'arrotondamento.
((Aperta parentesi. L'effetto macroscopico della rappresentazione di macchina e' che
per le operazioni del C non valgono le proprieta' che valgono
per le operazioni ideali, quindi meglio scordarsi cose tipo
proprieta' commutativa, distributiva, etc.etc.
Cioe' un test del tipo a*(b+c)  == a*b+a*c dove a,b,c sono numeri decimali in floating
point e' spesso destinato a fallire... Chiusa parentesi))
Se invece chiedi di stampare molte cifre decimali il fenomeno puo'
diventare evidente come nel tuo esempio.
Tra l'altro stampare un float con 13 cifre e'
concettualmente errato, perche' un float non le ha 13 cifre di precisione.
Un float ha una precisione ridicola e dovrebbe essere usato
solo sotto stetto controllo medico :-)
In particolare un float e' rappresentato tipicamente su 32 bit,
23 dei quali occupati dalla mantissa. Quindi vedi bene che un numero
float non puo' avere piu' di circa 7 cifre significative esatte,
che rischiano di assottigliarsi ad ogni operazione che ci fai su.
In generale, a meno che tu non sappia veramente bene cosa stai
facendo e ci siano dei motivi precisi per usare i float
(esempio: risparmio di memoria nel caso di strutture dati che ne contengono
milioni) evita i float come la peste ed usa al loro posto i double.
ciao,
g.

 
Grazie molte, sei stato molto chiaro.
Purtroppo sono costretto ad usare i float perché inseriti in una 
struttura che non si può modificare. Cercherò di fare degli 
arrotondamenti controllati ed eventualmente cercherò un medico 
compiacente :-P
grazie ancora
aL
p.s. chiedo venia per l'output del float a 13 cifre, ma era quello 
visualizzato da DDD :)