Programmausgabe in anderes Programm umleiten

Shorti

Shorti

Routinier
Hi @all,

so ich bin nun so gut wie fertig mit meiner Facharbeit. Nur meine Beispielprogramme möchte ich noch "verschönern".
Da mein Thema Erzeugung von Zufallszahlen ist, habe ich mir natürlich gedacht, ich implementiere die Algorithmen in c++ und anschließend mache ich, dann ein paar statistische Tests damit. Ebenfalls in c++ implementiert.

So weit so gut, nun hab ich alles in einem Programm. Da ich 2 verschiedene Algorithmen zur Erzeugung benutze, habe ich quasi zweimal das selbe Programm, nur der Algorithmus und die Parameter sind unterschiedlich.

Da aber Mathe-Lehrer, zumindest meine, keine Ahnung von "echter" Informatik haben, und mein Lehrer evtl. nicht den Aufwand sieht die Tests zu implementieren, dachte ich mir, dass ich die Tests einfach vom eigentlichen Programm splitte und eigenständige Programme daraus mache.

So weit so gut, aber wie leite ich nun die Zufallszahlenfolge aus dem einen Programm in ein anderes Programm um, welches dann anhand dieser Folge statistische Tests macht. Da ich Folgen von 10^9 Ziffern erzeugen lasse möchte ich mal eine tmp-Datei ausschließen.

Beide Programme sind in c++ geschrieben.

Vielen Dank im voraus

mfg
Shorti
 
Hi,

das Stichwort dass du suchst ist Interprozess Kommunikation (IPC). Das laesst sich auf sehr verschiedene Art und Weisen loesen.

Die gute alte Unixmanier waere wohl, nach stdout zu schreiben, von stdin zu lesen, und dann einfach Pipes zu verwenden. Da echtzeit Kommunikation wohl nicht notwendig zu sein scheint, erscheint mir die Loesung mit externen Dateien aber mit Abstand am leichtesten.

Wenn du zuviel Zeit hast, eine Herausforderung suchst und brauchbare Dinge lernen willst, kannst du es auch mit Sockets machen. ;)

mfg,
bytepool
 
Soll das ganze auch auf windows laufen?

Wenn nicht würd ich wirklich einfach pipen. Sonst bleibt dir eh nicht viel übrig, hauptsächlich unix sockets bzw du baust dein testprogramm als bibliothek und steckst die testroutine wirklich in jedes einzelne programm rein.
 
Code:
programm_mit_output | programm_das_den_output_als_input_nimmt

Siehe auch 'man bash' (oder was auch immer du für eine Shell verwendest). Pipes beherrschen so ziemlich alle.
 
Zuletzt bearbeitet:
Hi,
Soll das ganze auch auf windows laufen?
Wenn nicht würd ich wirklich einfach pipen.
Selbst Dos kannte "schon" primitive Pipes; 'dir | more' gehoerte zu den ersten Kommandos die ich an einem PC gelernt habe, damals noch mit MS Dos 5.x, glaub ich. ;)
Ich will ja gar nicht bestreiten dass Windows 95 ein Rueckschritt war, aber Pipes haben sie meines Wissens nach niemals abgeschafft. ;)

mfg,
bytepool
 
output.cpp:
Code:
#include <iostream>
int main() {
  std::cout << "1 2 3 4\n";
  return 0;
}

