Probleme beim Zuweisen von Werten an Arrayelemente



  • Hallo!

    Ich bin vor kurzem von FORTRAN zu C++ umgestiegen und versuche nun eine Metropolis Monte Carlo Simulation für das Ising Modell zu schreiben.
    Dabei hat man ein Gitter von Spins, von denen jeder die Werte +1 und -1 annehmen kann. Mit Hilfe von Übergangsvorschriften und Zufallszahlen simuliert man dann, welche Werte die Spins des Gitters am "liebsten" annehmen.

    Mein Spinsystem wird im Array

    int spin[V]
    

    abgespeichert. Das Problem ist nun, dass ich in Zeile 43 in main.cpp bei jedem Simulationsschritt einem Element des Arrays einen neuen Wert zuordnen will. Nur scheint das Array das irgendwie zu ignorieren. Es bleibt lange Zeit unverändert und dann auf einmal ändern sich alle Werte.

    Nun debugge ich schon tagelang und es scheint mir alles richtig zu sein. Aber wo liegt dann der Programmierfehler? Vielleicht ist das ja für einen C++ Profi offensichtlich?!

    Wenn ich ein kleines Testprogramm schreibe, in dem ein Array an eine Funktion übergeben wird und diese Funktion einzelne Elemente ändert, so funktioniert alles. Warum funktioniert das bei dem großen Porgramm nicht, obwohl ich es da genauso mache.

    Falls es wichtig ist, ich benutze Ubuntu 11.10, gcc 4.4 und QtCreator

    Bitte helft mir.

    Danke schonmal!

    Hier die Simulation:
    main.h

    #ifndef MAIN_H
    #define MAIN_H
    
    #include <iostream>
    #include <stdlib.h>
    #include <math.h>
    #include <fstream>
    #include <iomanip>
    #include <time.h>
    using namespace std;
    
    // SIMULATION AND SYSTEM PARAMETERS
    const int dim = 2;
    const int Lx = 10, Ly = 10, Lz = 1;
    const int V = Lx*Ly*Lz;
    const double betai = 0.05, betaf = 2.05;              // beta -> beta*J
    const int Nbeta = 5;
    const double H = 0.0;                                 // H    -> H/J
    const int Nsweeps = 10, eqsweeps = 0;
    
    // GLOBAL VARIABLES
    int NNtab[V][2*dim];
    double Rmntab[2*dim+1];
    double Esum, Msum, Mabssum, sqEsum, sqMsum;
    
    // FUNCTIONS
    void Ising_MC(int spin[]);
    void initialization();
    void close();
    int energy(int spin[], int site);
    void NNchart();
    void Rmnchart(double beta);
    void eval(int spin[]);
    void output(int spin[], double beta);
    
    // CLASS DECLARATIONS
    ofstream file_out, system_out;
    clock_t start, end;
    
    #endif // MAIN_H
    

    main.cpp

    //******************************************************//
    //      METROPOLIS MC SIMULATION OF THE ISING MODEL     //
    //******************************************************//
    
    #include <main.h>
    
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // PERFORMS THE MC SIMULATION ACROSS A SPECIFIC PARAMETER INTERVAL
    int main(){
        int spin[V];
        double beta;
    
        fill(spin,spin+V,1);
        initialization();
    
        beta = betai;
        for (int kbeta = 0; kbeta <= Nbeta; kbeta++){
            Rmnchart(beta);
            Ising_MC(spin);
    
            output(spin,beta);
            cout << beta << "\n";
            if(Nbeta != 0) beta += fabs(betaf-betai)/Nbeta;
        }
        close();
        return 0;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // MC SIMULATION ROUTINE FOR CERTAIN PARAMETERS
    void Ising_MC(int spin[]){
        int site;
        int dE;
        double urn,prob;
    
        for(int isw = 1; isw <= Nsweeps; isw++){
            for(int iup = 0; iup < V; iup++){
    
                site = rand() % V;
                dE = energy(spin,site);
    
                urn = (double)rand()/RAND_MAX;
                prob = Rmntab[dim-dE/2];
                if (urn <= prob) spin[site] = -spin[site];
    
                // spin system output zu testzwecken --------------------------------
                spin[site] = 4;
                cout << "\n" <<"\n";
                for(int k = 0; k < Lz; k++){
                    for(int l = 0; l < Ly; l++){
                        for(int m = 0; m < Lx; m++){
                            cout << setw(2) << spin[k*l*m];
                        }
                        cout << "\n";
                    }
                    cout << "\n" << "\n";
                }
                //spin system test end-----------------------------------------------
    
            }
            if (isw > eqsweeps) eval(spin);
        }
        return;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // PROGRAM INITIALIZATION
    void initialization(){
        start = clock();
        srand(time(NULL));
        NNchart();
    
        file_out.open("IsingMC_out.dat");
        system_out.open("IsingSystem_out.dat");
        cout << "\n";
        cout << "METROPOLIS MONTE CARLO SIMULATION OF THE ISING MODEL" << "\n";
        cout << "::::::::::::::::::::::::::::::::::::::::::::::::::::" << "\n";
        cout << "Parameters" << "\n";
        cout << setw(10) << "Lx = " << Lx << setw(10) << "Ly = " << Ly
                 << setw(10) << "Lz = " << Lz << setw(10) << "V = " << V << "\n";
        cout << setw(10) << "H = " << H  << setw(15) << "Nsweeps = " << Nsweeps
                 << setw(20) << "eqsweeps = " << eqsweeps << "\n" << "\n";
        file_out << "METROPOLIS MONTE CARLO SIMULATION OF THE ISING MODEL" << "\n";
        file_out << "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
                 << "::::::::::::::::::::::" << "\n";
        file_out << "Parameters" << "\n";
        file_out << setw(15) << "Lx = " << Lx << setw(15) << "Ly = " << Ly
                 << setw(15) << "Lz = " << Lz << setw(15) << "V = " << V << "\n";
        file_out << setw(15) << "H = " << H  << setw(30) << "Nsweeps = " << Nsweeps
                 << setw(15) << "eqsweeps = " << eqsweeps << "\n";
        file_out << "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
                 << "::::::::::::::::::::::" << "\n";
        file_out << left << setw(15) << "T" << setw(15) << "beta" << setw(15) << "E" << setw(15) << "M"
                         << setw(15) << "|M|" << setw(15) << "C" << setw(15) << "X" << "\n";
        file_out << "----------------------------------------------------------------------------"
                 << "----------------------" << "\n";
        return;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // PROGRAM CLOSING PROCEDURE
    void close(){
        file_out.close();
        system_out.close();
        end = clock();
        cout << "::::::::::::::::::::::::::::::::::::::::::::::::::::" << "\n";
        cout << "\n" << "CPU time in sec: " << (double) end/CLOCKS_PER_SEC << "\n";
        return;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // CALCULATION OF THE ENERGY DIFFERENCE
    int energy(int spin[], int site){
        int dE;
        dE = 0;
        for (int i = 0; i < 2*dim; i++) {
            dE += spin[NNtab[site][i]];
        }
        return dE;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // NEAREST NEIGHBOR ARRAY GENERATOR
    void NNchart(){
        for (int l = 0; l < V; l++){
            NNtab[l][0] = l-1;
            if(l % Lx == 0)     NNtab[l][0] += Lx;
            NNtab[l][1] = l+1;
            if((l+1) % Lx == 0) NNtab[l][1] -= Lx;
    
            if (dim > 1) {
                NNtab[l][2] = l-Lx;
                if(l % (Lx*Ly) < Lx)         NNtab[l][2] += Lx*Ly;
                NNtab[l][3] = l+Lx;
                if(l % (Lx*Ly) >= Lx*(Ly-1)) NNtab[l][3] -= Lx*Ly;
    
                if (dim > 2) {
                    NNtab[l][4] = l-Lx*Ly;
                    if(l % (Lx*Ly*Lz) < Lx*Ly)         NNtab[l][4] += Lx*Ly*Lz;
                    NNtab[l][5] = l+Lx*Ly;
                    if(l % (Lx*Ly*Lz) >= Lx*Ly*(Lz-1)) NNtab[l][5] -= Lx*Ly*Lz;
                }
            }
        }
        return;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // ARRAY OF ALL POSSIBLE EXP VALUES
    void Rmnchart(double beta){
        for (int i = 0; i <= 2*dim; i++){
            Rmntab[i] = min(1.0, exp(-2*beta*(2*dim - 2*i + H)));
        }
        return;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // EVALUATION OF OBSERVABLES
    void eval(int spin[]){
        double E, M;
        E = M = 0.0;
    
        for (int i = 0; i < V; i++){
            for (int jNN =0; jNN < 2*dim; jNN++){
                E += -1/2*spin[i]*spin[NNtab[i][jNN]];
            }
            E += -H*spin[i];
            M += spin[i];
        }
        Esum += E;
        Msum += M;
        Mabssum += fabs(M);
        sqEsum += E*E;
        sqMsum += M*M;
        return;
    }
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // OUTPUT OF AVERAGES AND SPIN SYSTEM
    void output(int spin[], double beta){
        int N = Nsweeps - eqsweeps;
        double C, X;
    
        C = beta*beta*(sqEsum/N - Esum*Esum/(N*N));
        X = beta*(sqMsum/N - Mabssum*Mabssum/(N*N));
    
        system_out << "\n" << "T = " << 1/beta << "\n" <<"\n";
        for(int k = 0; k < Lz; k++){
            for(int l = 0; l < Ly; l++){
                for(int m = 0; m < Lx; m++){
                    system_out << setw(3) << spin[k*l*m];
                }
                system_out << "\n";
            }
            system_out << "\n" << "\n";
        }
    
        file_out << left
                 << setw(15) << 1/beta << setw(15) << beta << setw(15) << Esum/(N*V)
                 << setw(15) << Msum/(N*V) << setw(15) << Mabssum/(N*V) << setw(15) << C/V
                 << setw(15) << X/V <<"\n";
    
        Esum = Msum = Mabssum = sqEsum = sqMsum = 0.0;
        return;
    }
    

    und hier noch das Testprogramm, wo die Zuweisung zu Arrayelementen funktioniert:

    #include<iostream>
    
    using namespace std;
    
    void assignelement(int array[]){
    
        array[1] = 2;
        array[2] = 3;
    }
    
    int main(){
        int array[3] = {1,1,1};
    
        assignelement(array);
    
        cout << array[0] << array[1] << array[2]<<endl;
    
        return 0;
    }
    

  • Mod

    Das ist furchtbar viel Code und furchtbar unübersichtlich. Konkret kann ich an Zeile 43 nix sehen und der Rest ist mir erst einmal zu lang. Aber es fällt auf dem ersten Blick auf: Du machst Fortran in C++. Und zwar im negativen Sinne:
    Google: writing fortran in any language

    Daraus resultieren zwei Probleme:
    1. Es ist furchtbar unübersichtlich. Variablen kannst du in C++ deklarieren, wo du sie brauchst, nicht am Anfang der Funktion. C++ unterstützt Objektorientierung von Haus aus. C++ kann Variablennamen die länger als 1 Zeichen sind. C++ kommt mit jeder Menge fertiger Algorithmen, die vieles abkürzen. C++ kommt mit jeder Menge fertiger Datenstrukturen die für alle praktischen Zwecke das richtige bieten. Insbesondere ein brauchbarer Ersatz für Arrays. In C++ brauchst du so gut wie nie globale Variablen.
    Ein Programm, dass in gutem C++ geschrieben ist, ist schon fast erschreckend robust gegen Programmierfehler, da viele Logikfehler und fast alle technischen Fehler gar nicht erst compilierbar sind.
    2. Manche Sprachfeatures funktionieren in C++ schlichtweg anders als in FORTRAN, insbesondere Arrays, die von C her kommen und im Vergleich mit anderen Datentypen ganz ungewohnte Eigenschaften haben. Kann gut sein, dass du da einen Fehler gemacht hast. Aber wie in 1 schon gesagt, hättest du wahrscheinlich gar keine Arrays gebraucht, sondern, je nachdem wie dein Programm genau funktioniert, std::array oder std::vector. Diese zählen wiederum zu den in 1 genannten Datenstrukturen, bei denen Fehler so gut wie ausgeschlossen oder, falls man doch mal einen macht, sehr viel leichter debugbar sind.



  • Wie siehst du das, dass das Array die falschen Werte enthält? Anhand deiner Testausgabe? Der Zugriff spin[k*l*m] ist ja wahrscheinlich nicht das, was du an der Stelle willst.



  • Wie siehst du das, dass das Array die falschen Werte enthält? Anhand deiner Testausgabe?

    Ja, die Ausgabe sieht so aus:

    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1

    müsste aber eher so aussehen:

    1-1 1 1 1
    1 1 1 1-1
    1-1 1 1 1
    -1-1 1-1 1
    1 1 1-1 1

    Du machst Fortran in C++. Und zwar im negativen Sinne:
    Google: writing fortran in any language

    Kennt denn jemand ein gutes Tutorial explizit um auf objektorientierte Programmierung umzusteigen?


  • Mod

    APE<<&l schrieb:
    Wie siehst du das, dass das Array die falschen Werte enthält? Anhand deiner Testausgabe?

    Ja, die Ausgabe sieht so aus:

    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1
    1 1 1 1 1

    müsste aber eher so aussehen:

    1-1 1 1 1
    1 1 1 1-1
    1-1 1 1 1
    -1-1 1-1 1
    1 1 1-1 1

    Bashar schrieb:

    Der Zugriff spin[k*l*m] ist ja wahrscheinlich nicht das, was du an der Stelle willst.

    Das wird's sein. Da sollen bestimmt noch die Breiten des Arrays beim Berechnen des Index einfließen.



  • Ah jetzt hab ichs kapiert. Ich war zu dumm mein Array richtig auszugeben.
    Danke für den Tipp!


Anmelden zum Antworten