Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Errore di round off
Forum - C/C++ - Errore di round off

Avatar
MagoAntò (Normal User)
Rookie


Messaggi: 42
Iscritto: 07/02/2009

Segnala al moderatore
Postato alle 9:23
Giovedì, 04/02/2010
Ciao a tutti!

Sono alle prese con un esercizio (anzi, una serie di esercizi) che mi richiedono, tra le altre cose, il calcolo dell'errore di round off. L'esercizio mi chiede di utilizzare una variabile double (nello specifico, double x)come risultato esatto e una variabile float (nello specifico, flx = (float)x) come sua approssimazione. Il calcolo dell'errore di round off viene, infine, eseguito calcolando l'errore relativo secondo questa formula: |x-flx|/|x|.

Vi riporto la traccia dell'esercizio:
Visualizzare l’errore di roundoff nei seguenti algoritmi. Scrivere una function C per calcolare una somma di molti addendi mediante l’algoritmo del raddoppiamento ricorsivo (batch adding - versione iterativa).

Diciamo che già la frase "raddoppiamento ricorsivo (versione iterativa)" già mi lascia un po' perplesso. Per raddoppiamento ricorsivo si intende una situazione del genere: abbiamo questi elementi

0 2 6 3 4 2

la somma totale, ovviamente, è 17 e la si deve ottenere con una funzione che somma prima 0+2 poi 6+3 poi 4+2, dopodichè somma i rispettivi risultati (2, 9, 6) facendo 2+9, il risultato +6 cioè 11+6 = 17

Ho deciso di implementare l'algoritmo ricorsivamente, in ogni caso. Questo è il codice:
Codice sorgente - presumibilmente C

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <float.h>
  4.  
  5. float somma_radd_ric (float a [], float primo, float ultimo);
  6.  
  7. void main ()
  8. {
  9.  
  10.         float a [50];
  11.         float errore_roundoff, primo, ultimo, risultato;
  12.         double risultato_esatto;
  13.         int i, size;
  14.         primo = 0;
  15.         risultato_esatto = 0;
  16.         printf ("Digita il numero degli addendi (max. 50): ");
  17.         scanf ("%d", &size);
  18.         ultimo = size-1;
  19.         for (i=0; i<size; i++)
  20.         {
  21.                 printf ("Inserisci il %d addendo: ", i+1);
  22.                 scanf ("%f", &a[i]);
  23.                 risultato_esatto = risultato_esatto + (double)a[i];
  24.         }
  25.         risultato = somma_radd_ric (a, primo, ultimo);
  26.         printf ("Il risultato e' = %f\n", risultato);
  27.         errore_roundoff = fabs ((risultato_esatto-risultato)/risultato_esatto);
  28.         printf ("L'errore di roundoff e' = %e\n", errore_roundoff);
  29. }
  30.  
  31. float somma_radd_ric (float a [], float primo, float ultimo)
  32. {
  33.         float mediano;
  34.         if (ultimo - primo == 1)
  35.                 return (a[primo] + a[ultimo]);
  36.         if (ultimo==primo)
  37.                 return (a[primo]);
  38.         else
  39.         {
  40.                 mediano = (primo+ultimo)/2;
  41.                 return (somma_radd_ric (a,primo,mediano) + somma_radd_ric (a,mediano+1,ultimo));
  42.         }
  43. }


Il codice mi da questi errori:

* warning C4244: '=' : conversion from 'int ' to 'float ', possible loss of data,
relativo alla riga "ultimo = size-1;"

* warning C4244: '=' : conversion from 'double ' to 'float ', possible loss of data,
relativo alla riga "errore_roundoff = fabs ((risultato_esatto-risultato)/risultato_esatto);"

* error C2108: subscript is not of integral type,
relativo alla riga "return (a[primo] + a[ultimo])";

* error C2108: subscript is not of integral type,
relativo alla riga "return (a[primo] + a[ultimo])";

* error C2110: cannot add two pointers,
relativo alla riga "return (a[primo] + a[ultimo])";

* warning C4033: 'somma_radd_ric' must return a value,
relativo alla riga "return (a[primo] + a[ultimo])";