input.cpp:
Code:
#include <iostream>
int main() {
 int a[4];
 for (int i = 0; i < 4; ++i) {
   std::cin >> a[i];
 }
Dann kannst Du die Programme mit './output | ./input' verbinden.
Falls Deine erstes Programm keine fixe Anzahl an Ziffern erzeugt, kann es ja als erstes ausgeben, wieviele es sein werden, damit das zweite damit dynamisch den Speicher anlegt.
 
output.cpp:
Code:
#include <iostream>
int main() {
  std::cout << "1 2 3 4\n";
  return 0;
}

input.cpp:
Code:
#include <iostream>
int main() {
 int a[4];
 for (int i = 0; i < 4; ++i) {
   std::cin >> a[i];
 }
Dann kannst Du die Programme mit './output | ./input' verbinden.
Falls Deine erstes Programm keine fixe Anzahl an Ziffern erzeugt, kann es ja als erstes ausgeben, wieviele es sein werden, damit das zweite damit dynamisch den Speicher anlegt.

Dafür gibt es einen eleganteren Weg.

Und zwar kann man main auch 2 Parameter übergeben.

Einmal char* args und int size.
Somit kannst du folgendes umsetzen.


Code sollte klappen ist aber trocken programmiert und nicht getestet.
Code:
#include <iostream>

int main(int size, char* args[])
{
    for(int i = 0; i < size; i++)
    {
         std::cout << args[i] << std::endl;
    }

    return 0;
}

Somit weiß man direkt wie viele Argumente übergeben wurden und in dem char* stehen dann die Argumente als Strings.

somit werden auch Argumente an Programme wie rm übergeben und verarbeitet :)

T-Virus
 
Dafür gibt es einen eleganteren Weg.

Und zwar kann man main auch 2 Parameter übergeben.

Einmal char* args und int size.
Somit kannst du folgendes umsetzen.

Ich bezweifle aber, dass das elegant sein soll, das würde nämlich nicht so aussehen,
Code:
programm1 | programm2
sondern so
Code:
programm2 $(programm1)

Das würde alle zahlen auf einmal in den ram laden und dann erst programm2 anwerfen. Da da 10^9 zahlen ausgewertet werden sollen mit sagen wir 1byte pro char und einer stringlänge von sagen wir 6 zeichen wären das heiße 6Gbyte daten.
 
Verdammt, ich hatte die Datenmenge überlesen.
Nun dann kann es natürlich so nicht klappen.
 
Vielen Dank. Aber ich habe beschlossen es mit Dateien zu machen. Nun habe ich ein Problem am CODE, nämlich: er gibt mir meine Nachkommastellen nicht mit aus

Hier mein Code:
Code:
#include <fstream>
 #include <stdlib.h>
 #include <iostream>
 #include <iomanip>

//  #include <string.h>
 
using namespace std;
unsigned long long verteilung[10]={0,0,0,0,0,0,0,0,0,0};
int c;
int test;
unsigned long long summe = 0;
float haeufigkeit = 0;
char filename[256];

int pseudochartoint (char tmp) {
  int r;
if (tmp == '0')  r=0;if (tmp == '1')  r=1;if (tmp == '2')  r=2;
if (tmp == '3')  r=3;if (tmp == '4')  r=4;if (tmp == '5')  r=5;
if (tmp == '6')  r=6;if (tmp == '7')  r=7;if (tmp == '8')  r=8;
if (tmp == '9')  r=9;
return r;
}

 int main() {
  cout << "Waehlen Sie eine Datei:\n";
  cin >> filename;
  cout << "--------------------------\n";
  ifstream fin;
  char ch;
  fin.open(filename);
  while (fin.get(ch)) {
    if(ch != ' ') {
        test = pseudochartoint(ch);
	verteilung[test]++;
    }
  }
  fin.close();
  
  for(c=0;c<10;c++)
	{
	  summe += verteilung[c];
	}
  for(c=0;c<10;c++)
	{
	  haeufigkeit =verteilung[c]/summe;
	  cout <<c<<"\t"<<verteilung[c]<< "\t\t";
	  cout << setprecision(5) << haeufigkeit;
	  cout << "\n";
	}
	cout << "Insgesammt wurden " << summe << " Ziffern untersucht\n";
 }

Er soll in die Variable haeufigkeit die relative Häufigkeit berechnen. Aber er gibt mir nur Nullen aus. Etwa so:

Code:
...$ ./a.out
Waehlen Sie eine Datei:
3-2-2.dat
--------------------------
0       5               0
1       5               0
2       8               0
3       6               0
4       3               0
5       7               0
6       7               0
7       7               0
8       4               0
9       2               0
Insgesammt wurden 54 Ziffern untersucht
Kann mir vllt einer helfen? Wenn jemandem sonstige Verbesserungen einfallen, freu ich mich. Ich bin noch nicht so lange bei c++
 
Code:
#include <fstream>
 #include <stdlib>            //<= C++ verwendet keine header mit *.h
 #include <iostream>
 #include <iomanip>

//  #include <string>
 
using namespace std;
unsigned long long verteilung[10]={0,0,0,0,0,0,0,0,0,0};
int c;
int test;
unsigned long long summe = 0;
float haeufigkeit = 0;
char filename[256];

//wtf? wenn du schon so eine funktion selber machen willst und nicht eine fertige verwendest, wie atoi, dann solltest du wenigstens was schnelles verwenden
int pseudochartoint (char tmp) {
return tmp-'0';
/*
  int r;
if (tmp == '0')  r=0;if (tmp == '1')  r=1;if (tmp == '2')  r=2;
if (tmp == '3')  r=3;if (tmp == '4')  r=4;if (tmp == '5')  r=5;
if (tmp == '6')  r=6;if (tmp == '7')  r=7;if (tmp == '8')  r=8;
if (tmp == '9')  r=9;
return r;*/
}

 int main() {
  cout << "Waehlen Sie eine Datei:\n";
  cin >> filename;
  cout << "--------------------------\n";
  ifstream fin;
  char ch;
  fin.open(filename);
  while (fin.get(ch)) {
    if(ch != ' ') {
        test = pseudochartoint(ch);
	verteilung[test]++;
    }
  }
  fin.close();
  
  for(c=0;c<10;c++)
	{
	  summe += verteilung[c]*c;         //<= böses pfui
	}
  for(c=0;c<10;c++)
	{
	  haeufigkeit =verteilung[c];          //<=böseres pfui
	  cout <<c<<"\t"<<verteilung[c]<< "\t\t";
	  cout << setprecision(5) << haeufigkeit;
	  cout << "\n";
	}
	cout << "Insgesammt wurden " << summe << " Ziffern untersucht\n";
 }

Ich halt das Programm nicht für Sinnvoll, statistische auswertungen in einstelligen ints ist komplett sinnlos in meinen Augen. Abgesehen davon wirst du bei einer statistischen Auswertung von 10^9 Zahlen mit deinen aktuellen Programmierkünsten nur Rundungsfehler ausrechnen.

Wenn du wirklich statistische Auswertungen betreiben willst schau dir gsl an, die Gnu scientific library.

Aber ich halts für Zweckführender, wenn du die Werte einfach in ein csv ausgiebst und die Auswertung in Openoffice, ms excel, gnumeric oder Dergleichen machst.
 
Ich halt das Programm nicht für Sinnvoll, statistische auswertungen in einstelligen ints ist komplett sinnlos in meinen Augen. Abgesehen davon wirst du bei einer statistischen Auswertung von 10^9 Zahlen mit deinen aktuellen Programmierkünsten nur Rundungsfehler ausrechnen.

Naja ich will ja erstmal nur zählen, welche Zahl wie oft gekommen ist. Des is ja kein Problem.
Um die relative Häufigkeit auszurechnen muss ich ja nur absolute Häufigkeit/Anzahl der Ziehungen rechnen. Wenn ich das auf 4-5 Dezimalstellen genau berechne passte es meiner Meinung nach. Aber ich hätte gerne die Kommastellen auch ausgegeben.
Das 10^9 ist nur so ungefähr des Maximum, da ich verschieden oft Ziehe.
 
Generierst du eigentlich zufallszahlen in int von 0 bis 9 oder auch größere zahlen?

Und wenn du Nachkommastellen haben willst, dann rechne bitt in float/double und nicht in int/long.

Oder du nimmst:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argv, char** argc)
{
        FILE*   inputfile;
        int     count=0,        verteilung[10]={0,0,0,0,0,0,0,0,0,0}, i;

        /*checken, ob ein dateiname mitgegeben wurde*/
        if(argv<2)
        {
                fprintf(stderr, "Usage: %s filename\n", argc[0]);
                exit(EXIT_FAILURE);
        }
        /*oeffnen der datei*/
        if(NULL == (inputfile=fopen(argc[1], "r")))
        {
                fprintf(stderr, "failed to open %s\n", argc[1]);
                return EXIT_FAILURE;
        }
        /*zeichenweises auslesen der Datei*/
        while( EOF != (i=fgetc(inputfile)))
        {
                if(isdigit(i))
                {
                        i-='0';
                        verteilung[i]++;
                        count++;
                }
        }
        /*schauen ob was da ist*/
        if(0 == count)
        {
                fprintf(stderr, "no numbers found\n");
                return EXIT_FAILURE;
        }
        /*ausgabe*/
        printf("%s:\n-----------------\n", argc[0]);
        for(i=0;i<=9;i++)
        {
                printf("%i\t%i\t%6.2f%c\n",     i, verteilung[i], (double)verteilung[i]/(double)count*(double)100, '%');
        }
        printf("Insgesamt wurden %i Ziffern untersucht\n", count);
        return EXIT_SUCCESS;
}

