PDA

Visualizza la versione completa : Programmazione in C, funzione pow


martatos
28-12-2015, 14:21
Ciao a tutti! Ho da poco iniziato a programmare in C per un esame, sto facendo un esercizio in cui devo definire una funzione per poi calcolare le X e le Y con un ciclo for nel main

Il problema è che per le x comprese tra -2 e 0 mi da nan una volta che compilo.. cioè nella y in cui è presente pow(x,2./3.) e so che è questo il problema perché ho provato a toglierlo e non mi da più errore.. Se qualcuno può aiutarmi perché non ho idea di cosa non vada :bhò:

Questa è la funzione:

double funz(double x){
double y;
if(x<-2 || x>=2)
y=23./9.;
else if(x>=-2 && x<=0)
y=(3./7.*(cos(x)*sin(x)))-(2./3.*pow(x,(2./3.)));
else
y=(9./5.*log(x+1))-(sqrt(x*x+1));
return y;
}

ing82
28-12-2015, 22:08
Qui (http://forum.html.it/forum/showthread.php?threadid=2918331&postid=25267001&viewfull=1#post25267001) avevo avuto lo stesso problema, mi pare, ed era stato risolto mettendo 2.0/3.0.
Il problema mi sembra lo stesso, da una lettura veloce...sperando di esser stato utile

MItaly
29-12-2015, 02:06
@ing82: non c'entra, scrivere 2. o 2.0 è lo stesso (basta già il punto a specificare che si tratta di double).

@martatos: il problema è che, anche se matematicamente x^(2/3) è ben definito anche sui negativi (in quanto definito come equivalente ad estrarre la radice cubica e poi fare il quadrato), operando in floating point non stai mai lavorando su frazioni esatte, ma sempre su loro approssimazioni finite (per dire, il 2./3. in questione in rappresentazione IEEE 754 di fatto è come se fosse la frazione 6004799503160661/9007199254740992). Per questo motivo, in generale elevare un numero negativo ad un numero floating point non ha nessun senso (visto che il fatto che venga fuori un numero immaginario o meno viene a dipendere dal fatto che per puro caso il risultato approssimato sia rappresentabile con una frazione con denominatore pari o dispari); di conseguenza, pow fallisce sempre se le si passa una base negativa e un esponente non intero.

Per ovviare al tuo problema, puoi semplicemente fare pow(-x, 2./3.), riportandoti così al caso in cui x è positivo (e matematicamente x^(2/3) è uguale a (-x)^(2/3), visto che il 2 uccide il segno).

M.A.W. 1968
29-12-2015, 15:57
Per completezza, aggiungo che prima di cimentarsi nell'uso di calcoli in C usando il FP IEEE 754 è opportuno studiare nell'ordine almeno questo (http://floating-point-gui.de/) e a seguire questo (https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) (se si preferisce, in un più completo formato PDF stampabile (https://ece.uwaterloo.ca/~dwharder/NumericalAnalysis/02Numerics/Double/paper.pdf)), sperabilmente seguiti da un testo di analisi numerica (http://www.ioprogrammo.it/index.php/topic=13654.5).

Aggiungerei solo che, in casi del genere, un idioma generalmente caldeggiato in letteratura è il seguente:


pow(x*x,1./3.);

ing82
29-12-2015, 17:22
Mi sembrava troppo semplicistico quanto da me ipotizzato, e infatti così era: intanto però ne ho imparata un'altra, e qualche link di materiale serio serve sempre!

Grazie

martatos
30-12-2015, 16:58
@ing82 @MItaly Grazie mille per l'interessamento e per l'aiuto!
L'altro giorno alla fine ero riuscita a risolvere perché invece di scrivere pow(x,(2./3.)) ho usato l'operatore per la conversione double quindi pow(x,(double)(2/3)), perché ho pensato che il pow richiede solo double come argomenti -> pow(double,double) e infatti così non mi ha più dato problemi, il programma funzionava..Quello che non capisco è perché 2./3. non me lo riconosceva come double mentre double(2./3.) sì anche se in realtà lo sono entrambi....:confused:
Ho provato anche con pow(-x, 2./3.) come hai detto tu @MItaly e anche così funziona, quindi grazie mille!

MItaly
30-12-2015, 18:52
@ing82 @MItaly Grazie mille per l'interessamento e per l'aiuto!
L'altro giorno alla fine ero riuscita a risolvere perché invece di scrivere pow(x,(2./3.)) ho usato l'operatore per la conversione double quindi pow(x,(double)(2/3)), perché ho pensato che il pow richiede solo double come argomenti -> pow(double,double) e infatti così non mi ha più dato problemi, il programma funzionava..Quello che non capisco è perché 2./3. non me lo riconosceva come double mentre double(2./3.) sì anche se in realtà lo sono entrambi....:confused:

Se scrivi (double)(2/3) ottieni sempre 0: visto che 2 e 3 sono interi fa una divisione intera (e 2/3 in divisione intera dà 0), e poi converte il risultato a double; invece che NaN ottenevi sempre 1. :D

Loading