* error C2108: subscript is not of integral type,
relativo alla riga "return (a[primo])";

* error C2115: 'return' : incompatible types,
relativo alla riga "return (a[primo])";

Il problema è il seguente: la function sembra funzionare solo nel caso in cui i parametri di input e di output vengano dichiarati come int. Nel momento in cui cambio i tipi di dato, succede quello che ho elencato sopra. Avevo pensato di dichiarare l'array e il risultato esatto come campi di una union, in modo da condividere la stessa area di memoria. Qualche aiuto? E' molto importante! Grazie in anticipo a tutti :)

Ultima modifica effettuata da MagoAntò il 04/02/2010 alle 11:08
PM Quote
Avatar
Poggi Marco (Member)
Guru


Messaggi: 969
Iscritto: 05/01/2010

Segnala al moderatore
Postato alle 19:25
Giovedì, 04/02/2010
Ciao!

Ho letto il tuo programma, e ho trovato che tu usi dati float come indice della matrice.

Non ho ben capito come vorresti costruire l' union.

Ultima modifica effettuata da Poggi Marco il 04/02/2010 alle 19:27
PM Quote
Avatar
MagoAntò (Normal User)
Rookie


Messaggi: 42
Iscritto: 07/02/2009

Segnala al moderatore
Postato alle 22:10
Giovedì, 04/02/2010
Testo quotato

Postato originariamente da Poggi Marco:

Ciao!

Ho letto il tuo programma, e ho trovato che tu usi dati float come indice della matrice.

Non ho ben capito come vorresti costruire l' union.  


Ciao e grazie per la risposta.

Beh, prima ancora di creare l'union, vorrei capire perchè il programma, impostato così, mi da quegli errori.
Per quanto riguarda la union, avevo pensato ad una cosa del genere:
Codice sorgente - presumibilmente C/C++

  1. union bit_64bit
  2. {
  3. double dx;
  4. _int64 y;
  5. }a;


...visto che il mio codice sembra dare problemi nel momento in cui uso variabili float al posto delle int. Qualche altra idea?

PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6381
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 8:27
Venerdì, 05/02/2010
Gli indici di un vettore *devono* essere interi, non double o float ...

In particolare, devono essere intere le variabili primo, ultimo e mediano ...

Ultima modifica effettuata da nessuno il 05/02/2010 alle 8:29


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti (uno dei padri fondatori del moderno Calcolo delle probabilità) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Avatar
MagoAntò (Normal User)
Rookie


Messaggi: 42
Iscritto: 07/02/2009

Segnala al moderatore
Postato alle 11:59
Venerdì, 05/02/2010
Testo quotato

Postato originariamente da nessuno:

Gli indici di un vettore *devono* essere interi, non double o float ...

In particolare, devono essere intere le variabili primo, ultimo e mediano ...



Dico una sciocchezza: dichiarandoli come interi, non riduco la precisione dei risultati? Dovrei calcolarli sia come float che come double, per questo dicevo... :-|

PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6381
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 12:14
Venerdì, 05/02/2010
Testo quotato

Postato originariamente da MagoAntò:

Testo quotato

Postato originariamente da nessuno:

Gli indici di un vettore *devono* essere interi, non double o float ...

In particolare, devono essere intere le variabili primo, ultimo e mediano ...



Dico una sciocchezza: dichiarandoli come interi, non riduco la precisione dei risultati? Dovrei calcolarli sia come float che come double, per questo dicevo... :-|



Cosa c'entra la precisione del calcolo con gli indici di un array? Stai facendo confusione tra gli elementi di un array e i suoi indici ...


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti (uno dei padri fondatori del moderno Calcolo delle probabilità) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Avatar
MagoAntò (Normal User)
Rookie


Messaggi: 42
Iscritto: 07/02/2009

Segnala al moderatore
Postato alle 13:26
Venerdì, 05/02/2010
Testo quotato

Postato originariamente da nessuno:

Testo quotato

Postato originariamente da MagoAntò:

Testo quotato

Postato originariamente da nessuno:

Gli indici di un vettore *devono* essere interi, non double o float ...