In C, ist aber imho übersichtlicher.

Edit: wenn du aber pipen willst geht das ganze noch kürzer, und zwar so:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argv, char** argc)
{
        int     count=0,        verteilung[10]={0,0,0,0,0,0,0,0,0,0}, i;

        /*zeichenweises auslesen aus stdin*/
        while( EOF != (i=getc(stdin)))
        {
                if(isdigit(i))
                {
                        i-='0';
                        verteilung[i]++;
                        count++;
                }
        }
        /*schauen ob was da ist*/
        if(0 == count)
        {
                fprintf(stderr, "no numbers found\n");
                return EXIT_FAILURE;
        }
        /*ausgabe*/
        printf("%s:\n-----------------\n", argc[0]);
        for(i=0;i<=9;i++)
        {
                printf("%i\t%i\t%6.2f%c\n",     i, verteilung[i], (double)verteilung[i]/(double)count*(double)100, '%');
        }
        printf("Insgesamt wurden %i Ziffern untersucht\n", count);
        return EXIT_SUCCESS;
}
 
Zuletzt bearbeitet:
Versuch's mal mit
Code:
haeufigkeit =[B]1.0*[/B]verteilung[c]/summe;
Ohne den Faktor '1.0*' stehen auf der rechten Seite nur ganze Zahlen, so dass das Ergebnis als ganze Zahl berechnet wird (also dann abgerundet 0 ergibt). Erst dann wird durch das Gleicheitszeichen aus der ganzzahligen 0 eine 'float' gecastet, doch dann ist es bereits zu spaet, die Nachkommaziffern sind bereits verloren gegangen.
Durch den Vorfaktor '1.0' wird die Division bereits als float/ double durchgefuehrt.

