PROBLEMA [C]Come calcolare l'epsilon macchina e rmin.

Pubblicità

enzoio99

Nuovo Utente
Messaggi
82
Reazioni
2
Punteggio
28
dovrei calcolare l'epsilon macchina e rmin , entrambi in singola e doppia precisione . questi sono i due programmi:
#include <stdio.h>

void Singola_Precisione (float e, int b);

void Doppia_Precisione(double e, int b);

int main(void){
int base=2;
float e=1.0;


Singola_Precisione(e,base);


Doppia_Precisione(e,base);



return 0;

}

float Singola_Precisione(float e, int b){
float eps;

while(1.0+e!=1){

e=e/(float)b;
}
printf("l'epsilon macchina in dippia precisione e' %.16f", e*2);
}

double Doppia_Precisione(double e, int b){
double eps;

while(1.0+e!=1){

e=e/(double) b;
}
printf("l'epsilon macchina in dippia precisione e' %.32f", e*2);

}







rmin:
#include <stdio.h>

void r_min_Singola_Precisione(float e,int b);

void r_min_Doppia_Precisione (double e,int b);

int main(){
int b;
float rmin;
b=2;
rmin=1.0;

r_min_Singola_Precisione( rmin, b);

r_min_Doppia_Precisione ( rmin, b);

return 0;
}

void r_min_Singola_Precisione(float e,int b){
float rmin1;

while(e!=0){
rmin1=e;
e=rmin1/(float)b;
}

printf("rmin in singola precisione e' %.54f\n", e);
}

void r_min_Doppia_Precisione (double e,int b){
double rmin1;

while(e!=0){
rmin1=e;
e=rmin1/(double)b;
}
printf("rmin in doppia precisione e' %.32f\n", e);
}


nel primo esercizio mi trovo solo la precisione doppia e non capisco il perchè , mentre nell'rmin non mi trovo nessuno dei due...
 
Ciao, ho dato un'occhiata al primo esercizio e credo di averlo risolto. Per prima cosa ho corretto degli errori (forse di distrazione nel copiare il codice): Singola_Precisione() e Doppia_Precisione() sono procedure, non funzioni, perciò il loro tipo di ritorno deve essere void, come hai scritto correttamente nei prototipi, (ma nelle definizionni hai messo float e double). Secondo, le variabili locali eps nelle due procedure sono inutilizzate, perciò le ho eliminate. Per far stampare correttamente l'epsilon di macchina a singola precisione ho messo double come tipo del parametro di input e della procedura, inoltre il cast va fatto nella valutazione dell'if.
Poi, per comodità, ho messo lo specificatore di conversione %g (che in questo caso utilizza una notazione esponenziale "breve") nelle printf. Ah, ho scritto e /= b al posto di e = e / b per brevità ma è lo stesso.
Ecco il codice:
C:
#include <stdio.h>

void Singola_Precisione(double e, int b);
void Doppia_Precisione(double e, int b);

int main(void)
{
    int base = 2;
    double eps = 1.0;

    Singola_Precisione(eps, base);
    Doppia_Precisione(eps, base);

    return 0;
}

void Singola_Precisione(double e, int b){
   while((float)(1.0 + (e / b)) != 1.0){
        e /= b;
    }
    printf("l'epsilon macchina in singola precisione e' %g\n", e);
}

void Doppia_Precisione(double e, int b){
   while((double)(1.0 + (e / b)) != 1.0){
        e /= b;
    }
    printf("l'epsilon macchina in doppia precisione e' %g\n", e);
}
 
Ultima modifica:
Ciao, ho dato un'occhiata al primo esercizio e credo di averlo risolto. Per prima cosa ho corretto degli errori (forse di distrazione nel copiare il codice): Singola_Precisione() e Doppia_Precisione() sono procedure, non funzioni, perciò il loro tipo di ritorno deve essere void, come hai scritto correttamente nei prototipi, (ma nelle definizionni hai messo float e double). Secondo, le variabili locali eps nelle due procedure sono inutilizzate, perciò le ho eliminate. Per far stampare correttamente l'epsilon di macchina a singola precisione ho messo double come tipo del parametro di input e della procedura, inoltre il cast va fatto nella valutazione dell'if.
Poi, per comodità, ho messo lo specificatore di conversione %g (che in questo caso utilizza una notazione esponenziale "breve") nelle printf. Ah, ho scritto e /= b al posto di e = e / b per brevità ma è lo stesso.
Ecco il codice:
Codice:
#include <stdio.h>

