|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Dec 2004
Messaggi: 783
|
[C] Imprecisioni in lettura file e serie
Salve a tutti, avrei un problema un po strano che non so risolvere. Ho scritto un programmino che legge da file dei numeri. Quando visualizzo questi numeri però ci sono delle discrepanze. Ad esempio:
23.5 diventa 23.499998 1.2 diventa 1.2000001 mentre altri numeri rimangono corretti. Se poi mi creo un vettore che contiene una serie anch'essa ad un certo punto sballa nel senso che se faccio Codice:
t[i]=t[i-1]+0.2 Codice:
383 383,200012 383,399994 383,609985 383,809998 384,01001 384,209991 384,410004 Codice:
383,004974 383,204987 383,404999 383,605011 383,805023 384,005035 384,205048 384,40506 Grazie a tutti per i suggerimenti. PS Se volete ho il listato del programma. Un ultima cosa, le variabili sono di tipo float.
__________________
"May the wind always be at your back and the sun upon your face. And may the wings of destiny carry you aloft to dance with the stars...." |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Apr 2006
Messaggi: 22462
|
il problema è del c stesso, esso scrive in memoria i numeri virgola mobile non come tali, ma come il numero che più vi si avvicina
__________________
amd a64x2 4400+ sk939;asus a8n-sli; 2x1gb ddr400; x850 crossfire; 2 x western digital abys 320gb|| asus g1
Se striscia fulmina, se svolazza l'ammazza |
|
|
|
|
|
#3 | |
|
Senior Member
Iscritto dal: Nov 2004
Città: Padova
Messaggi: 2342
|
Quote:
Il problema è che i numeri sono rappresentati in modo approssimato, qualche volta esatto.
__________________
CPU Ryzen 2600 @ 3,95Ghz + Bequiet Dark Rock TF / MB Asus X470-F Gaming / RAM 2x8GB DDR4 G.Skill FlareX 3200 CL14 / VGA Sapphire RX 7900 XT Nitro+ @ 3200Mhz / SSD Samsung 970 Pro 512GB + Sandisk 240GB Plus + Sandisk 960GB Ultra II PSU Seasonic Platinum P-660 / Headset Kingston HyperX Flight |
|
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Se usi sempre tipi di dato float per storare i tuoi numeri prova a fere così:
Codice:
t[i]=t[i-1]+0.2f
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Non è un problema di rappresentazione, credo, 23.5 ha bisogno di una sola cifra binaria dopo la virgola per essere rappresentato senza troncamenti. Come li leggi i numeri? Dev'essere lì l'errore, direi.
![]() EDIT: però 0.2 non ha bisogno di una sola cifra... è vero, conviene usare dei double.
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! Ultima modifica di DanieleC88 : 04-07-2008 alle 18:50. |
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Dec 2004
Messaggi: 783
|
Cerco di rispondere a tutte le considerazioni che mi avete proposto:
Grazie
__________________
"May the wind always be at your back and the sun upon your face. And may the wings of destiny carry you aloft to dance with the stars...." |
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Aug 2000
Messaggi: 608
|
Scusatemi, io non sono un esperto di programmazione e non voglio passare per tale, ma leggendo le vostre risposte al problema di Salvodel si potrebbe dedurre che i PC non servono a niente e si potrebbero anche buttare nel cassonetto...
Se davvero, come ha affermato qualcuno, questo problema fosse insormontabile ed intrinseco nella rappresentazione stessa dei numeri in virgola mobile, allora non si spiegherebbe l'esistenza stessa del computer, che nasce guardacaso proprio per compiere "calcoli complessi". Finché si suppone che sia un limite del "C" allora uno potrebbe dire "bene, cambio linguaggio"....ma se si afferma che il problema è del formato stesso in virgola mobile.....allora non si potrebbe andare oltre il 2+2. Come nascerebbero, allora, programmi di calcolo, programmi 3d, programmi astronomici, ecc ecc....?? Come sarebbero stati creati 3d Studio, Autocad, e altri software che hanno precisioni nell'ordine dei 4-5 decimali? Insomma, che senso avrebbe usare un computer per fare dei calcoli se davvero fosse "naturale" che sbagli delle cifre anche ad un solo decimale?? Mi sembra troppo assurda come risposta, o forse sono io che non ho capito nulla di come gira il mondo....
__________________
Intel Core2Quad Q6600 2,4GHz @ 3,0 GHz 2 Gb RAM 667 MHz ATI HD2900XT |
|
|
|
|
|
#8 | |
|
Senior Member
Iscritto dal: Nov 2004
Città: Padova
Messaggi: 2342
|
mmmh tutti i vostri dubbi sono di facile risoluzione conoscendo come un calcolatore rappresenta i dati al suo interno.
Per i numeri Naturali non si pone il problema in quanto basta semplicemente convertire da binario a decimale e viceversa. Per i numeri interi positivi e negativi si hanno diverse tecniche di rappresentazione ma possono sempre rappresentare il numero in modo esatto. Con i numeri float e double la cosa è diversa. Un numero a virgola mobile nel calcolatore viene memorizzato come n = M x 2^e. Non serve essere matematici per trarre conclusioni quali: solo pochi numeri possono essere rappresentati esattamente, alcuni numeri non sono nemmeno rappresentabili, si hanno problemi di assorbimento (es: 2^15 +1 = 2^15 ) ecc... Quote:
__________________
CPU Ryzen 2600 @ 3,95Ghz + Bequiet Dark Rock TF / MB Asus X470-F Gaming / RAM 2x8GB DDR4 G.Skill FlareX 3200 CL14 / VGA Sapphire RX 7900 XT Nitro+ @ 3200Mhz / SSD Samsung 970 Pro 512GB + Sandisk 240GB Plus + Sandisk 960GB Ultra II PSU Seasonic Platinum P-660 / Headset Kingston HyperX Flight Ultima modifica di demos88 : 05-07-2008 alle 20:53. |
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
È un problema di base numerica, ci sono alcuni numeri che non sono precisamente rappresentabili, ma solo approssimativamente (perché in base 2 sono periodici).
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
#10 | |
|
Senior Member
Iscritto dal: Aug 2000
Messaggi: 608
|
Quote:
Software di calcoli ingegneristici, fisici, quantistici,....tutte approssimazioni? Nei programmi di progettazione ad altissima precisione (meccanica, fisica, chimica) dove un millesimo di millimetro di differenza può significare il fallimento di un progetto lavorano tutti per "approssimazione"? Scusate, io non sono né un fisico né un matematico, ma per il buon senso mi risulta difficile crederlo..... Inoltre, nei miei primi apprendimenti di programmazione, le poche volte che ho sperimentato calcoli con variabili float e double in C e C++ i valori sono sempre stati corretti, mai sbagliato un solo decimale... Il problema lamentato da Salvodel sembra più un difetto di calcolo che una cosa "normale".... Voglio dire, si parla di un 23.5 che diventa 23.499998 e non il contrario, quindi sarebbe un'approssimazione inversa.....quando mai la si è vista? Posso capire se 23.499998 me lo approssima a 23.5 per la difficoltà di rappresentare troppi decimali, ma il contrario proprio non l'ho mai visto....e non credo abbia senso.....cioè, il calcolatore non riesce a rappresentare correttamente 23.5? Allora anche la semplice "calcolatrice di windows" in base a che principio funziona? Miracoli? Scusate la mia incredulità, nelle mie considerazioni non vuole esserci né polemica né presunzione, voglio solo cercare di capire perchè se davvero esiste questo problema tutto il concetto di "computer" cade e va a farsi friggere....ma mi sembrano cose dell'altro mondo
__________________
Intel Core2Quad Q6600 2,4GHz @ 3,0 GHz 2 Gb RAM 667 MHz ATI HD2900XT |
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Alcune volte sì. Non è una cosa che capita con tutti i numeri, ma alcuni numeri decimali non è possibile (in base 2) rappresentarli con esattezza. Il sistema numerico in base 2 è un sistema posizionale come anche quello in base 10; ciò significa che ogni cifra di un numero ha un suo "peso" che è dato dalla posizione. Ad esempio, il numero 123 è uguale a (1·100) + (2·10) + (3·1), dove tutti i moltiplicatori sono potenze di 10. I numeri decimali seguono lo stesso principio: 0,53 = (5 / 10) + (3 / 100), dove i moltiplicatori sono le potenze negative di 10.
Un numero in base 2 ha semplicemente una base diversa, il procedimento invece è identico: 7 in base 10 = 111 in base 2 = (1·4) + (1·2) + (1·1). Invece: 0,25 in base 10 = 0,01 in base 2 = (0 / 2) + (1 / 4). L'algoritmo per convertire un numero decimale dalla base 10 alla base 2 è semplice: lo moltiplichi per due; del risultato, la parte a sinistra della virgola è il "bit" della conversione, la parte a destra della virgola va presa da sola e vi va riapplicato il procedimento (finché non ottieni 0). Prendiamo 0,2 in base 10 e convertiamolo in base 2: Codice:
0,2 · 2 = 0,4 | primo bit: 0 0,4 · 2 = 0,8 | secondo bit: 0 0,8 · 2 = 1,6 | terzo bit: 1 0,6 · 2 = 1,2 | quarto bit: 1 0,2 · 2 = ...... Per sicurezza ho chiesto anche a Qalculate!, che mi traduce 0,2 in base 10 in questa stringa binaria: Codice:
≈ 0.0011001100110011001100110011 Il problema coi float è che usano la precisione singola su 32 bit (1 di segno, 8 di esponente, e solo 23 di mantissa), quindi, approssimazione dopo approssimazione, con centinaia e centinaia di somme ottieni risultati imprecisi. Con la precisione doppia già puoi avere risultati più affidabili. Poi, ovvio che software complessi che devono garantire una buona dose di precisione facciano fronte a questi problemi in diversi modi... Insomma, non è tutto da gettare alle ortiche, tranquillo.
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! Ultima modifica di DanieleC88 : 06-07-2008 alle 18:28. |
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Ci fai vedere un po' di codice ? Secondo me si tratta di una somma di errori di rappresentazione. Compreso il codice che stampa in numeri per verifica
Prima di tutto devi usare sempre i double e mai i float. Il problema di rappresentazione dei numeri in virgola mobile è presto detto: i numeri reali hanno cardinalità maggiore dei numeri rappresentabili su un floating point a qualsiasi precisione. E' chiaro, di conseguenza, che non tutti i numeri reali sono rappresentabili su un numero limitato di bit. Nei calcoli di alto livello si usano per questo precisioni maggiori dei 64-80 bit dei double. Spesso si usano floating point a 128 bit. I nostri processori permettono già di usare questo livello di precisione, ma solamente tramite istruzioni SSE, che sono appunto adatte a processare dati vettorialmente. Poi c'è anche tutta una teoria dietro per limitare la propagazione di errori di rappresentazione. |
|
|
|
|
|
#13 |
|
Member
Iscritto dal: Jul 2008
Messaggi: 237
|
Qualora fosse ancora necessario...
Mi sono registrato oggi e ho visto questo thread. La spegazione fornita sopra sull'inesattezza della rappresentazione binaria di un numero decimale è esatta, e alla luce di essa è opportuno decidere qual'è il livello di precisione realmente necessario. La libreria che si trova al link seguente fornisce la possibilità di calcolo in virgola mobile con più precisione di quanta non ne serva normalmente. Se si desiderassero numeri esatti, ad ogni modo, e questi non fossero parte di algoritmi particolarmente cpu-intensive, consiglio l'uso di un elevata precisione combinata combinata ad arrotondamenti, in maniera tale da arrivare a risultati "esatti". Nel caso di applicazioni che devono fare calcoli di denaro è molto utile al fine di non perdere o aggiungere nei calcoli qualcosa qua e la, specie perché se la quantità di operazioni diventa ingente anche le somme perse o aggiunte possono diventare non trascurabili. http://www.apfloat.org/apfloat/ |
|
|
|
|
|
#14 | |
|
Senior Member
Iscritto dal: Dec 2004
Messaggi: 783
|
Quote:
Grazie a tutti. Codice:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int salva(float time[],float time_c[], int max)
{
FILE *fdati;
char *OUTPUT;
int t;
OUTPUT=(char *)malloc(15*sizeof(char));
printf("Salvataggio - ");
sprintf(OUTPUT, "%s.dat", "tempi");
if((fdati=fopen(OUTPUT,"w"))==NULL)
{
printf("\nImpossibile scrivere il file\n");
return 0;
}
else
{
for(t=0;t<max;t++)
fprintf(fdati,"%d\t%f\t%f\n",t,time[t], time_c[t]);
}
printf("O.K.\n");
return 1;
}
int main()
{
float *time, *time_c, *WIND;
float tMAX, WIND_medio;
int count, t;
FILE *fdati;
tMAX=-1;WIND_medio=-1;
time =(float *)malloc(1*sizeof(float *));
WIND =(float *)malloc(1*sizeof(float *));
count=0;
if((fdati=fopen("dati.dat","r"))==NULL)
printf("Impossibile aprire il file");
else
{
while(fscanf(fdati,"%f",&time[count])>0)
{
count++;
time = (float *) realloc (time, (count+1)*sizeof(float));
}
}
time_c =(float *)malloc(count*sizeof(float *));
time_c[0]=0.0f;
for(t=1;t<count;t++)
time_c[t]=time_c[t-1]+0.2f;
salva(time,time_c,count);
return 1;
}
__________________
"May the wind always be at your back and the sun upon your face. And may the wings of destiny carry you aloft to dance with the stars...." |
|
|
|
|
|
|
#15 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Allora, il primo problema è intrinseco al fatto che vai a scrivere i dati con printf. I floating point, se dopo devono essere recuperati e rielaborati devono essere SEMPRE salvati in binario. Altrimenti già stampando su file con %f limiti la precisione del float stesso non andando a scrivere gran parte delle cifre dopo la virgola. In alternativa, nonostante non sia perfettamente equivalente, stampa con %.20f.
Il secondo problama: non si usano MAI i float, ma SEMPRE i double. I float hanno una precisione adatta ai programmini delle scuole superiori. I float sono solamente 32 bit (se non mi ricordo male 23 di mantissa, 8 di esponente e 1 di segno). Solo la scrittura e la lettura binaria ti garantisce di andare a scrivere un numero e poi andare a riprendere esattamente quello che hai scritto. Infatti c'è già un grandissima approssimazione intrinseca alla scrittura in testo con decimali limitati, poi quando vai a riprendere questi numeri leggendo il testo c'è una ulteriore approssimazione dovuta alla conversione da testo a floating point. Ecco qui il doppio errore di approssimazione. |
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Dec 2004
Messaggi: 783
|
Quote:
Cmq c'è un erroraccio nel listato(c'era un * di troppo essendo in principio una function). Ora l'ho corretto ed ottengo il seguente risultato: OK Codice:
0 0 0 1 0.2 0.2 2 0.4 0.4 3 0.6 0.6 4 0.8 0.8 5 1 1 Codice:
159 31.8 31.8 160 32 32 161 32.2 32.2001 162 32.4 32.4001 163 32.6 32.6001 164 32.8 32.8001 165 33 33.0001 166 33.2 33.2001 Codice:
446 89.2 89.1998 447 89.4 89.3998 448 89.6 89.5998 449 89.8 89.7998 450 90 89.9998 451 90.2 90.1998 452 90.4 90.3998 453 90.6 90.5998 454 90.8 90.7998 455 91 90.9998 456 91.2 91.1998 457 91.4 91.3997 458 91.6 91.5997 459 91.8 91.7997 460 92 91.9997 461 92.2 92.1997 462 92.4 92.3997 463 92.6 92.5997 464 92.8 92.7997 465 93 92.9997 466 93.2 93.1997 467 93.4 93.3997 468 93.6 93.5997 469 93.8 93.7997 470 94 93.9997 471 94.2 94.1997 472 94.4 94.3997 473 94.6 94.5997 474 94.8 94.7997 475 95 94.9997 476 95.2 95.1997 477 95.4 95.3997 478 95.6 95.5997 479 95.8 95.7997 480 96 95.9997 481 96.2 96.1997 482 96.4 96.3997 483 96.6 96.5997 484 96.8 96.7997 485 97 96.9997 486 97.2 97.1997 487 97.4 97.3997 488 97.6 97.5997 489 97.8 97.7997 490 98 97.9996 491 98.2 98.1996 492 98.4 98.3996 Grazie
__________________
"May the wind always be at your back and the sun upon your face. And may the wings of destiny carry you aloft to dance with the stars...." Ultima modifica di salvodel : 07-07-2008 alle 13:01. |
|
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Sono proprio le somme che propagano ancora di più l'errore di rappresentazione
Prova a sostituire questo for(t=1;t<count;t++) time_c[t]=time_c[t-1]+0.2f; con questo for(t=1;t<count;t++) time_c[t]=time_c[0]+0.2f * t; Ultima modifica di cionci : 07-07-2008 alle 13:09. |
|
|
|
|
|
#18 | |
|
Senior Member
Iscritto dal: Dec 2004
Messaggi: 783
|
Quote:
Cmq questo è quello che ottengo con %lf e facendo il prodotto Codice:
contatore | serie letta | serie generata 4264 852.830000 852.800000 4265 853.030000 853.000000 4266 853.230000 853.200000 4267 853.430000 853.400000 4268 853.630000 853.600000 4269 853.830000 853.800000 4270 854.030000 854.000000 4271 854.230000 854.200000 4272 854.430000 854.400000 Codice:
contatore | serie letta | serie generata 4264 852.830000 852.800013 4265 853.030000 853.000013 4266 853.230000 853.200013 4267 853.430000 853.400013 4268 853.630000 853.600013 4269 853.830000 853.800013 4270 854.030000 854.000013 4271 854.230000 854.200013 4272 854.430000 854.400013 PS cionci quando togli la scritta Lontano dal forum per qualche mese?
__________________
"May the wind always be at your back and the sun upon your face. And may the wings of destiny carry you aloft to dance with the stars...." |
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 20:02.





