@marcellus:
muesste es nicht "#include <cstdlib>" heissen?
 
Das ist C und nicht C++, ich kenn mich mit C++ wenig bis gar nicht aus.

Das wäre immer noch C++.
Die cstdlib ist nur die C++ Version der C stdlib.h
In C++ haben die Header der Standard Template Library und der Standard Header keine .h Endung mehr.


Der Inhalt der c* Dateien ist aber identisch mit den C Versionen.

T-Virus
 
Das wäre immer noch C++.
Die cstdlib ist nur die C++ Version der C stdlib.h
In C++ haben die Header der Standard Template Library und der Standard Header keine .h Endung mehr.


Der Inhalt der c* Dateien ist aber identisch mit den C Versionen.

T-Virus

Und das was ich geschrieben habe ist immernoch C, wieso sollte ich die "einge++ten" versionen der header verwenden, wenns C ist?
 
Das ist C und nicht C++, ich kenn mich mit C++ wenig bis gar nicht aus.

Auf meinem System (Debian Lenny) erzeugt ein '#include <stdlib>' eine Fehlermeldung, weil es keine Datei stdlib gibt, sondern nur eine Datei cstdlib und eine Datei stdlib.h. Fuer eine muss ich mich entscheiden. Das hat nichts damit zu tun, ob ich mit gcc oder g++ kompiliere. Das sollte bei Dir eigentlich auch so sein, denke ich.
 
Auf meinem System (Debian Lenny) erzeugt ein '#include <stdlib>' eine Fehlermeldung, weil es keine Datei stdlib gibt, sondern nur eine Datei cstdlib und eine Datei stdlib.h. Fuer eine muss ich mich entscheiden. Das hat nichts damit zu tun, ob ich mit gcc oder g++ kompiliere. Das sollte bei Dir eigentlich auch so sein, denke ich.

Oh ja da oben gabs das ja auch noch einmal, ich dachte du hast das auf das programm bezongen, dass ich vorher gepostet hab.
 
Zurück
Oben