void Singola_Precisione(double e, int b);
void Doppia_Precisione(double e, int b);

int main(void)
{
    int base = 2;
    double eps = 1.0;

    Singola_Precisione(eps, base);
    Doppia_Precisione(eps, base);

    return 0;
}

void Singola_Precisione(double e, int b){
   while((float)(1.0 + (e / b)) != 1.0){
        e /= b;
    }
    printf("l'epsilon macchina in singola precisione e' %g\n", e);
}

void Doppia_Precisione(double e, int b){
   while((double)(1.0 + (e / b)) != 1.0){
        e /= b;
    }
    printf("l'epsilon macchina in doppia precisione e' %g\n", e);
}
ah grazie...quegli errori probabilmente sono dovuti al fatto che lho cercato di fare 40000 volte quell'esercizio e non ci riuscivo....e per l'rmin? thanks ancora!
 
Ciao, ho dato un'occhiata al primo esercizio e credo di averlo risolto. Per prima cosa ho corretto degli errori (forse di distrazione nel copiare il codice): Singola_Precisione() e Doppia_Precisione() sono procedure, non funzioni, perciò il loro tipo di ritorno deve essere void, come hai scritto correttamente nei prototipi, (ma nelle definizionni hai messo float e double). Secondo, le variabili locali eps nelle due procedure sono inutilizzate, perciò le ho eliminate. Per far stampare correttamente l'epsilon di macchina a singola precisione ho messo double come tipo del parametro di input e della procedura, inoltre il cast va fatto nella valutazione dell'if.
Poi, per comodità, ho messo lo specificatore di conversione %g (che in questo caso utilizza una notazione esponenziale "breve") nelle printf. Ah, ho scritto e /= b al posto di e = e / b per brevità ma è lo stesso.
Ecco il codice:
Codice:
#include <stdio.h>

void Singola_Precisione(double e, int b);
void Doppia_Precisione(double e, int b);

int main(void)
{
    int base = 2;
    double eps = 1.0;

    Singola_Precisione(eps, base);
    Doppia_Precisione(eps, base);

    return 0;
}

void Singola_Precisione(double e, int b){
   while((float)(1.0 + (e / b)) != 1.0){
        e /= b;
    }
    printf("l'epsilon macchina in singola precisione e' %g\n", e);
}

void Doppia_Precisione(double e, int b){
   while((double)(1.0 + (e / b)) != 1.0){
        e /= b;
    }
    printf("l'epsilon macchina in doppia precisione e' %g\n", e);
}


ho fatto l'altro esercizio nel seguente modo:
Codice:
#include <stdio.h>

void r_min_Singola_Precisione(double e,int b);

void r_min_Doppia_Precisione (double e,int b);

int main(){
    int b;
    double rmin;
    b=2;
    rmin=1.0;
  
    r_min_Singola_Precisione( rmin, b);
  
    r_min_Doppia_Precisione ( rmin, b);
  
    return 0;
}

void r_min_Singola_Precisione(double e,int b){
    double rmin1;
  
    while((float)(e/b)!=0){
        rmin1=e;
        e=rmin1/b;
    }
  
    printf("rmin in singola precisione e' %g\n", e);
}

void r_min_Doppia_Precisione (double e,int b){
    double rmin1;
  
    while((double)(e/b)!=0){
        rmin1=e;
        e=rmin1/b;
    }
    printf("rmin in doppia precisione e' %g\n", e);
}



però mi da come risultato:
Codice:
rmin in singola precisione e' 1.4013e-045
rmin in doppia precisione e' 4.94066e-324

--------------------------------
Process exited after 0.04994 seconds with return value 0
Premere un tasto per continuare . . .
 
Ciao, ti faccio notare che mettendo rmin1 anziché e nelle printf il codice del primo post produce lo stesso risultato di quello che hai postato oggi (perché se per il computer e == 0 è ovvio che ti stampa 0, e allora devi stampare il numero immediatamente precedente, rmin1).

