Integrali con il metodo montecarlo
ciao, vorrei calcolare con il metodo montecarlo l'integrale definito di $x^2$ tra 0 e b...
l'output è 0... non capisco perchè.
#include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> main() { int i,n; double x[1000],b,y[1000],k[1000],area; printf("Questo programma calcola l'integrale definito con il metodo montecarlo di x^2 da 0 a b\n"); printf("Quanti numeri casuali vuoi generare?"); scanf("%d",&n); printf("inserisci l'estremo di integrazione superiore"); scanf("%lf",&b); srand(time(NULL)); k[1]=0; for (i=1;i<=n;i++) { x[i]=rand()*b/RAND_MAX; y[i]=rand()*b*b/RAND_MAX; if (y[i]<=x[i]*x[i]) { k[i]=k[i]+y[i]/y[i]; } } area=b*b*b*k[i]/n; printf("l'area sottesa dalla parabola è %lf",area); }
l'output è 0... non capisco perchè.
Risposte
Ciao!
Ho letto il tuo programma. Non ho capito che metodo vuoi utilizzare, in ogni modo, è davvero originale!
Ti restituisce 0 perché non sommi le aree elementari.
Ho letto il tuo programma. Non ho capito che metodo vuoi utilizzare, in ogni modo, è davvero originale!
Ti restituisce 0 perché non sommi le aree elementari.
ciao, non ci sono aree elementari..... il metodo che uso lo trovi spiegato in questo sito
http://it.wikipedia.org/wiki/Metodo_Monte_Carlo
http://it.wikipedia.org/wiki/Metodo_Monte_Carlo
Quello che stai usando è spesso chiamato 'rejection sampling' ed è certamente un metodo Monte Carlo valido per calcolare il tuo integrale, ma incredibilmente inefficiente. Stai infatti prendendo campioni da una superficie di area \(b^3\), ignorando tutti quelli che non fanno parte di una superficie di area \( b^3/3 \). Abbiamo quindi che i \(2/3\) di tutti i campioni verranno ignorati.
Ma la causa dell'errore non è nel metodo, ma nell'uso degli array. Non sono affatto necessari e li stai usando nel modo sbagliato. Per prima cosa gli indici degli array in C partono da 0, perché parti quindi da 1? Manca quindi la verifica che il numero di punti generato sia inferiore a 1000, un numero MOLTO PICCOLO per questo metodo... Inoltre stai aggiornando tutti i k[ i ] separatamente, quando dovresti calcolare una somma globale. La riga
avrebbe al massimo dovuto essere uguale a
e avresti dovuto inizializzare k[0] a 0 e non k[1]. Ma tira via tutti gli indici e il codice verrebbe corretto.. Si fa molto prima e il codice richiede anche meno memoria..
Ma se proprio vuoi usare un metodo Monte Carlo per calcolare questo integrale, allora il metodo da utilizzare è diverso. Quello che stai infatti calcolando non è tecnicamente l'integrale della funzione \(x^2\), ma quello della funzione in due variabili che è uguale a zero nella regione del piano \(y > x^2\) e uguale a uno altrimenti. Questo metodo è comodo quando si deve lavorare con una regione di uno spazio che non sia esprimibile globalmente come una funzione di un numero inferiore di variabili. Wikipedia ha presentato questo metodo come IL metodo di integrazione Monte Carlo, ma tecnicamente non è quello che hanno presentato. Quello che normalmente si fa è generare numeri casuali solo per la \(x\) e quindi sommare tutti i contributi \( f(x)/b \) per ogni campione.
Ma la causa dell'errore non è nel metodo, ma nell'uso degli array. Non sono affatto necessari e li stai usando nel modo sbagliato. Per prima cosa gli indici degli array in C partono da 0, perché parti quindi da 1? Manca quindi la verifica che il numero di punti generato sia inferiore a 1000, un numero MOLTO PICCOLO per questo metodo... Inoltre stai aggiornando tutti i k[ i ] separatamente, quando dovresti calcolare una somma globale. La riga
k[i]=k[i]+y[i]/y[i];
avrebbe al massimo dovuto essere uguale a
k[i] = k[i-1] + 1.0;
e avresti dovuto inizializzare k[0] a 0 e non k[1]. Ma tira via tutti gli indici e il codice verrebbe corretto.. Si fa molto prima e il codice richiede anche meno memoria..
Ma se proprio vuoi usare un metodo Monte Carlo per calcolare questo integrale, allora il metodo da utilizzare è diverso. Quello che stai infatti calcolando non è tecnicamente l'integrale della funzione \(x^2\), ma quello della funzione in due variabili che è uguale a zero nella regione del piano \(y > x^2\) e uguale a uno altrimenti. Questo metodo è comodo quando si deve lavorare con una regione di uno spazio che non sia esprimibile globalmente come una funzione di un numero inferiore di variabili. Wikipedia ha presentato questo metodo come IL metodo di integrazione Monte Carlo, ma tecnicamente non è quello che hanno presentato. Quello che normalmente si fa è generare numeri casuali solo per la \(x\) e quindi sommare tutti i contributi \( f(x)/b \) per ogni campione.
grazie adesso funziona perfettamente... per chi fosse interessato il codice corretto è:
#include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> main() { int i,n; double x[10000],b,y[10000],k=0,area; printf("Questo programma calcola l'integrale definito con il metodo montecarlo di x^2 da 0 a b\n"); printf("Quanti numeri casuali vuoi generare?"); scanf("%d",&n); printf("inserisci l'estremo di integrazione superiore"); scanf("%lf",&b); srand(time(NULL)); for (i=1;i<=n;i++) { x[i]=rand()*b/RAND_MAX; y[i]=rand()*b*b/RAND_MAX; if (y[i]<pow(x[i],2)) { k=k+y[i]/y[i]; } } area=b*b*b*k* (pow(n,-1)); printf("l'area è: %lf",area); }
Non c'è motivo di usare pow e, come ti ho già scritto nel mio precedente post, \( y_i / y_i = 1 \).. Per cui non c'è motivo di fargli fare un calcolo quando hai già il risultato corretto.. Per il resto mi sembra ok. Anche gli altri due array non sono comunque necessari.
un'ultima cosa se hai tempo... ho modificato il programma precedente e adesso mi calcola l'integrale definito non più tra 0 e b ma tra due estremi $a$ e $b$. Tuttavia ho utilizzato un metodo barbaro: mi sono calcolato l'integrale definito da 0 a $b$, poi mi sn calcolato l'integrale da 0 ad $a$ e poi ho fatto la differenza delle aree.
Il metodo corretto secondo me sarebbe quello di generare numeri casuali tra due estremi a e b
, e poi calcolarsi l'integrale, tuttavia faccio fatica a farlo.... come posso combinare il tutto? dovrei fare un ciclo while e dentro il while un ciclo for?
#include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> main() { int i,j,n; double x,b,y,k=0,area,a,X,Y,K=0,Area; printf("Questo programma calcola l'integrale definito con il metodo montecarlo di x^2 \n"); printf("Quanti numeri casuali vuoi generare?"); scanf("%d",&n); printf("inserisci l'estremo di integrazione superiore"); scanf("%lf",&b); printf("inserisci l'estremo di integrazione inferiore"); scanf("%lf",&a); srand(time(NULL)); for (i=1;i<=n;i++) { x=rand()*b/RAND_MAX; y=rand()*b*b/RAND_MAX; if (y<pow(x,2)) { k=k+1; } } area=b*b*b*k* (pow(n,-1)); for (j=1;j<=n;j++) { X=rand()*a/RAND_MAX; Y=rand()*a*a/RAND_MAX; if (Y<pow(X,2)) { K=K+1; } } Area=area-a*a*a*K* (pow(n,-1)); printf("l'area è: %lf",Area); }
Il metodo corretto secondo me sarebbe quello di generare numeri casuali tra due estremi a e b
#include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> main() { int i,n,y[100]; double a,b,x[100]; printf("Questo programma genera numeri casuali "); printf("Quanti numeri casuali vuoi generare ?\n"); scanf("%d",&n); printf("Da quale numero vuoi iniziare a generare numeri casuali?\n"); scanf("%lf",&a); printf("Fino a quale numero vuoi generare numeri casuali?"); scanf("%lf",&b); srand(time(NULL)); i=1; while (i<=n) { y[i]=rand(); x[i]=b*y[i]/RAND_MAX; if (x[i]>=a) { printf("%lf \n",x[i]); i++; } } }
, e poi calcolarsi l'integrale, tuttavia faccio fatica a farlo.... come posso combinare il tutto? dovrei fare un ciclo while e dentro il while un ciclo for?
No, devi semplicemente generare numeri casuali nel corretto intervallo. Siccome sto scrivendo con uno smartphone mi viene difficile scriverti il codice ma corrisponde a generare un numero casuale tra zero e $(b-a)$ e poi sommare $a$ a questo numero.
ciao... ho provato a fare come dici ma non viene
#include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> main() { int i,n; double x,b,y,k=0,area,a; printf("Questo programma calcola l'integrale definito con il metodo montecarlo di x^2 \n"); printf("Quanti numeri casuali vuoi generare?"); scanf("%d",&n); printf("inserisci l'estremo di integrazione superiore"); scanf("%lf",&b); printf("inserisci l'estremo di integrazione inferiore"); scanf("%lf",&a); srand(time(NULL)); for(i=1;i<=n;i++) { x=(rand()*(b-a)/RAND_MAX)+a; y=(rand()*(b*b-a*a)/RAND_MAX)+a*a; if(y<pow(x,2)) { k=k+1; } } area=(b-a)*b*b*k*(pow(n,-1)); printf("L'area sottesa è: %lf \n",area); }
up
Ma in che senso non funziona? Ad una prima occhiata e prova a me sembra funzionare..
il risultato numerico è scorretto... per esempio:
Questo programma calcola l'integrale definito con il metodo montecarlo di x^2
Quanti numeri casuali vuoi generare?1000
inserisci l'estremo di integrazione superiore3
inserisci l'estremo di integrazione inferiore2
L'area sottesa è: 4.194000
il risultato corretto sarebbe 19/3 che è diverso da 4.19
Questo programma calcola l'integrale definito con il metodo montecarlo di x^2
Quanti numeri casuali vuoi generare?1000
inserisci l'estremo di integrazione superiore3
inserisci l'estremo di integrazione inferiore2
L'area sottesa è: 4.194000
il risultato corretto sarebbe 19/3 che è diverso da 4.19
Il metodo Montecarlo è un metodo MOLTO poco efficiente per il calcolo di integrali in dimensioni molto basse. Sono in effetti altre le situazioni in cui vengono utilizzati questi metodi (può per esempio funzionare in modo egregio anche in situazioni in cui la dimensione dello spazio dal quale vengono campionati i punti sia infinito). Per poter quindi fare qualsiasi discorso di correttezza devi per prima cosa riprovare più volte il risultato. Un singolo test non significa molto. Conviene inoltre aumentare il numero di punti in modo da diminuire la varianza del risultato. Direi di provare con qualcosa come 100000.