Ciclo for o non ciclo for: questo è il problema!
Buonasera a tutti!
Vi pongo un problema in cui mi sono imbattuta nei tre giorni appena trascorsi: sto lavorando ad un programma scritto in C++ mediante il quale ricavare il raggio spettrale di una matrice al variare di un certo coefficiente "tau" (in particolare devo verificare la stabilità del metodo FTCS) e mi sono accorta che ottengo risultati diversi se faccio variare "tau" con un ciclo for o se lo faccio variare "manualmente", cioè cambiando di volta in volta il suo valore prima di compilare ogni volta il programma.
Chiedo scusa a quanti stanno leggendo il mio post, come avrete capito sono una principiante, quindi mi scuso soprattutto per il linguaggio che sto usando, probabilmente inappropriato .
Il programma è il seguente (non so se possa essere utile):
#include
#include
#include
#include
using namespace std;
int main()
{
int N=101;
double I[101][101], D[101][101], A[101][101], B[101][101];
double sum;
double rho;
double tau=0.000000001;
double h=0.01;
double t=(h*h)/2;
ofstream file("B.dat");
for(int i=0; i
{
for(int j=0; j
{
if(i==j)
{
I[j]=1;
}
else
{
I[j]=0;
}
}
}
for(int i=0; i
{
for(int j=0; j
{
if(j==i+1)
{
if(j==0)
{
D[j]=0;
}
else
{
D[j]=1;
}
}
else if(j==i)
{
if(j==0 || j==N-1)
{
D[j]=0;
}
else
{
D[j]=-2;
}
}
else if(j==i-1)
{
if(j==0)
{
D[j]=0;
}
else
{
D[j]=1;
}
}
else
{
D[j]=0;
}
}
}
while(tau<=100)
{
for(int i=0; i
{
for(int j=0; j
{
if(i==j)
{
double c=tau/(2*t);
A[j]=I[j]+c*D[j];
B[j]=A[j]*A[j];
sum+=B[j];
}
}
}
rho=sqrt(sum);
file << tau << "\t" << rho << endl;
tau*=10;
}
fflush(stdin);
return 0;
}
NON utilizzando il ciclo for ottengo valori del raggio spettrale che si aggirano tutti intorno ai 10, finchè non si ha -giustamente- divergenza, mentre se USO il ciclo for l'ordine di grandezza è lo stesso, però i valori sono diversi tra loro.
Il mio quesito è: qualcuno potrebbe avvertirmi se sto sbagliando qualcosa e se sì per quale motivo?
Vi ringrazio anticipatamente,
Francesca
Vi pongo un problema in cui mi sono imbattuta nei tre giorni appena trascorsi: sto lavorando ad un programma scritto in C++ mediante il quale ricavare il raggio spettrale di una matrice al variare di un certo coefficiente "tau" (in particolare devo verificare la stabilità del metodo FTCS) e mi sono accorta che ottengo risultati diversi se faccio variare "tau" con un ciclo for o se lo faccio variare "manualmente", cioè cambiando di volta in volta il suo valore prima di compilare ogni volta il programma.
Chiedo scusa a quanti stanno leggendo il mio post, come avrete capito sono una principiante, quindi mi scuso soprattutto per il linguaggio che sto usando, probabilmente inappropriato .
Il programma è il seguente (non so se possa essere utile):
#include
#include
#include
#include
using namespace std;
int main()
{
int N=101;
double I[101][101], D[101][101], A[101][101], B[101][101];
double sum;
double rho;
double tau=0.000000001;
double h=0.01;
double t=(h*h)/2;
ofstream file("B.dat");
for(int i=0; i
for(int j=0; j
if(i==j)
{
I[j]=1;
}
else
{
I[j]=0;
}
}
}
for(int i=0; i
for(int j=0; j
if(j==i+1)
{
if(j==0)
{
D[j]=0;
}
else
{
D[j]=1;
}
}
else if(j==i)
{
if(j==0 || j==N-1)
{
D[j]=0;
}
else
{
D[j]=-2;
}
}
else if(j==i-1)
{
if(j==0)
{
D[j]=0;
}
else
{
D[j]=1;
}
}
else
{
D[j]=0;
}
}
}
while(tau<=100)
{
for(int i=0; i
for(int j=0; j
if(i==j)
{
double c=tau/(2*t);
A[j]=I[j]+c*D[j];
B[j]=A[j]*A[j];
sum+=B[j];
}
}
}
rho=sqrt(sum);
file << tau << "\t" << rho << endl;
tau*=10;
}
fflush(stdin);
return 0;
}
NON utilizzando il ciclo for ottengo valori del raggio spettrale che si aggirano tutti intorno ai 10, finchè non si ha -giustamente- divergenza, mentre se USO il ciclo for l'ordine di grandezza è lo stesso, però i valori sono diversi tra loro.
Il mio quesito è: qualcuno potrebbe avvertirmi se sto sbagliando qualcosa e se sì per quale motivo?
Vi ringrazio anticipatamente,
Francesca
Risposte
To consiglio di usare il tag
Comunque, intendi dire che se scrivi qualcosa tipo:
per 10 volte consecutive anzichè usare il ciclo while ottieni $ tau = 10 $ ?
Invece col ciclo while ottieni valori compresi tra -10 e +10?
codeper rendere più leggibile il codice.
Comunque, intendi dire che se scrivi qualcosa tipo:
for(...)
for(...)
calcolo sum
calcolo rho
incremento tau
for(...)
for(...)
calcolo sum
calcolo rho
incremento tau
per 10 volte consecutive anzichè usare il ciclo while ottieni $ tau = 10 $ ?
Invece col ciclo while ottieni valori compresi tra -10 e +10?
Ho cambiato qualcosa e commentato. Dando principalmente qualche suggerimento per semplificare il codice. L'output è esattamente lo stesso del tuo.
Come puoi leggere dal codice che ti ho postato c'é una parte che non ho modificato (tranne un paio di preferenze stilistiche mie) e che a mio avviso è sbagliata:
Tieni conto che quel codice è equivalente a
Immagino invece che il tutto vada espresso in forma matriciale come A = cD + I, B=A*A (component-wise o come matrice) e sum come la somma degli elementi di B... Se è così il calcolo è ben diverso.
Tieni conto che esistono modi comodi e compatti per salvare matrici tridiagonali come sono I, D e immagino A e B. Inoltre non è detto che convenga avere A invece che semplicemente sommare per A*A... Il tutto, tra l'altro con più cicli più comodi come quello che ho usato per scrivere D.
Comunque il tuo problema con il ciclo è senza dubbio il problema di inizializzazione di sum... Ma secondo me il programma è probabilmente sbagliato in ogni caso.
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <fstream>
using namespace std;
int main()
{
unsigned int const N = 101; // meglio metterlo in const.
//hai definito una variabile per la definizione, allora usala. Inoltre ho mandato I e D a zero.
double I[N][N] = { 0 }, D[N][N] = { 0 }, A[N][N], B[N][N];
//somma non inizializzata. ATTENZIONE la prossima volta. Non sono sicuro però vada inizializzato qui.
double sum=0.0;
double rho;
double tau = 1E-9; // scrittura equivalente ma penso più espressiva.
double const h = 0.01; // penso sia anche questa costante.
double t = (h*h)/2;
// Per definire su I la matrice identità ho cambiato il tuo codice mettendo tutto a zero
// nella definizione e ora modificando solo gli elementi sulla diagonale.
// Molto più semplice, non ti sembra?
for(unsigned int i=0; i!=N; ++i)
{
I[i][i] = 1.0;
}
// La definizione di D è difficile da capire così e troppo lunga.
// Ho messo a 0 tutto e ora scrivo sopra solo le cose essenziali.
// Alcune tue condizioni tra l'altro hanno poco senso come chiedersi se j==0 sapendo che j == i+1>= 1
// Il mio codice dà per scontato che N >= 3. Non penso sia particolarmente restrittivo.
// In caso bisognerebbe aggiungere un test su N (che verrebbe selezionato in fase di compilazione).
// Controlla se ho preso in considerazione tutti i casi. Tieni conto che tutto il resto è 0.
D[0][1] = 1.0;
D[1][1] = -2.0;
D[1][2] = 1.0;
for(unsigned int i=2; i!=N-1; ++i)
{
D[i][i-1] = 1.0;
D[i][i] = -2.0;
D[i][i+1] = 1.0;
}
D[N-1][N-2] = 1.0;
// meglio aprire i file dove li usi. Tanto non ha alcun limite a dove definire una variabile.
// Eventualmente potevi creare prima ed aprire dopo.
ofstream file("B.dat");
while(tau <= 100)
{
// questa parte non ha senso. Stai facendo una operazione solo nel caso in cui sono uguali,
// a quel punto creare 4 matrici era inutile... Penso che in questo ciclo ci sia un errore grave.
for(unsigned int i=0; i!=N; ++i)
{
for(unsigned int j=0; j!=N; ++j)
{
if(i==j)
{
double const c=tau/(2*t);
A[i][j]=I[i][j]+c*D[i][j];
B[i][j]=A[i][j]*A[i][j];
sum+=B[i][j];
}
}
}
rho=sqrt(sum);
file << tau << "\t" << rho << endl;
tau*=10.0;
}
// è inutile usare fflush su stdin anche considerando che non usi stdio ma iostream (non so come fa a compilare).
// il comportamento di fflush su uno stream di input non è neanche uniforme a seconda della libreria che usi
// non essendo specificato nello standard. Chi te l'ha insegnato come minimo dovrebbe ripassarsi lo standard C.
// Attenzione inoltre che non hai chiuso il file.
file.close();
return 0;
}
Come puoi leggere dal codice che ti ho postato c'é una parte che non ho modificato (tranne un paio di preferenze stilistiche mie) e che a mio avviso è sbagliata:
for(unsigned int i=0; i!=N; ++i)
{
for(unsigned int j=0; j!=N; ++j)
{
if(i==j)
{
double const c=tau/(2*t);
A[i][j]=I[i][j]+c*D[i][j];
B[i][j]=A[i][j]*A[i][j];
sum+=B[i][j];
}
}
}Tieni conto che quel codice è equivalente a
for(unsigned int i=0; i!=N; ++i)
{
double const c=tau/(2*t);
A[i][i]=I[i][i]+c*D[i][i]; // o anche = 1+c*D[i][i]; fare un if è inutile... Il più delle volte è 1-2c
B[i][i]=A[i][i]*A[i][i];
sum+=B[i][i];
}Immagino invece che il tutto vada espresso in forma matriciale come A = cD + I, B=A*A (component-wise o come matrice) e sum come la somma degli elementi di B... Se è così il calcolo è ben diverso.
Tieni conto che esistono modi comodi e compatti per salvare matrici tridiagonali come sono I, D e immagino A e B. Inoltre non è detto che convenga avere A invece che semplicemente sommare per A*A... Il tutto, tra l'altro con più cicli più comodi come quello che ho usato per scrivere D.
Comunque il tuo problema con il ciclo è senza dubbio il problema di inizializzazione di sum... Ma secondo me il programma è probabilmente sbagliato in ogni caso.