Implementierung der "Korrigierten Stichprobenvarianz" in C++



  • Hallo liebe Leute,

    ich bin Neuling im Programmieren. Ich studiere Mathematik und muss eine Programmieraufgabe bearbeiten, die wie folgt aussieht:

    [edit]

    Aufgabe:
    In dieser Aufgabe sollen Sie das arithmetische Mittel und die korrigierte Stichprobenvarianz eines Arrays von Zahlen bestimmen. Ist eine Stichprobe von n Werten x_1,...,x_n\displaystyle x\_1, ... , x\_n gegeben, so ist das arithmetische Mittel x definiert als:

    y:=1ni=1n(xi)\displaystyle y:=\frac{1}{n}\sum_{i=1}^n\left(x_i\right).

    Die korrigierte Stichprobenvarianz s² ist definiert als:

    s2:=1n1i=1n(xiy)2\displaystyle s^2:=\frac{1}{n-1}\sum_{i=1}^n\left(x_i-y\right)^2.

    Schreiben Sie ein Programm, das: (ich kürz das mal ab)
    1. Auffordert n einzugeben.
    2. Die einzelnen xix_i einliest und in einem Array speichert.
    3. y und s² berechnet und ausgibt.

    Juhuu es funktioniert 😃 Vielen lieben Dank an SeppJ 🙂

    SeppJ schrieb:

    [...]
    Oder für komplexe Formeln gibt es die Latex-Blöcke:
    s2:=1n1i=1n(xiy)2\displaystyle s^2:=\frac{1}{n-1}\sum_{i=1}^n\left(x_i-y\right)^2

    Wie ich das alles genau gemacht habe, kann man sehen, indem man meinen Beitrag zitiert.

    [/edit]

    Ich habe nun alles programmiert, jedoch kriege ich eine falsche Varianz raus. Könnt ihr mir sagen warum?

    #include <iostream>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    using namespace std;
    
    int main() {
      int n;
      double summe;
      double armit;
      double summeneu;
      double varianz;
    
      cout << "Geben Sie die Größe der Stichprobe an " << endl;
      cin >>n;
    
      double *x;
      x=(double*)malloc(n*sizeof(double));
    
      for (int i = 1; i<=n; i=i+1) {
        cout << "Geben Sie den " << i << "-ten Wert an " << endl;
        cin >> x[i-1];
      }
    
      for (int i=0; i<n; i=i+1) {
        cout << x[i] <<" "<<endl;
      }
    
      summe=0.;
      for (int i=0; i<=n; i++) {
        summe=summe+x[i];
      }
    
      double N = n;
      armit=(1/N)*summe;
      cout <<"Die Summe ist " << summe << " " << endl;
      cout <<"Das arithmetische Mittel ist "<< armit << " "<<endl;
    
      double q = armit;
    
      summeneu = 0.;
      for (int i=0; i<=n; i=i+1) {
        summeneu=summeneu+(pow((x[i]-q),2));
      }
      varianz=(1/(N-1))*summeneu;
      cout <<"Die korrigierte Stichprobenvarianz ist "<< varianz << " "<<endl;
    
      free(x);
    }
    

    Danke schon mal im Voraus 🙂

    Tut mir leid, ich weiß nicht wie ich die ganzen Zeichen auch richtig anzeigen lassen soll (Σ z.B.)

    [edit2]

    Okay danke an alle die geantwortet haben 🙂

    ich habe im Code nun folgendes verändert und es funktioniert:

    L30: for (int i=0; i<n; i++)
    L42: for (int i=0; i<n; i=i+1)
    

    [/edit2]



  • Die zweite schleife läuft von 0 bis n, das sind n+1 iterationen, also eine zu viel.

    Nebenbei bemerkt ist Dein Code recht schräger mischmasch aus C und C++. Ich schieb dich mal ins C++-Forum, da kann man Dir sicher einige nützliche Hinweise geben.



  • Dieser Thread wurde von Moderator/in Jester aus dem Forum Mathematik und Physik in das Forum C++ (alle ISO-Standards) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.


  • Mod

    Was Jester sagte. Du solltest Schleifen möglichst immer mit < statt <= formulieren. Und lass sie auch bei 0 los laufen, wenn der erste Index 0 ist, anstatt von 1 und dann immer minus 1 zu rechnen. Dann sieht man schneller, über welche und wie viele Werte die Schleifen laufen und Fehler wie dieser hier passieren nicht so leicht.

    Allgemein noch der Hinweis, dass dies nicht wirklich ist, wie man arithmetisches Mittel und Varianz berechnen würde. Das ist wohl nur als "Vereinfachung" für Programmieranfänger gemeint. Eine bessere Methode kommt ganz ohne Zwischenspeicher aus, macht alles in einem Durchlauf und ist zudem noch numerisch stabiler. Man muss bloß Mathematik anwenden. Komisch, dass ihr das im Mathematikstudium nicht benutzt. So geht's:

    #include <iostream>
    #include <cmath>
    
    int main()
    {
      unsigned int N = 0;  // Anzahl der Werte
      double mean = 0;     // Mittelwert, wird laufend aktualisiert
      double m2 = 0;       // Quadratische Abweichung vom Mittelwert, wird laufend aktualisiert
      for(double value ; std::cin >> value; )
        {
          ++N;
          double delta = value - mean;
          mean += delta / N;
          m2 += delta*(value - mean);
        }
      double S2 = m2 / (N - 1);  // Stichprobenvarianz
    
      // Optional: Berechnung der Fehlerstreuung der Größen:
      double lg1 = std::lgamma(0.5*N);
      double lg2 = std::lgamma((0.5*(N-1)));
      double Kn = std::sqrt(2./(N-1))*std::exp(lg1 - lg2);
      double sdev = Kn * std::sqrt(S2);
      double delta_sdev = sdev *std::sqrt(1./(Kn*Kn)-1);
    
      // Ausgabe: Arithmetisches Mittel, Standardfehler des Mittels, Standardabweichung der Stichprobe, Standardfehler der Standardabweichung der Stichprobe
      std::cout << mean << '\t' << sdev / std::sqrt(N) << '\t' << sdev << '\t' << delta_sdev << '\n';
    }
    

    Nachzulesen geht das, wenn ich mich recht erinnere, in "The Art of Computer Programming".



  • viklut schrieb:

    Hallo liebe Leute

    Tut mir leid, ich weiß nicht wie ich die ganzen Zeichen auch richtig anzeigen lassen soll (Σ z.B.)

    Hallo, versuche mal (ungetestet):

    #include <locale>
    
    int main() {
      std::wcout.imbue(std::locale::global(std::locale("")));
    
      ...
    
      std::wcout << L"\u03C3 - Sigma\n";
    }
    

    So klappert das hier unter Linux zumindest (alles utf-8, Terminal, Editor etc...)

    Wenn dein Editor auf utf-8 gestellt ist kannst du auch öäü usw eingeben.
    Aber immer L"" statt "" benutzen. zumindest wenn Umlaute drin sind.

    Ach ja, besser dann nicht wcout und cout mischen...

    hth
    dirkski

    Edit: Ich weiß nicht ob nach C++-Standard überhaupt Nicht-Ascii-Zeichen
    im Quellcode erlaubt sind oder ob's nur geduldet wird...


  • Mod

    Ich glaube, er meint, wie er die Zeichen im Forum richtig anzeigen lassen kann 😉

    Unter dem Editfenster sind eine Menge Knöpfe. Da sind unter anderem griechische Buchstaben: Σ. Das funktioniert nicht innerhalb von Codeblöcken, denn Codeblöcke sind nun einmal primär für Code da (wo solch eine Ersetzung unerwünscht wäre) und nicht für Zitate, dafür wären die Quote-Blöcke:

    Aufgabenstellung schrieb:

    s²:= (1/(n-1))* Σ von i=1 bis n von (xi - y)².

    Oder für komplexe Formeln gibt es die Latex-Blöcke:
    s2:=1n1i=1n(xiy)2\displaystyle s^2:=\frac{1}{n-1}\sum_{i=1}^n\left(x_i-y\right)^2

    Wie ich das alles genau gemacht habe, kann man sehen, indem man meinen Beitrag zitiert.



  • SeppJ schrieb:

    Ich glaube, er meint, wie er die Zeichen im Forum richtig anzeigen lassen kann 😉

    Ja, war ich auch am überlegen. Aber er hatte ja das Sigma-Zeichen schon im
    ursprünglichen Post drin, daher dachte ich er meinte die Ausgabe seines Programms...

    Ich habe früher immer QStrings verwendet und hatte nie Probleme mit Umlauten.
    Als ich dann mal auf std::string gewechselt bin stand ich wie ein Ochs' vorm Berg 😃

    Je nach Terminal-Einstellung kam nur murks raus. Dann hatte ich std::wstring
    probiert und es kam ... nix 😕

    So mit der locale ging's dann perfekt, dachte daher als Tipp...

    Wobei mich interessieren würde ob das so der richtige Weg ist, also
    nicht nur hier bei mir klappt...

    Einen schönen Abend noch
    dirkski


  • Mod

    dirkski schrieb:

    Wobei mich interessieren würde ob das so der richtige Weg ist, also
    nicht nur hier bei mir klappt...

    Das ist ein bisschen ein schwieriges Thema, wenn es dich genau interessiert, solltest du einen eigenen Thread dazu aufmachen. Ich bin ja ein Fan der Devise UTF-8 everywhere, wodurch das alles überhaupt kein Problem wäre. Dummerweise ist die Welt nicht so schön wie sie sein könnte und daher muss man manchmal zu solchen Hacks greifen, wie du sie gezeigt hast.



  • SeppJ schrieb:

    Dummerweise ist die Welt nicht so schön wie sie sein könnte und daher muss man manchmal zu solchen Hacks greifen, wie du sie gezeigt hast.

    Mist! Und ich dachte das ist der richtige Weg. Als ich das erste mal std::wcout
    benutzt habe klappte das immer nur bis zum ersten Umlaut, danach Schluß!

    Nach langem Suchen und probieren hatte ich das mit der locale rausbekommen.
    Dann hab ich mich aufgeregt warum man die extra setzen muss. Mit std::locale("")
    wird die locale der Benutzereinstellung gesetzt.
    Default steht sie ja auf, brr lass mich raten "LC_ALL". Naja, dann hab
    ich mir gedacht ist ok so weil Unix-Kommandos in Scripten halt Englische
    Ausgaben auswerten müssen, daher halt besser so.

    Aber jetzt schockierst du mich 😃

    Dachte das Texte eines Programms was nur wcout benutzt, Umlaute im Quellcode
    mit utf-8 codiert, sowie die locale richtig gesetzt hat sagen wir mal auf einen latin-1 Maschine
    trotzdem richtig ausgegeben werden. (was für ein Satz)

    Shit, steh ich ja wieder am Anfang...

    So, Nacht...

    dirkski


  • Mod

    Versteh das nicht falsch: Dein Weg ist schon korrekt. Er ist bloß ein bisschen umständlich im Vergleich zum Fall, wenn man wirklich konsequent UTF-8 durchziehen würde. Bei meinem Linuxsystem kann ich einfach cout << "∑"; schreiben und es funktioniert wie erwartet, ohne dass ich mich um locales oder Zeichencodierungen kümmern müsste. Aber hier im Forum kann ich nicht einfach direkt ein ∑ in das Editorfenster setzen, weil irgendeine der vielen Zwischenstationen daraus dumme HTML-Codes macht.



  • SeppJ schrieb:

    Versteh das nicht falsch: Dein Weg ist schon korrekt. Er ist bloß ein bisschen umständlich im Vergleich zum Fall, wenn man wirklich konsequent UTF-8 durchziehen würde. Bei meinem Linuxsystem kann ich einfach cout << "∑"; schreiben und es funktioniert wie erwartet, ohne dass ich mich um locales oder Zeichencodierungen kümmern müsste. Aber hier im Forum kann ich nicht einfach direkt ein ∑ in das Editorfenster setzen, weil irgendeine der vielen Zwischenstationen daraus dumme HTML-Codes macht.

    Ok, Danke. Bin wieder beruhigt. Wird aber OT. Vielleicht mache ich morgen (heute) mal einen neuen Thread auf. Bis denne...



  • SeppJ schrieb:

    Was Jester sagte. Du solltest Schleifen möglichst immer mit < statt <= formulieren. Und lass sie auch bei 0 los laufen, wenn der erste Index 0 ist, anstatt von 1 und dann immer minus 1 zu rechnen. Dann sieht man schneller, über welche und wie viele Werte die Schleifen laufen und Fehler wie dieser hier passieren nicht so leicht.

    Allgemein noch der Hinweis, dass dies nicht wirklich ist, wie man arithmetisches Mittel und Varianz berechnen würde. Das ist wohl nur als "Vereinfachung" für Programmieranfänger gemeint. Eine bessere Methode kommt ganz ohne Zwischenspeicher aus, macht alles in einem Durchlauf und ist zudem noch numerisch stabiler. Man muss bloß Mathematik anwenden. Komisch, dass ihr das im Mathematikstudium nicht benutzt. So geht's:
    [...]
    Nachzulesen geht das, wenn ich mich recht erinnere, in "The Art of Computer Programming".

    Das sieht für mich alles recht kryptisch aus haha 🙂 Ich programmiere vielleicht seit einem Monat und ich benutze eben das, was uns der Professor gezeigt hat 😃
    was bedeutet \t in deinem Code? Und was bedeutet using namespace std, was unser prof immer an den Anfang klatscht? Warum benutzt du vor den couts und cins std::?

    Ich bräuchte glaube ich mal einen guten online Kurs für C++, könnt ihr mir da eins empfehlen? Es gibt nämlich gefühlte 72.352 davon 😃

    Nochmal danke an alle, hätte nicht gedacht, dass so viele antworten werden 😃

    dirkski schrieb:

    Hallo, versuche mal (ungetestet):

    #include <locale>
    
    int main() {
      std::wcout.imbue(std::locale::global(std::locale("")));
    
      ...
    
      std::wcout << L"\u03C3 - Sigma\n";
    }
    

    So klappert das hier unter Linux zumindest (alles utf-8, Terminal, Editor etc...)

    Wenn dein Editor auf utf-8 gestellt ist kannst du auch öäü usw eingeben.
    Aber immer L"" statt "" benutzen. zumindest wenn Umlaute drin sind.

    Ach ja, besser dann nicht wcout und cout mischen...

    hth
    dirkski

    Edit: Ich weiß nicht ob nach C++-Standard überhaupt Nicht-Ascii-Zeichen
    im Quellcode erlaubt sind oder ob's nur geduldet wird...

    SeppJ schrieb:

    Ich glaube, er meint, wie er die Zeichen im Forum richtig anzeigen lassen kann 😉

    Ich meinte tatsächlich das Darstellen der Zeichen hier im Forum 🙂
    und was L"" bedeuten soll weiß ich auch nicht hahah 😃


  • Mod

    viklut schrieb:

    was bedeutet \t in deinem Code?

    Tabulatorzeichen.

    Und was bedeutet using namespace std, was unser prof immer an den Anfang klatscht? Warum benutzt du vor den couts und cins std::?

    Das ist vermutlich ein bisschen viel für einen Forenbeitrag. Ich verweise mal auf gute Anfängerbücher oder auf die Beiträge eines anderen Helfers, der sich vielleicht findet, dies ausführlich zu erklären.

    Ich bräuchte glaube ich mal einen guten online Kurs für C++, könnt ihr mir da eins empfehlen? Es gibt nämlich gefühlte 72.352 davon 😃

    Es ist leider kein gutes Onlinetutorial für C++ bekannt. Die besten sind von einer Qualität, dass man sagen kann, dass sie nicht nicht aktiv Schaden anrichten. Bei den meisten sieht es aber leider anders aus.


Anmelden zum Antworten