Per capire se l'esercizio è svolto correttamente devi specificare quali valori ti aspetti. In altre parole, il più piccolo reale positivo rappresentabile non è univoco, ma dipende dal sistema di codifica usato. In generale, secondo lo standard IEEE 754 possiamo usare 32 bit (precisione singola) o 64 bit (precisione doppia). Possiamo rappresentare l'insieme dei numeri di macchina come una quadrupla F(β,t,M1,M2) dove β è la base, t sono i bit per la mantissa, M1 e M2 sono gli estremi dell'intervallo di variabilità dell'esponente (compreso tra M1+1 e M2-1). Per la precisione singola si ha F(2,23,-127,128), con i 32 bit suddivisi nel seguente modo: 1 per il segno, 8 per l'esponente e 23 per la mantissa. Si avrebbero 2^8 = 256 possibili valori per l'esponente, ma dato che i valori 0 e 255 sono usati per rappresentare rispettivamente lo 0 e gli infiniti, restano 254 valori utili, che possono rappresentare esponenti compresi tra -126 e 127. In questo caso abbiamo che il più piccolo numero positivo normalizzato rappresentabile è 2^-126, circa 1.175e-38 (sarebbe 2^-126 x (1.00...00), dove l'ultimo fattore è la mantissa).
Per la precisione doppia si ha F(2,52,-1023,1024) e il più piccolo numero positivo normalizzato rappresentabile è 2^-1022 (circa 2.225e-308).
I valori che hai ottenuto tu sono i più piccoli numeri denormali rappresentabili (2^-149 e 2^-1074). I numeri denormali (o denormalizzati o subnormalizzati) servono per rappresentare numeri che generano underflow, compresi tra 0 e il più piccolo numero positivo normalizzato. Si ottengono mettendo uno zero come prima cifra della mantissa, e usando l'esponente minimo. Per cui, nel caso della precisione singola, il più piccolo numero denormale positivo è 2^-126 x (0.00...01) che è uguale a 2^-149 (perché ci sono 23 cifre nella mantissa e 126 + 23 = 149). Analogamente per la precisione doppia.
Ora non so cosa chiedeva la traccia di preciso.

 
Ultima modifica:
Ciao, ti faccio notare che mettendo rmin1 anziché e nelle printf il codice del primo post produce lo stesso risultato di quello che hai postato oggi (perché se per il computer e == 0 è ovvio che ti stampa 0, e allora devi stampare il numero immediatamente precedente, rmin1).

Per capire se l'esercizio è svolto correttamente devi specificare quali valori ti aspetti. In altre parole, il più piccolo reale positivo rappresentabile non è univoco, ma dipende dal sistema di codifica usato. In generale, secondo lo standard IEEE 754 possiamo usare 32 bit (precisione singola) o 64 bit (precisione doppia). Possiamo rappresentare l'insieme dei numeri di macchina come una quadrupla F(β,t,M1,M2) dove β è la base, t sono i bit per la mantissa, M1 e M2 sono gli estremi dell'intervallo di variabilità dell'esponente (compreso tra M1+1 e M2-1). Per la precisione singola si ha F(2,23,-127,128), con i 32 bit suddivisi nel seguente modo: 1 per il segno, 8 per l'esponente e 23 per la mantissa. Si avrebbero 2^8 = 256 possibili valori per l'esponente, ma dato che i valori 0 e 255 sono usati per rappresentare rispettivamente lo 0 e gli infiniti, restano 254 valori utili, che possono rappresentare esponenti compresi tra -126 e 127. In questo caso abbiamo che il più piccolo numero positivo normalizzato rappresentabile è 2^-126, circa 1.175e-38 (sarebbe 2^-126 x (1.00...00), dove l'ultimo fattore è la mantissa).
Per la precisione doppia si ha F(2,52,-1023,1024) e il più piccolo numero positivo normalizzato rappresentabile è 2^-1022 (circa 2.225e-308).
I valori che hai ottenuto tu sono i più piccoli numeri denormali rappresentabili (2^-149 e 2^-1074). I numeri denormali (o denormalizzati o subnormalizzati) servono per rappresentare numeri che generano underflow, compresi tra 0 e il più piccolo numero positivo normalizzato. Si ottengono mettendo uno zero come prima cifra della mantissa, e usando l'esponente minimo. Per cui, nel caso della precisione singola, il più piccolo numero denormale positivo è 2^-126 x (0.00...01) che è uguale a 2^-149 (perché ci sono 23 cifre nella mantissa e 126 + 23 = 149). Analogamente per la precisione doppia.
Ora non so cosa chiedeva la traccia di preciso.

A me, l'esercizio chiede, di calcolare secondo l'IEEE l'rmin. Quindi in poche parole dovrei stampare alla fine l'rmin1? cosi:
Codice:
#include <stdio.h>

void r_min_Singola_Precisione(double e,int b);

void r_min_Doppia_Precisione (double e,int b);

int main(){
    int b;
    double rmin;
    b=2;
    rmin=1.0;
   
    r_min_Singola_Precisione( rmin, b);
   
    r_min_Doppia_Precisione ( rmin, b);
   
    return 0;
}

void r_min_Singola_Precisione(double e,int b){
    double rmin1;
   
    while((float)(e/b)!=0){
        rmin1=e;
        e=rmin1/b;
    }
   
    printf("rmin in singola precisione e' %g\n", rmin1);
}

void r_min_Doppia_Precisione (double e,int b){
    double rmin1;
   
    while((double)(e/b)!=0){
        rmin1=e;
        e=rmin1/b;
    }
    printf("rmin in doppia precisione e' %g\n", rmin1);
}

e mi da come risultato :
Codice:
rmin in singola precisione e' 2.8026e-045
rmin in doppia precisione e' 9.88131e-324

--------------------------------
Process exited after 0.04533 seconds with return value 0
Premere un tasto per continuare . . .
 
No, non hai capito. Intendevo dire che dovevi stampare rmin1 nel codice che hai scritto nel primo post del topic, ieri. Quello che hai postato oggi pomeriggio era giusto. Sono equivalenti (ragiona sui calcoli). Quello che hai messo ora invece è sbagliato.
 
ho fatto l'altro esercizio nel seguente modo:
Codice:
#include <stdio.h>

void r_min_Singola_Precisione(double e,int b);

void r_min_Doppia_Precisione (double e,int b);

int main(){
    int b;
    double rmin;
    b=2;
    rmin=1.0;
 
    r_min_Singola_Precisione( rmin, b);
 
    r_min_Doppia_Precisione ( rmin, b);
 
    return 0;
}

void r_min_Singola_Precisione(double e,int b){
    double rmin1;


 
    while((float)(e/b)!=0){
        rmin1=e;
        e=rmin1/b;
    }
 
    printf("rmin in singola precisione e' %g\n", e);
}

void r_min_Doppia_Precisione (double e,int b){
    double rmin1;
 
    while((double)(e/b)!=0){
        rmin1=e;
        e=rmin1/b;
    }
    printf("rmin in doppia precisione e' %g\n", e);
}



però mi da come risultato:
Codice:
rmin in singola precisione e' 1.4013e-045
rmin in doppia precisione e' 4.94066e-324

--------------------------------
Process exited after 0.04994 seconds with return value 0
Premere un tasto per continuare . . .
intendi questo? ...scusa ma sto impazzendo...
 
Sì, questo è matematicamente corretto, ma come ti ho scritto nel mio precedente post il programma stampa il più piccolo numero denormale positivo, non so se invece la traccia vuole quello normalizzato. Spero che tu abbia capito la differenza.
 
Non lo so, tra l'altro non capisco l'utilità di un programma del genere dato che basta ragionare sui numeri IEEE per ottenere il risultato, e cioè 2^-126 per la singola precisione e 2^-1022 per la doppia. Mi puoi dire la traccia?
 
Calcolo (stima) di rmin (singola e doppia precisione) .
questa è la traccia...aspe ti metto gli appunti che ho:
rmin:
def.:il più piccolo numero macchina(appartenente ad F, quindi) rappresentabile >0

Nel sistema F(10,3,-3,3)
rmin=0.100 x 10alla-3


var:rmin,rmin1:real

rmin:=1

repeat
rmin1:=rmin
rmin:= rmin/2
until(rmin=0)

NB in questo caso E' INDISPENSABILE salvare il precedente valore di rmin prima di dividere ulteriormente per 2; diventando <<0>>, non potremmo ovviamente tornare , moltiplicando per 2, come invece nel caso dell'epsilon macchina, al valore precedente, <<corretto>> secondo la definizione di rmin!
 
Ah ok perfetto:D. Allora credo che non si possa fare altro, cioè non è chiaro se è corretto considerare anche i numeri denormali, e comunque non saprei come escluderli, perciò credo che l'esercizio sia giusto.
 
Pubblicità
Pubblicità
Indietro
Top