In particolare, devono essere intere le variabili primo, ultimo e mediano ...



Dico una sciocchezza: dichiarandoli come interi, non riduco la precisione dei risultati? Dovrei calcolarli sia come float che come double, per questo dicevo... :-|



Cosa c'entra la precisione del calcolo con gli indici di un array? Stai facendo confusione tra gli elementi di un array e i suoi indici ...



Hai ragione, scusami. ;)

Ho modificato il codice dichiarando primo, ultimo e mediano come interi, adesso il programma funziona. Inoltre, ho dichiarato l'array a come double in modo da poter calcolare meglio il risultato "esatto". La function somma_radd_ric, poi, provvederà a restituirmi il risultato come un float. Ho ragionato bene? Ecco il codice modificato:
Codice sorgente - presumibilmente C

  1. #include  <stdio.h>
  2. #include <math.h>
  3. #include <float.h>
  4.  
  5. float somma_radd_ric (double a [], int primo, int ultimo);
  6.  
  7. void main ()
  8. {
  9.  
  10.     double a [50];
  11.     float risultato;
  12.     double risultato_esatto, errore_roundoff;
  13.     int i, size, primo, ultimo;
  14.     primo = 0;
  15.     risultato_esatto = 0;
  16.     printf ("Digita il numero degli addendi (max. 50): ");
  17.     scanf ("%d", &size);
  18.     ultimo = size-1;
  19.     for (i=0; i<size; i++)
  20.     {
  21.         printf ("Inserisci il %d addendo: ", i+1);
  22.         scanf ("%lf", &a[i]);
  23.         risultato_esatto = risultato_esatto + a[i];
  24.     }
  25.     printf ("Il risultato calcolato come double e': %lf\n", risultato_esatto);
  26.     risultato = somma_radd_ric (a, primo, ultimo);
  27.     printf ("Il risultato e' = %f\n", risultato);
  28.     errore_roundoff = fabs ((risultato_esatto-risultato)/risultato_esatto);
  29.     printf ("L'errore di roundoff e' = %e\n", errore_roundoff);
  30. }
  31.  
  32. float somma_radd_ric (double a [], int primo, int ultimo)
  33. {
  34.     int mediano;
  35.     if (ultimo - primo == 1)
  36.         return (a[primo] + a[ultimo]);
  37.     if (ultimo==primo)
  38.         return (a[primo]);
  39.     else
  40.     {
  41.         mediano = (primo+ultimo)/2;
  42.         return (somma_radd_ric (a,primo,mediano) + somma_radd_ric (a,mediano+1,ultimo));
  43.     }
  44. }


Come test, ho provato ad inserire 50 componenti nell'array tutte uguali a 999999999999999 e, come output, il programma mi da:

Il risultato calcolato come double e': 49999999999999984.000000
Il risultato e' = 49999999161237504.000000
L'errore di roundoff e' = 1.569325e-008

L'errore di roundoff è "abbastanza piccolo" da poter essere accettato. Infine, il programma mi segnala solo due warning:

* warning C4244: 'return' : conversion from 'double ' to 'float ', possible loss of data,
relativo alla riga della function "return (a[primo] + a[ultimo])";

* warning C4244: 'return' : conversion from 'double ' to 'float ', possible loss of data,
relativo alla riga della function "return (a[primo])";


Ho sbagliato qualcosa? Grazie mille per l'aiuto! :k:

Ultima modifica effettuata da MagoAntò il 05/02/2010 alle 13:45
PM Quote
Avatar
Poggi Marco (Member)
Guru


Messaggi: 969
Iscritto: 05/01/2010

Segnala al moderatore
Postato alle 19:06
Venerdì, 05/02/2010
Ciao!

Finalmente hai terminato il programma!

Per quanto riguarda i warning, non preoccuparti più di tanto.
Il compilatore si aspetta un dato float a destra di return, mentre tu gli inserisci un double. Per risolvere il problema, basta fare un cast ( return (float) (a[primo])"; ).

Ultima modifica effettuata da Poggi Marco il 05/02/2010 alle 19:08
PM Quote