Dev CPP
Dev CPP
1 Dev-C++
Version Dev-C++ 4.9.6.0
Die Oberfläche mit den GNU-Compilern g++ und gcc lässt ein bequemes Arbeiten mit der
Entwicklungsumgebung (Windows IDE) zu. Alle Einstellungen können von dort aus erfolgen.
Die Arbeit soll an einfachen Beispielen erläutert werden. Nach diesem Muster können andere
Programme gleichfalls erstellt und abgearbeitet werden.
1.1 Aufgabe 1
Demoprogramm a1c.cpp im Verzeichnis C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc
// a1c.cpp
// Rechnen mit komplexen Zahlen - Newton-Verfahren fuer Polynome
struct komplex
{ double re,im; };
// Addition: z = z1+z2
komplex add(komplex z1,komplex z2)
{ komplex z;
z.re = z1.re+z2.re;
z.im = z1.im+z2.im;
return z; }
// Subtraktion: z = z1-z2
komplex sub(komplex z1,komplex z2)
{ komplex z;
z.re = z1.re-z2.re;
z.im = z1.im-z2.im;
return z; }
// Betrag |z|
double kabs(komplex z)
{ return sqrt(z.re*z.re+z.im*z.im); }
// Multiplikation: z = z1*z2
komplex mult(komplex z1,komplex z2)
{ komplex z;
z.re = z1.re*z2.re-z1.im*z2.im;
z.im = z1.re*z2.im+z1.im*z2.re;
return z; }
// Division: z = z1/z2
komplex div(komplex z1,komplex z2)
{ komplex z,h; double nenner;
h.re = z2.re; h.im = -z2.im;
nenner = z2.re*z2.re+z2.im*z2.im;
z.re = (z1.re*h.re-z1.im*h.im)/nenner;
1
z.im = (z1.re*h.im+z1.im*h.re)/nenner;
return z; }
int main()
{ komplex c1,c2,h,p,ps;
komplex a[11];
char vz;
int n,i;
for(i=0;i<=n;i++)
{ cout<<"\na["<<i<<"].re: ";
cin>>a[i].re;
cout<<"a["<<i<<"].im: ";
cin>>a[i].im;
}
cout<<"\nStartwert Newton: x[0].re= ";
cin>>c1.re;
cout<<"Startwert Newton: x[0].im= ";
cin>>c1.im;
vz = (c1.im<0?’-’:’+’);
cout.precision(16);
cout<<"\nNullstelle c1: "<<c1.re<<vz<<fabs(c1.im)<<"*I\n";
getch();
return 0;
}
2
Fuehrt g++.exe... aus
g++.exe "C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c.cpp"
-o "C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c.exe"
-s -I"C:\Dev-Cpp\include"
-I"C:\Dev-Cpp\include\g++-3"
-I"C:\Dev-Cpp\include"
-L"C:\Dev-Cpp\lib"
Ausfuehrung beendet
Kompilierung erfolgreich
3. Menüpunkt Ausführen
⇒ Ausführen
Es öffnet sich das Eingabe- und Ergebnisfenster
2 C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc\a1c.exe
Rechnen mit komplexen Zahlen - Newton-Verfahren
pn(x)=a[n]xˆn+a[n-1]xˆ(n-1)+...+a[1]x+a[0] = 0
Polynomgrad n (n<=10): 2
Eingabe Polynomkoeffizienten:
...
4. Menüpunkt Ausführen
⇒ Kompilieren u. Ausführen
Dasselbe Programm stellen wir als a1c .c bereit und übersetzen es. Dazu wird er Compiler
gcc.exe aufgerufen. Als erstes kommt eine Meldung zur Header-Datei iostream.h, die in
C nicht vorgesehen ist, weil es die Objekte cin, cout,... nicht gibt.
4 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c iostream.h: No such file or directory.
Wir kommentieren die entsprechende Zeile heraus und machen den nächsten Versuch, jedoch
bei zahlreichen weiteren Fehlermeldungen.
14 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘add’
14 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z1’
C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c [Warning] In function ‘add’:
15 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘komplex’ undeclared (first use in this function)
[Build Error] (Each undeclared identifier is reported
[Build Error] only once for each function it appears in.)
15 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z’
16 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z’ undeclared (first use in this function)
16 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z1’ undeclared (first use in this function)
16 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z2’ undeclared (first use in this function)
[Build Error] At top level:
21 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘sub’
21 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z1’
C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c [Warning] In function ‘sub’:
22 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘komplex’ undeclared (first use in this function)
22 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z’
23 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z’ undeclared (first use in this function)
23 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z1’ undeclared (first use in this function)
23 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z2’ undeclared (first use in this function)
[Build Error] At top level:
28 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z’
C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c [Warning] In function ‘kabs’:
29 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z’ undeclared (first use in this function)
[Build Error] At top level:
32 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘mult’
32 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z1’
C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c [Warning] In function ‘mult’:
3
33 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘komplex’ undeclared (first use in this function)
33 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z’
34 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z’ undeclared (first use in this function)
34 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z1’ undeclared (first use in this function)
34 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z2’ undeclared (first use in this function)
[Build Error] At top level:
39 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘div’
39 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z1’
40 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c conflicting types for ‘div’
350 C:\Dev-Cpp\include\stdlib.h previous declaration of ‘div’
C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c [Warning] In function ‘div’:
40 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘komplex’ undeclared (first use in this function)
40 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘z’
41 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘h’ undeclared (first use in this function)
41 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z2’ undeclared (first use in this function)
43 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z’ undeclared (first use in this function)
43 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘z1’ undeclared (first use in this function)
C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c [Warning] In function ‘main’:
48 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘komplex’ undeclared (first use in this function)
48 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c parse error before ‘c1’
53 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘cout’ undeclared (first use in this function)
55 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘cin’ undeclared (first use in this function)
60 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘a’ undeclared (first use in this function)
66 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘c1’ undeclared (first use in this function)
73 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘c2’ undeclared (first use in this function)
74 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘p’ undeclared (first use in this function)
74 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘ps’ undeclared (first use in this function)
76 C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\a1c_.c ‘h’ undeclared (first use in this function)
Man erkennt, dass eine Reihe von Veränderungen bzw. Korrekturen notwendig ist, um ein
lauffähiges C-Programm zu erhalten.
(1) In C++ reicht als Typangabe für eine Strukturvariable der Typbezeichner (hier komplex),
in C ist der Typ durch struct komplex zu notieren. Dadurch kommen die meisten Fehler-
meldungen.
(2) Die Ein-/Ausgabeanweisungen cin, cout sind nicht deklariert und in C durch die Kom-
mandos scanf, printf zu ersetzen. scanf erwartet als Argumente Adressen, so dass man
den Adressoperator & direkt vor den Variablennamen stellt.
(3) div ist in der Bibliothek stdlib.h als Standardfunktion vordefiniert und steht im Kon-
flikt mit der gleichnamigen Nutzerfunktion. Diese sollte man anders bezeichnen (hier divi).
(4) Die meisten Header-Dateien werden im Übersetzungsprozess durch Verlinken mit den
Bibliotheken Dev-Cpp\include und Dev-Cpp\lib schon eingebunden. Damit ist auch die
Funktion getch() verfügbar.
Nach den Korrekturen erhält man das C-Programm a1c.c.
// a1c.c
// Rechnen mit komplexen Zahlen - Newton-Verfahren fuer Polynome
//#include <stdio.h>
//#include <stdlib.h>
#include <math.h> // muss bleiben
//#include <conio.h>
struct komplex
{ double re,im; };
// Addition: z = z1+z2
struct komplex add(struct komplex z1,struct komplex z2)
{ struct komplex z;
z.re = z1.re+z2.re;
z.im = z1.im+z2.im;
return z; }
// Subtraktion: z = z1-z2
struct komplex sub(struct komplex z1,struct komplex z2)
{ struct komplex z;
z.re = z1.re-z2.re;
z.im = z1.im-z2.im;
return z; }
4
// Betrag |z|
double kabs(struct komplex z)
{ return sqrt(z.re*z.re+z.im*z.im); }
// Multiplikation: z = z1*z2
struct komplex mult(struct komplex z1,struct komplex z2)
{ struct komplex z;
z.re = z1.re*z2.re - z1.im*z2.im;
z.im = z1.re*z2.im + z1.im*z2.re;
return z; }
// Division: z = z1/z2
struct komplex divi(struct komplex z1,struct komplex z2)
{ struct komplex z,h;
double nenner;
h.re=z2.re; h.im=-z2.im;
nenner=z2.re*z2.re+z2.im*z2.im;
z.re = (z1.re*h.re - z1.im*h.im)/nenner;
z.im = (z1.re*h.im + z1.im*h.re)/nenner;
return z; }
int main()
{ struct komplex c1,c2,h,p,ps;
struct komplex a[11];
char vz;
int n,i;
for (i=0;i<=n;i++)
{ printf("\na[%i].re: ",i);
scanf("%lf",&a[i].re);
printf("a[%i].im: ",i);
scanf("%lf",&a[i].im);
}
printf("\nNewton-Verfahren");
printf("\nStartwert: x[0].re= ");
scanf("%lf",&c1.re);
printf(" x[0].im= ");
scanf("%lf",&c1.im);
// Newton-Verfahren, Nullstellenberechnung fuer komplexe Polynome unter Nutzung des zweizeiligen Hornerschema
do
{ c2 = c1;
p = a[n]; ps = p;
for(i=n-1;i>0;i--)
{ h = mult(p,c2); p = add(h,a[i]); // p =p*x0+a[i];
h = mult(ps,c2); ps = add(h,p); // ps=ps*x0+p;
}
h = mult(p,c2); p = add(h,a[0]); // p=p*x0+a[0];
c1 = sub(c2,divi(p,ps));
}
while(kabs(sub(c1,c2))>1e-10);
vz = (c1.im<0?’-’:’+’);
printf("\nNullstelle: %17.15lf%c%17.15lf*I\n",c1.re,vz,fabs(c1.im));
getch();
return 0;
}
5
1.2 Aufgabe 2
Demoprogramm a4c.cpp im Verzeichnis C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc
// a4c.cpp
// Numerische Integration - zusammengesetzte Trapezregel
// Integranden
double f1(double x)
{ return sin(x*x);}
double f2(double x)
{ return sin(x)/x; }
double f3(double x)
{ return sqrt(8.0*x)-x*x/8; }
double f4(double x)
{ return x-x*x*x; }
double f5(double x)
{ return 2.0*exp(-x*x)/sqrt(3.141592653589793); }
// Zusammengesetzte Trapezregel
double Trapez(double f(double),double a,double b,int n)
{
int k;
double I,x,h;
x = a;
h = (b-a)/n;
I = 0.5*(f(a)+f(b));
for(k=1;k<n;k++)
{
x = x+h;
I = I+f(x);
}
return h*I;
}
int main()
{
double a,b;
int n;
a = 0; b = 1;
n = 10;
cout<<"Integralberechnungen mit zusammengesetzter Trapezregel\n";
cout<<"\nIntegrand f5(x)=2 exp(-x*x)/sqrt(Pi)\n";
cout<<"n="<<n<<"\n";
cout.precision(16);
for(b=1;b<4.1;b=b+1.0)
{
cout<<"Integralwert Tn(f5,0,"<<b<<") = "<<Trapez(f5,a,b,n)<<"\n";
}
n = 20;
cout<<"\nn="<<n<<"\n";
for(b=1;b<4.1;b=b+1)
{
cout<<"Integralwert Tn(f5,0,"<<b<<") = "<<Trapez(f5,a,b,n)<<"\n";
}
cout<<"\nExakter Wert = Int(f5,0,unendlich) = 1\n";
getch();
return 0;
}
Alle Parameter für die Integrationsformel sind im Programm definiert, so dass keine Eingabe
vorgesehen ist.
Nach Übersetzen und Ausführen von a4c.exe öffnet sich das Ergebnisfenster
6
2 C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc\a4c.exe
Integralberechnungen mit zusammengesetzter Trapezregel Tn(f,a,b)
n=20
Integralwert Tn(f5,0,1) = 0.842527817
Integralwert Tn(f5,0,2) = 0.995253490
Integralwert Tn(f5,0,3) = 0.999976360
Integralwert Tn(f5,0,4) = 0.999999981
Wiederrum sind einige Veränderungen bzw. Korrekturen notwendig, um ein analoges lauffähi-
ges C-Programm zu erhalten.
// a4c.c
// Numerische Integration - zusammengesetzte Trapezregel
//#include <stdio.h>
//#include <stdlib.h>
#include <math.h>
//#include <conio.h>
// Integranden
double f1(double x)
{ return sin(x*x);}
...
double f5(double x)
{ return 2.0*exp(-x*x)/sqrt(3.141592653589793); }
// Zusammengesetzte Trapezregel
double Trapez(double f(double),double a,double b,int n)
{ int k;
double I,x,h;
...
}
int main()
{ double a,b;
int n;
a = 0; b = 1;
n=10;
printf("Integralberechnungen mit zusammengesetzter Trapezregel Tn(f,a,b)\n");
printf("\nIntegrand f5(x)=2 exp(-x*x)/sqrt(Pi)\n");
printf("n=%d\n",n);
for(b=1;b<4.1;b=b+1.0)
{
printf("Integralwert Tn(f5,0,%1.0lf)=%11.9lf\n",b,Trapez(f5,a,b,n));
}
n = 20;
printf("\nn=%d\n",n);
for(b=1;b<4.1;b=b+1)
{
printf("Integralwert Tn(f5,0,%1.0lf)=%11.9lf\n",b,Trapez(f5,a,b,n));
}
printf("\nExakter Wert = Int(f5,0,unendlich) = 1\n");
getch();
return 0;
}
7
1.3 Aufgabe 3
Demoprogramm a5c.cpp im Verzeichnis C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc
// a5c.cpp
// Koerpergewicht
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h> /* deklariert Objekte wie getch, printf, scanf */
do /* Schleifenanfang */
{
// clrscr(); /* Diese Funktion loescht den Bildschirm! */
// /* Headerdatei: <conio.h> */
/* Achtung: clrscr() funktioniert nicht mit Visual C++, Dev-C++,... */
printf("\n\n\t Bitte geben Sie Ihre Koerpergroesse (in cm) ein: ");
scanf("%d%c", &groesse, &ret);
printf("\n\t Bitte geben Sie Ihr Gewicht (in kg) ein: ");
scanf("%f%c", &gewicht, &ret);
printf("\n\t Bitte geben Sie Ihr Geschlecht an:");
printf("\n\t m = Mann");
printf("\n\t f = Frau\n\t "); // !=m ist Frau
auswahl = getch();
printf("%c\n", auswahl);
ideal = groesse-100;
if(geschlecht==’m’)
ideal = ideal/100*90;
else
ideal = ideal/100*85;
Alles scheint in Ordnung zu sein, aber bei dem Versuch das Programm zu kompilieren weigert
sich g++ den Quelltext zu übersetzen.
[Warning] In function ‘int main()’:
implicit declaration of function ‘int errechne_ideal(...)’
8
Das liegt daran, dass die Funktion errechne_ideal() erst nach der Hauptfunktion definiert
wurde. So mancher C-Compiler lässt sich überlisten, indem man die Funktion einfach vor
der Hauptfunktion definiert. Die korrekte Lösung besteht jedoch in der Verwendung eines
Prototypes, an dem der Compiler erkennen kann das irgendwo weiter unten im Quelltext
noch eine entsprechende Funktion definiert ist.
// Deklaration des Prototyps
float errechne_ideal(int groesse, char geschlecht);
Diesen fügt man als Zeile zwischen die #include-Anweisungen und die main-Funktion ein.
Dies ist der übliche Ort an dem Prototypen platziert werden sollten.
Da die Eingabe von Daten mit der <Enter>-Taste beendet wird, haben wir das <Enter>-
Zeichen extra einer Variablen zugeordnet.
scanf("%d%c", &groesse, &ret);
Damit sichert man, dass der Tastaturpuffer geleert wird. Man kann dies auch mit dem
Aufruf der Methoden flush() bzw. fflush(stdin) mit dem Standardbezeichner stdin aus
den Header-Files stdio.h oder conio.h tun. Oft passiert dies jedoch automatisch mit den
Abschluss der Eingabe einfach durch die <Enter>-Taste und nach der Anweisung cout<<.
Es sind keine Veränderungen bzw. Korrekturen notwendig, um daraus ein lauffähiges C-
Programm zu erhalten. Man bezeichnet einfach die Datei um in a5c.c.
1.4 Aufgabe 4
Demoprogramm matsum.cpp im Verzeichnis
C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc
// matsum.cpp
// Summe c = a+b zweier Matrizen der Dimension (m,n)
void summe(int m,int n,long double x[][3],long double y[][3],long double z[][3]); // long double = extended
int main()
{
long double a[2][3] = {0.987654321e-12,-2,1,3,4,7};
long double b[2][3] = {2.0e-5,4,8,-5,-5,-5};
summe(2,3,a,b,c);
cout.precision(16); // double !
cout << "c[0][0] = " << c[0][0] << endl;
cout << "c[0][1] = " << c[0][1] << endl;
cout << "c[0][2] = " << c[0][2] << endl;
cout << "c[1][0] = " << c[1][0] << endl;
cout << "c[1][1] = " << c[1][1] << endl;
cout << "c[1][2] = " << c[1][2] << endl;
getch();
return 0;
}
9
void summe(int m, // Zeilenzahl
int n, // Spaltenzahl
long double x[][3], // erste Matrix
long double y[][3], // zweite Matrix
long double z[][3]) // Summenmatrix
{
for(int i=0;i<m;++i)
for(int k=0;k<n;++k)
z[i][k] = x[i][k]+y[i][k];
}
Ausgewählte Ergebnisse
cout.precision(16);
long double a[2][3] = {0.987654321e-12,-2,1,3,4,7};
//#include <stdio.h>
//#include <stdlib.h>
#include <math.h>
//#include <conio.h>
10
void summe(int m,int n, double x[][3], double y[][3],
double z[][3]); // nicht in C: long double = extended
int main()
{
double a[2][3] = {0.987654321e-12,-2,1,3,4,7};
double b[2][3] = {2.0e-5,4,8,-5,-5,-5};
summe(2,3,a,b,c);
printf("c[0][0] = %17.15e\n",c[0][0]);
printf("c[0][1] = %.0lf\n",c[0][1]);
printf("c[0][2] = %.0lf\n",c[0][2]);
printf("c[1][0] = %.0lf\n",c[1][0]);
printf("c[1][1] = %.0lf\n",c[1][1]);
printf("c[1][2] = %.0lf\n",c[1][2]);
getch();
return 0;
}
Ergebnisse
11
1.5 Aufgabe 5
Demoprogramm tnewton1.c im Verzeichnis C:\d\Neundorf\nwptexte\tech phy\05\dev cpp
Die Definitionen und Prototypen, also die Prozedurköpfe usw., findet man in den Header-
Files basis.h, u_proto.h, tfunc1.h als Vorabdeklarationen und werden damit bekannt
gemacht.
Ihre eigentliche Definition erfolgt in den Funktionen fnewtonc.c, tfunc1.c, basis.c,
die nach der Hauptfunktion main stehen.
// tnewton1.c
/*-------------------------------------------------------------------*/
/* Test program for newton */
/*-------------------------------------------------------------------*/
printf("%s\n", text);
printf("Start value x0 = ");
printf(FORMAT_LF, x);
printf("\n");
rc = newton(fct,fctd,&x,&f,&iter);
12
printf("Return code = % d\n", rc);
printf("Root = "); printf (FORMAT_2016LF, x);
printf("\nFunction value = "); printf (FORMAT_LE, f);
printf("\nIterations = % d\n\n", iter);
}
WriteEnd();
getch();
return (0);
}
// fnewton.c
/* Loesung nichtlinearer Gleichungen
Numerische Verfahren zur Loesung nichtlinearer Gleichungen
Newton-Verfahren fueur einfache und mehrfache Nullstellen */
#include "basis.h"
#include "u_proto.h"
#define ITERMAX 300 /* Maximale Iterationszahl */
#define ABSERR ZERO /* Zugelassener Absolutfehler */
#define RELERR (REAL)((REAL)128.0 * MACH_EPS) /* Zugelassener Relativfehler */
#define FCTERR (REAL)((REAL)4.0 * MACH_EPS) /* Max. Fehler im Funktionwert*/
// tfunc1.c
/* Definition of test functions for newton, pegasus and roots */
#include "basis.h"
#include "u_proto.h"
#include "tfunc1.h"
// basis.c
/* grundlegende Funktionen: Definitionsdatei */
Die Programme sind aus der Bibliothek FORMELN\CNUM8 (Formelsammlung zur Nu-
merischen Mathematik in ANSI C und C++, Aachener Bibliothek) entnommen und zusam-
mengestellt.
Das Programm tnewton1.c wir mit dem Compiler gcc übersetzt (→ tnewton1.exe) und
man führt es aus.
13
Das Ergebnisfenster ist
f = 5∗x-exp(x)
Start value x0 = 1.000000
Return code = 0
Root = 0.2591711018190737
Function value = -1.758576e-016
Iterations =5
f = (((((x-6)∗x+15)∗x-20)∗x+15)∗x-6)∗x+1
Start value x0 = 2.000000
Return code = 2
Root = 1.0059508814409825
Function value = 4.451994e-014
Iterations = 300
f = sin(x)
Start value x0 = 1.000000
Return code = 0
Root = 0.0000000000000000
Function value = 0.000000e+000
Iterations =5
f = 1+sin(x)
Start value x0 = 1.000000
Return code = 0
Root = -1.5707963497819439
Function value = 2.642201e-016
Iterations = 26
f = exp(x)-(1.0+x+x∗x∗0.5)
Start value x0 = 2.000000
Return code = 0
Root = 0.0000148767867855
Function value = 4.037569e-016
Iterations = 162
f = (x-1.0)∗(x-1.0)∗(sin(PI∗x)-log(fabs(2.0∗x/(x+1.0)))
Start value x0 = 2.000000
Return code = 0
Root = 2.0981196117437797
Function value = -2.541919e-016
Iterations =5
——————————————————————————–
14
2 Aufbau der Numerik-Bibliothek
In Abschnitt 1, Aufgabe 5, ist eine Programmbibliothek verwendet worden.
Die Aachener Bibliothek ist hierarchisch aufgebaut, wohl strukturiert und nach Teildiszipli-
nen der Numerischen Mathematik angelegt.
1. Die Programme befinden sich auf dem Novell-Netz RUNGE (Volume share) des IfMath
Q:\Neundorf\stud m93\FORMELN\ANSICNUM, ...\CNUM8
Die neuere Version CNUM8 om 26.04.1996 enthält mehr und verbesserte numerische
Algorithmen.
Lokal ist das Bibliotheksverzeichnis z. B. unter
c:\d\Neundorf\FORMELN\ANSICNUM, ...\CNUM8
2. Literaturhinweis
- Engeln-Müllges, G., Reutter, F.: Numerik-Algorithmen mit ANSI-C-Programmen.
Wissenschaftsverlag Mannheim 1993. Standort: 50/51=MAT 93 A 7745.
- Engeln-Müllges, G., Reutter, F.: Formelsammlung zur Numerischen Mathematik
mit FORTRAN 77-Programmen. Bibliogr. Institut Mannheim 1988 (auch für TP, C).
3. Informationen zum Aufbau der Bibliothek, ihrer Verzeichnisstruktur und zu ihrer Be-
nutzung (z. B. Anwendung und Einstellungen für unterschiedliche Compiler, Benut-
zungsarten) findet man in der Datei LIESMICH.TXT im jeweiligen Verzeichnis.
4. Analog gibt es Verzeichnisse von Versionen der Numerik-Tools für andere Program-
miersprachen, z. B. für Turbo Pascal im Verzeichnis \TPNUM mit ähnlicher Struktur.
5. Inhalte der einzelnen Unterverzeichnisse
Verzeichnis Inhalt
15
3 Projekte in Borland-C
3.1 Borland-C++3.1 (DOS)
Der Borland-C-Compiler lässt ein bequemes Arbeiten mit der Entwicklungsumgebung (DOS
IDE) zu. Alle Einstellungen können von dort aus erfolgen.
(a) Man lege im Verzeichnis \CNUM8 ein Arbeitsverzeichnis für EXE- und OBJ-
Dateien an, im weiteren mit \EXE bezeichnet.
(b) Man starte den Borland-Compiler, und wechsle in das Verzeichnis \CNUM8\02\TST.
(c) Man lade das Demoprogramm TNEWTON.C. Die dortigen Include-Anweisungen
für die Header-Dateien enthalten schon wichtige Hinweise dafür, welche Files zum
Projekt gehören.
#include <basis.h> /*Grundlegender Deklarationsteil*/
#include <u_proto.h> /*Vordeklaration aller Bibliotheksfunktionen*/
#include <tfunc1.h> /*Testfunktionen*/
16
(h) Bei erfolgreicher Übersetzung ist eine Kontrolle der in TNEWTON.C einbezo-
genen Header-Dateien möglich mittels Project, Include files.
(i) Start des übersetzten Projekts gleich in der Entwicklungsumgebung mittels Run,
Run.
Die letzten Ergebnisse sind mittels Window, Output zu besichtigen. Bei der
Rechnung zahlreicher Beispiele und Ausgabe vieler Daten über mehrere Bildschir-
me sind im Quelltext sogenannte Haltepunkte einzufügen. Das können solche An-
weisungen sein wie getch(), dazu noch ev. das Löschen des BS mittels clrscr().
Dabei ist möglicherweise im Demoprogramm noch die Include-Anweisung für die
Header-Datei conio.h einzutragen, also
#include <conio.h> /*Direkte MSDOS Console I/O*/
(j) Es empfiehlt sich, vor Verlassen der Entwicklungsumgebung das Projekt zu spei-
chern. Mittels Options, Save, Project wird die Projektdatei TNEWTON.PRJ
in das Verzeichnis \CNUM8\02\TST gespeichert. Auch die gesetzten Directories
werden gespeichert. Damit ist eine erneute Behandlung dieses Projekts schnell
möglich.
(k) Natürlich kann man die Datei TNEWTON.EXE aus der DOS- oder Windows-
Oberfläche starten.
2. Beispiel: Lösung einer Anfangswertaufgabe für Systeme
von gewöhnlichen Differentialgleichungen mittels Runge-Kutta-
und anderer Verfahren mit Schrittweitensteuerung
Aufgabe: das Demoprogramm M AWP.C im Verzeichnis \CNUM8\17\TST ist zu
übersetzen und auszuführen. Dazu sind ähnlich wie im obigen Beispiel die folgenden
Schritte auszuführen. Wir beschränken uns auf die Angabe einiger Unterschiede.
(a) Das Demoprogramm ist M AWP.C.
(b) Öffnen eines Projektfiles M AWP.PRJ mittels Project, Open project.
(c) Man füge mit Project, Add item die folgenden benötigten Files in das Projekt
ein.
\CNUM8\17\TST\M AWP.C
\CNUM8\17\AWP.C
\CNUM8\17\TST\T DGLS.C
\CNUM8\BASIS\VMBLOCK.C
\CNUM8\BASIS\BASIS.C
(d) Es gibt noch ein Verzeichnis \CNUM8\17\EIN mit Eingabedateien der Parameter
der verschiedenen Beispiele.
(e) Normalerweise erfolgt eine Eingabe im Dialog. Gemäß der im Quelltext T DGLS.C
vorliegenden Beispiele sind die Beispielnummer und danach die Verfahrenspara-
meter nrbeisp , εa , εr , nrmeth , x0 , y1 (x0 ), y2 (x0 ), h, xend , fmax einzugeben.
Die Eingabeaufforderung kann wahlweise angezeigt oder unterdrückt werden. Um
diese anzuzeigen, ist im Demoprogramm die Anweisung
#define INTERAKTIV
noch zu ergänzen.
Haltepunkte wie getch() sind bei der Ausgabe großer Datenmengen als auch
nach Fehlermeldungen sinvoll.
17
Übersetzen mit dem Borland-C-Compiler C++3.1 (Windows)
Unter Windows sollte man ein eigenständiges Projekt erstellen.
Ein Zusammenspiel“ mit DOS ist nicht ganz problemlos.
”
Dazu die Bemerkungen:
1. Es können Projekte, die unter DOS IDE erstellt wurden, auch in die Windows IDE laden.
Dann erscheint ein Dialogfenster mit der Frage, ob die Optionen des DOS IDE umzukonfi-
gurieren sind.
2. EXE-Dateien von Projekten unter Windows IDE nur unter Windows aufrufen.
3. Verwendet man ein Projekt aus Windows IDE in der Entwicklungsumgebung DOS, ist
aufgrund von Voreinstellungen durch Windows die Übersetzung Compiler, Build all
möglich, nicht aber die Ausführung Run, Run.
18
Vorgehensweise:
- Im Projektfenster mittels rechter Maustaste auf proj0001[.exe] klicken.
- TargetExpert auswählen.
- Im TargetExpert-Fenster die Standardbibliothek BGI ergänzen.
(b) Optionen, Projekt
Im Fenster Projektoptionen sind Verzeichnisse zu aktualisieren.
- Quelltextverzeichnisse
Include : ;..\CNUM8\INC
Bibliothek : keine Änderung oder ev. ;..\CNUM8\LIB
Quelltext : ..\CNUM8\17\TST
- Ausgabeverzeichnisse
OBJ-Dateien : ..\CNUM8\EXE
EXE-Datei : ..\CNUM8\EXE
(c) Optionen, Speichern
Im Fenster Optionen speichern der Konfiguration des Projekts.
(d) Projekt, Projekt neu compilieren
Hier erfolgt die Übersetzung des Gesamtprojekts.
Im Fenster Compilerstatus wird der Ablauf dieses Prozesses angezeigt.
Im Fenster Meldung erscheinen Informationen zur Übersetzung sowie zu ev.
Warnungen und Fehlern.
(e) Debug, Ausführen (oder Strg F9 bzw. Blitz“-Ikone)
”
Starten des Projekts. Der Eingabedialog sowie die Ergebnisdarstellung erfolgen
in einem Windows-Fenster. Vor einem wiederholten Start des Projekts ist dieses
i. Allg. neu zu öffnen (außer bei Fehlermeldugen).
(f) Nach Beendigung der Arbeit am Projekt können einige Dateien gelöscht werden,
so z. B. im Verzeichnis \CNUM8\17\TST die Dateien
- proj0001.dsw (Turbo C Context File)
- proj0001.csm (Konfigurationsfile)
- proj0001.˜de (Bak-Datei von proj0001.ide)
- proj0001.obr (Browser State File)
Achtung!
Auch ein Programm, das nur Standard-Header-Dateien enthält, sollte als Projekt de-
finiert werden (nicht Bedingung), um damit den Zugriff und die Einbindung dieser in
jedem Fall zu sichern.
Beispiel:
C++ Programm matbau6a.cpp enthält die Header-Files über die Include-
Anweisungen
#include <stdio.h>
#include <iostream.h>
#include <malloc.h>
#include <stdlib.h>
#include <math.h>
Das Projekt hat die kurze Darstellung
· - proj0002[.exe]
|
· − 2 matbau6a[.cpp]
19
2. Arbeit mit vorhandenem Projekt.
Als Beispiel diene das Programm M AWP.C im Verzeichnis ..\CNUM8\17\TST.
Da aber immer nur eines dieser Programme aktiv sein kann und ausgeführt werden
kann, müssen die anderen mittels
- Anglicken der rechten Maustaste,
- Lokale Optionen bearbeiten ... (Edit local options)
Optionen, Attribute
- Vom Elternknoten ausschließen (Build Attributes, Exclude from parents)
vom Elternknoten (hier matbau6a.cpp) ausgeschlossen werden. Anstelle der Markie-
rung “·“ erhalten die ausgegrenzten Knoten die neue Markierung “ “.
Die Darstellung im Projektfenster ist dann
· - proj0003[.exe]
· |− 2 matbau6a[.cpp]
|− 2 matbau6b[.cpp]
|− 2 matbau6c[.cpp]
|− 2 matbau6d[.cpp]
|− 2 matbau6e[.cpp]
20
4 Projekte in Dev-C++
Wir demonstrieren die Erstellung von Projekten und den Umgang damit anhand von einigen
Beispielen. Dabei wollen wir schrittweise vorgehen unter Verwendung der Informationen aus
den vorherigen Abschnitten.
4.1 Aufgabe 1
In den Demoprogrammen wird der Gauß-Algorithmus zur Lösung des LGS Ax = b in ver-
schiedenen Versionen implementiert. Die Programme befinden sich im Verzeichnis
C:\d\Neundorf\nwptexte\tech phy\05\dev cpp\projekt1.
Variante 1
Demoprogramme gauss1.c und gauss1.cpp (außer den Dateinamen keine Unterschiede)
/* gauss1.c bzw. gauss1.cpp */
/* Resttableau-Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
/* Tausch mit ersten NNE in der Spalte */
/* Ax=b, A=>oberes U, unteres Dreieck gleich Null */
/* Ux=c Loesung mit Rueckwaertseinsetzen */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define Nmax 10
// Vowaertsdeklarationen, Prototypen
int Gauss();
void Einlesen();
void Rausschreiben();
int SucheNichtNull(int);
void NulleSpalte(int);
void BerechneX();
void Vertausche(int, int);
void Zeile_abziehen(int, int);
int N;
double A[Nmax][Nmax],b[Nmax],x[Nmax]; // statische Felder
int main()
{ int flag;
Einlesen();
flag = Gauss();
if(flag!=0)
{
printf("Gleichungssystem nicht loesbar!\n");
getch();
return(-1);
}
Rausschreiben();
return(0);
}
/*---------------------------------------------------------------------------*/
int Gauss()
{ int i,j,flag;
for(i=0;i<N;i++)
{
flag = SucheNichtNull(i);
if(flag!=0) return(-1);
NulleSpalte(i);
}
BerechneX();
return(0);
}
21
void Einlesen() // Dateiarbeit
{ FILE *datin;
int i,j;
datin = fopen("gauss1-input.dat","r");
fscanf(datin,"%i",&N);
for(i=0;i<N;i++)
for(j=0;j<N;j++) fscanf(datin,"%lf",&A[i][j]);
for(i=0;i<N;i++) fscanf(datin,"%lf",&b[i]);
fclose(datin);
}
/*---------------------------------------------------------------------------*/
void Rausschreiben() // Dateiarbeit
{ FILE *datout;
int i,j;
datout = fopen("gauss1-output.dat","w");
for(i=0;i<N;i++) fprintf(datout,"%lf\n",x[i]);
fclose(datout);
}
/*---------------------------------------------------------------------------*/
int SucheNichtNull(int i)
{ int k;
for(k=i;k<N;k++)
if(A[k][i]!=0.0)
{
Vertausche(i,k);
return(0);
}
return(-1); // kein NNE in der i-ten Spalte, A singulaer
}
/*---------------------------------------------------------------------------*/
void NulleSpalte(int i)
{ int k;
for(k=N-1;k>=0;k--)
{
x[k] = b[k];
for(l=k+1;l<N;l++) x[k] = x[k]-A[k][l]*x[l];
x[k] = x[k]/A[k][k];
}
}
/*---------------------------------------------------------------------------*/
void Vertausche(int i, int j)
{ double temp;
int k;
for(k=i;k<N;k++)
{
temp = A[i][k];
A[i][k] = A[j][k];
A[j][k] = temp;
}
temp = b[i];
b[i] = b[j];
b[j] = temp;
}
/*---------------------------------------------------------------------------*/
void Zeile_abziehen(int i, int j)
{ double quotient;
int k;
quotient = A[j][i]/A[i][i];
for(k=i;k<N;k++) // Resttableau modifizieren
A[j][k] = A[j][k]-quotient*A[i][k]; // dabei i-te Spalte zu Null machen
b[j] = b[j]-quotient*b[i];
}
22
Eingabedatei: gauss1-input.dat
2
0 1
2 0
1
4
Ausgabedatei: gauss1-output.dat
2.000000
1.000000
Variante 2
Demoprogramme gauss21.cpp, gauss22.cpp und gauss21.c
Anders als bei Variante 1 wollen wir den Gauß-Algorithmus in Form des Resttableau-
Algorithmus als kompakte Funktion und die Ein-/Ausgabe als selbständige Funktionen de-
finieren und dabei die Möglichkeit der Eingabe- und Rückgabeparameter nutzen. Deshalb
sind dazu einige Erläuterungen zum Parameterkonzept sinnvoll.
Es gibt in C++/C mehrere Übergabeverfahren für Parameter.
(a) Werteparameter, call by value
Dies ist der übliche Weg, wo dem Parameter beim Aufruf der Funktion eine Variable über-
geben wird. Der Parameter wird dann mit dem Wert dieser Variablen initialisiert und stellt
eine Kopie der Variablen dar (erfordert zusätzlichen Speicherplatz), mit der die Funktion
arbeiten kann. Die übergebene Variable wird nicht von der aufrufenden Funktion verändert.
(b) Referenzparameter, call by reference
Dabei wird als Argument eine Adresse übergeben, und über diese Adresse kann die auf-
rufende Funktion auf ein Objekt zugreifen. Dieses sogenannte var-Objekt ist sowohl in der
Funktion als auch in ihrer Umgebung verfügbar. Vorgenommene Veränderungen in der Funk-
tion werden damit auch an die Umgebung zuruckgegeben (Rückgabeparameter).
Für Felder ist das Zeigerkonzept und damit die Adressübergabe fest in der Sprache veran-
kert. Für einfache Variablen muss ein Zeiger-Parameter (speichert und verwaltet Adressen)
verwendet werden, der auf das var-Objekt zugreift und es auch verändert.
Drei Möglichkeiten der Verwendung von Zeigern als Parameter und damit der Übergabe von
Adressen in Parametern gibt es.
- Direkte Übergabe der Adresse einer Variablen (&variable),
- analog dazu die Übergabe eines Zeigers,
- Übergabe einer Referenz (nur C++).
Betrachten wir die parameterabhängige Eingabefunktion
void eingabe(int n, double a[Nmax][Nmax], double b[Nmax])
{ int i,j;
printf("Matrixdimension n = ");
scanf("%d",&n);
printf("Matrixeingabe element- und zeilenweise\n");
for(i=0;i<n;i++)
for(j=0;j<n;j++) scanf("%lf",&a[i][j]);
printf("Rechte Seite elementweise\n");
for(i=0;i<n;i++) scanf("%lf",&b[i]);
}
23
Darin ist die Variable n ein Werteparameter sowie die Felder a und b automatisch Refe-
renzparameter. Die Felder stehen nach ihrer Eingabe innerhalb der Funktion auch in der
Umgebung (Rahmenprogramm) zur Verfügung. Die eingelesene Dimension n wird jedoch
nicht zurückgegeben. Das soll nun verändert werden.
printf("Matrixdimension n = ");
scanf("%d",n); // genauso scanf("%d",&*n);
printf("Matrixeingabe element- und zeilenweise\n");
for(i=0;i<*n;i++)
for(j=0;j<*n;j++)
scanf("%lf",&a[i][j]);
printf("Rechte Seite elementweise\n");
for(i=0;i<*n;i++)
scanf("%lf",&b[i]);
}
printf("Matrixdimension n = ");
scanf("%d",&n);
printf("Matrixeingabe element- und zeilenweise\n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%lf",&a[i][j]);
printf("Rechte Seite elementweise\n");
for(i=0;i<n;i++)
scanf("%lf",&b[i]);
}
Bemerkenswert ist die Syntax für die Funktion mit dem Referenzparameter.
Die Funktion sieht der Werteparameter-Version sehr ähnlich. Nur in der Parameterdeklara-
tion zeigt das Adresssymbol &, dass es sich um einen Referenzparameter handelt. Auch der
Aufruf ist identisch.
24
Demoprogramm gauss21.c mit Übergabeverfahren von Zeiger
(genauso gauss21.cpp mit Übergabeverfahren von Zeiger,
analog gauss22.cpp mit Übergabeverfahren von Referenz)
/* gauss21.c */
/* Resttableau-Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
/* Tausch mit betragsgroessten NNE in der Spalte */
/* Ax=b, A => L\U, P, PA=LU */
/* Ux=c Loesung mit Rueckwaertseinsetzen */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define Nmax 10
printf("Matrixdimension n = ");
scanf("%d",n); // genauso richtig ist scanf("%d",&*n);
// Kontrolle
// printf("*n=%d\n",*n); // n
// printf("n=%d\n",n); // Adresse auf n
// printf("&*n=%d\n",&*n); // gleiches Ergebnis
// getch();
printf("Loesungsvektor\n");
for(i=0;i<n;i++)
printf("%lf ",x[i]);
printf("\nPermutationsvektor\n");
for(i=0;i<n;i++)
printf("%d ",1+ind[i]);
printf("\n");
}
void gauss(int n, int *t, double a[Nmax][Nmax], double b[Nmax], double x[Nmax], int ind[Nmax], int *sing)
{
double max,s,eps;
int i,j,m,index,h;
/* Initialisierung */
*sing = 0;
for(m=0;m<n;m++) /* Permutationsvektor */
ind[m] = m;
eps = 1e-12; /* Toleranz fuer Test auf Singularitaet */
/* Hinrechnung */
for(m=0;m<n;m++)
{
/* Pivotsuche */
max = 0.0;
for(i=m;i<n;i++)
{
s = a[i][m];
if(fabs(s)>fabs(max))
{
25
max = s;
index = i;
}
}
/* Zeilentausch */
if(index>m)
{
h = ind[m];
ind[m] = ind[index];
ind[index] = h;
for(i=0;i<n;i++)
{
s = a[m][i];
a[m][i] = a[index][i];
a[index][i] = s;
}
s = b[m];
b[m] = b[index];
b[index] = s;
}
/* Rueckrechnung */
for(i=n-1;i>=0;i--)
{
s = -b[i];
for(j=n-1;j>i;j--)
s += a[i][j]*x[j];
x[i] = -s/a[i][i];
}
_LM1: ;
}
int main()
{ int n,abb,t,i,j;
double a[Nmax][Nmax],b[Nmax],x[Nmax];
int ind[Nmax];
printf("Gauss-Algorithmus: Resttableau-Algorithmus\n");
printf("mit Spaltenpivotisierung und Zeilenvertauschung\n\n");
eingabe(&n,a,b);
gauss(n,&t,a,b,x,ind,&abb);
if(abb==1)
{
printf("Gleichungssystem nicht loesbar!\n");
getch();
return(-1);
}
ausgabe(n,x,ind);
getch();
return(0);
}
26
Das Ergebnisfenster ist
Matrixdimension n = 2
Matrixeingabe element- und zeilenweise
1
2
4
6
Rechte Seite elementweise
1
1
Loesungsvektor
-2.000000 1.500000
Permutationsvektor
2 1
———————————————————————————————————-
Gauss-Algorithmus: Resttableau-Algorithmus
mit Spaltenpivotisierung und Zeilenvertauschung
Matrixdimension n = 2
Matrixeingabe element- und zeilenweise
1
2
1
2
Rechte Seite elementweise
1
1
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define Nmax 10
27
void ausgabe(int, double*, int*);
int main()
{ int n,abb,t,i,j;
double a[Nmax][Nmax],b[Nmax],x[Nmax];
int ind[Nmax];
printf("Gauss-Algorithmus: Resttableau-Algorithmus\n");
printf("mit Spaltenpivotisierung und Zeilenvertauschung\n\n");
eingabe(&n,a,b);
gauss(n,&t,a,b,x,ind,&abb);
if(abb==1)
{
printf("Gleichungssystem nicht loesbar!\n");
getch();
return(-1);
}
ausgabe(n,x,ind);
getch();
return(0);
}
printf("Matrixdimension n = ");
scanf("%d",n);
printf("Matrixeingabe element- und zeilenweise\n");
for(i=0;i<*n;i++)
for(j=0;j<*n;j++)
scanf("%lf",&a[i][j]);
printf("Rechte Seite elementweise\n");
for(i=0;i<*n;i++)
scanf("%lf",&b[i]);
}
printf("\nLoesungsvektor\n");
for(i=0;i<n;i++)
printf("%lf ",x[i]);
printf("\nPermutationsvektor\n");
for(i=0;i<n;i++)
printf("%d ",1+ind[i]);
printf("\n");
}
/* Initialisierung */
*sing = 0;
for(m=0;m<n;m++) ind[m] = m; /* Permutationsvektor */
eps = 1e-12; /* Toleranz fuer Test auf Singularitaet */
/* Hinrechnung */
for(m=0;m<n;m++)
{ /* Pivotsuche */
max = 0.0;
for(i=m;i<n;i++)
{ s = a[i][m];
if(fabs(s)>fabs(max))
{ max = s;
index = i;
}
}
/* Test auf Singularitaet */
if(fabs(max)<eps)
{ *sing = 1;
*t = m;
28
printf("\nMatrix singulaer, Abbruch im Schritt %d\n",m+1);
goto _LM1;
}
/* Zeilentausch */
if(index>m)
{ h = ind[m];
ind[m] = ind[index];
ind[index] = h;
for(i=0;i<n;i++)
{ s = a[m][i];
a[m][i] = a[index][i];
a[index][i] = s;
}
s = b[m];
b[m] = b[index];
b[index] = s;
}
/* Bestimmung der Spaltenelemente und Zeilenelemente */
for(i=m+1;i<n;i++)
{ s = a[i][m]/max;
a[i][m] = s;
for(j=m+1;j<n;j++)
a[i][j] = a[i][j]-s*a[m][j];
b[i] = b[i]-s*b[m];
}
}
/* Rueckrechnung */
for(i=n-1;i>=0;i--)
{ s = -b[i];
for(j=n-1;j>i;j--)
s += a[i][j]*x[j];
x[i] = -s/a[i][i];
}
_LM1: ;
}
int main()
{ int n,abb,t,i,j;
double a[Nmax][Nmax],b[Nmax],x[Nmax];
int ind[Nmax];
printf("Gauss-Algorithmus: Resttableau-Algorithmus\n");
printf("mit Spaltenpivotisierung und Zeilenvertauschung\n\n");
eingabe(n,a,b);
gauss(n,t,a,b,x,ind,abb);
if(abb==1)
{
printf("Gleichungssystem nicht loesbar!\n");
getch();
return(-1);
}
ausgabe(n,x,ind);
getch();
return(0);
}
void gauss(int n, int &t, double a[Nmax][Nmax], double b[Nmax], double x[Nmax], int ind[Nmax], int &sing)
...
29
• Als zweites erzeugen wir zu den Prototypen für die 3 Funktionen eingabe, ausgabe, gauss
eine Header-Datei und nehmen diese ins Rahmenprogramm auf.
C-Version: Header-Datei gauss2b.h.
/* gauss2b.h */
/* Resttableau-Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define Nmax 10
Diese liegt im selben Verzeichnis wie das einschließende Programm gauss2b.c und wird
dort verwendet.
/* gauss2b.c */
/* Resttableau-Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include "gauss2b.h" // Header-Datei im aktuellen Verzeichnis
// Definitionen und Prototypen eingabe, gauss, ausgabe
int main()
...
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define Nmax 10
Diese liegt im selben Verzeichnis wie das einschließende Programm gauss2b.cpp und wird
dort verwendet.
/* gauss2b.cpp */
/* Resttableau-Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include "gauss2bp.h" // Header-Datei im aktuellen Verzeichnis
// Definitionen und Prototypen eingabe, gauss, ausgabe
int main()
...
30
• Als dritten und letzten Schritt nehmen wir die Header-Datei zu den 3 Prototypen, bilden
aus deren Definitionen einen eigenständigen Quelltext, um schließlich mit dem Rahmenpro-
gramm ein Projekt daraus zu konstruieren.
C-Version:
Header-Datei gauss2b.h.
Quelltext gauss2cc.c.
/* gauss2cc.c */
/* Resttableau-Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include "gauss2b.h" // Header-Datei im aktuellen Verzeichnis
// Definitionen und Prototypen eingabe, gauss, ausgabe
int main()
...
31
3. Damit öffnet sich ein neues Auswahlfenster Create new project
Speichern in: C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\projekt1
Dateiname: gauss2c Speichern
Dateityp: dev-c++ project(*.dev)
Es erscheint unter Projekt im Projektfenster folgender Baum des noch leeren Projekts
gauss2c.
ℵ≡ gauss2c
S
[Views]
ProjectView=1
4. Nun vervollständigt man das Projekt um die Komponenten gauss2c.c und gauss2cc.c.
Menüpunkt Projekt
⇒ Zum Projekt hinzufügen
Damit öffnet sich das Auswahlfenster Unit öffnen
Suchen in: projekt1 (aktuelles Verzeichnis)
Dateiname: gauss2c Öffnen
Dateityp: All known Files
Genauso mit gauss2cc.
Im Projektfenster vergrößert sich der Baum des Projekts gauss2c. Es erscheint
2- –ℵ≡ gauss2c
S
||− gauss2c.c
|− gauss2cc.c
Hinzugefügte Komponenten können durch Anklicken als Quelltexte angezeigt werden.
Gleichzeitig vergrößert sich im Verzeichnis die Projektdatei gauss2c.dev.
[Project]
FileName=gauss2c.dev
Name=gauss2c
UnitCount=2
Type=1
Ver=1
ObjFiles=
Includes=
Libs=
PrivateResource=
ResourceIncludes=
MakeIncludes=
Resources=
Compiler=
Linker=
IsCpp=0
Icon=
ExeOutput=
ObjectOutput=
OverrideOutput=0
32
OverrideOutputName=
Folders=
CommandLine=
Focused=1
Order=0,1
[Unit1]
FileName=gauss2c.c
Open=1
Folder=
Top=0
CursorCol=1
CursorRow=1
TopLine=1
LeftChar=1
[Unit2]
FileName=gauss2cc.c
Open=1
Folder=
Top=1
CursorCol=1
CursorRow=1
TopLine=1
LeftChar=1
[Views]
ProjectView=1
Das Projekt kann also konfiguriert werden, indem insbesondere überflüssige Knoten
(Programme) gelöscht und neue Knoten hinzugefügt werden (hierarchische Struktur).
5. Es ist manchmal sinnvoll bzw. notwendig, Verzeichnisse von eingebundenen Dateien
(C-Includes, C++-Includes) zu ergänzen.
Menüpunkt Werkzeuge
⇒ Compiler Optionen
Damit öffnet sich das Auswahlfenster Compiler Optionen
Unter Verzeichnisse und C-Includes kann im Fenster das Verzeichnis
C:\d\neundorf\nwptexte\tech_phy\05\dev_cpp\projekt1
eingetragen werden. Dann Hinzufügen und Ok .
6. Man klickt nun auf das Projekt gauss2c und kommt zum
• Menüpunkt Ausführen
⇒ Kompilieren
Es folgen Informationen zum Übersetzen und im Kompilier Log steht
Building Makefile: "C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\projekt1\Makefile.win"
Fuehrt make... aus
33
Im Verzeichnis stehen dann die ausführbare Datei gauss2c.exe sowie die Objektda-
teien gauss2c.o und gauss2cc.o.
Sind die Objektdateien zu diesem Projekt schon vorhanden (z. B. durch wiederhol-
ten Aufruf), so müssen diese nicht erzeugt werden und die Information verkürzt sich
entsprechend. Legt man im Verzeichnis jedoch ein weiteres Projekt an, das zufällig
dieselben Namen von Objektdateien verwendet, sollte man zuvor die “alten“ Objekte
löschen.
Dazu kommt zum Projekt noch das sogenannte Makefile Makefile.win.
# Project: gauss2c
# Makefile created by Dev-C++ 4.9.6.0
CC = gcc.exe
WINDRES = windres.exe
RES =
OBJ = gauss2c.o gauss2cc.o $(RES)
LIBS = -L"C:/Dev-Cpp/lib"
INCS = -I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt1"
BIN = gauss2c.exe
CFLAGS = $(INCS) -s
clean: clean-custom
rm -f $(OBJ) $(BIN)
$(BIN): $(OBJ)
$(CC) $(OBJ) -o "gauss2c.exe" $(LIBS) $(CFLAGS)
gauss2c.o: gauss2c.c
$(CC) -c gauss2c.c -o gauss2c.o $(CFLAGS)
gauss2cc.o: gauss2cc.c
$(CC) -c gauss2cc.c -o gauss2cc.o $(CFLAGS)
Das Makefile zeigt an, wie das Projekt aufgebaut ist, wie es abgearbeitet wir, wel-
che Abhängigkeiten zwischen einzelnen Programmmodulen bestehen und welche Pro-
grammbibliotheken eingebunden sind. Unter Unix bzw. Linux kann es einfach mit dem
Kommando make aufgerufen werden. Unter Windows gibt es dies nicht.
• Menüpunkt Ausführen
⇒ Ausführen
Es folgt das Ausführen des Programms mit den Fenster für Ein- und Ausgaben.
• Menüpunkt Ausführen
⇒ Kompilieren u. Ausführen
Es folgen Informationen zum Übersetzen und im Kompilier Log steht
Ausfuehrung beendet
Kompilierung erfolgreich
Diese Kurzform ergibt sich, wenn das Makefile schon vorhanden ist.
34
C++-Version:
Header-Datei gauss2bp.h.
Quelltext gauss2cc.cpp.
/* gauss2cc.cpp */
/* Resttableau-Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include "gauss2bp.h" // Header-Datei im aktuellen Verzeichnis
// Definitionen und Prototypen eingabe, gauss, ausgabe
int main()
...
Der Umgang mit diesem Projekt, das hier dasselbe Verzeichnis benutzen soll, ist sehr ähn-
lich zum vorhergehenden Projekt gauss2c. Es kann aber immer nur ein Projekt bearbeitet
werden.
Ein Unterschied besteht darin, dass man es natürlich mit C++ zu tun hat und der Compiler
g++ verwendet wird.
Dann beachte man die Modifikationen in den Funktionen eingabe, gauss bezüglich der
Verwendung von Referenzparametern.
Da die Komponenten des Projekts gauss2cpp dieselben Bezeichner haben wie die vom
Projekt gauss2c, ist es ratsam vor der Kompilierung bestehende “alte“ Objektdateien
gauss2c.o und gauss2cc.o sicherheitshalber zu löschen.
Im vorliegenden Fall kann jedoch jedes der beiden Projekte jeweils mit den Objektdateien
des anderen arbeiten.
Klickt man den Schalter Klassen an, so erscheinen im Projektfenster die Klassen (hier
Funktionen) main, ausgabe, eingabe, gauss.
35
Variante 3
Demoprogramme gauss31.cpp, gauss32.cpp und gauss31.c
Ähnlich zur Variante 2 wollen wir den Gauß-Algorithmus in Form des verketteten Algorith-
mus als kompakte Funktion und die Ein-/Ausgabe als selbständige Funktionen definieren und
dabei die schon beschriebenen Möglichkeiten der Eingabe- und Rückgabeparameter nutzen.
Demoprogramm gauss31.c mit Übergabeverfahren von Zeiger
(genauso gauss31.cpp mit Übergabeverfahren von Zeiger,
analog gauss32.cpp mit Übergabeverfahren von Referenz)
/* gauss31.c */
/* Verketteter Gauss-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung */
/* Tausch mit betragsgroessten NNE in der Spalte */
/* Ax=b, A => (-L)\U, P, PA=LU */
/* Ux=c Loesung mit Rueckwaertseinsetzen */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define Nmax 10
printf("Matrixdimension n = ");
scanf("%d",n); // genauso richtig ist scanf("%d",&*n);
printf("Matrixeingabe element- und zeilenweise\n");
for(i=0;i<*n;i++)
for(j=0;j<*n;j++)
scanf("%lf",&a[i][j]);
printf("Rechte Seite elementweise\n");
for(i=0;i<*n;i++)
scanf("%lf",&b[i]);
}
printf("\nLoesungsvektor\n");
for(i=0;i<n;i++)
printf("%lf ",x[i]);
printf("\nPermutationsvektor\n");
for(i=0;i<n;i++)
printf("%d ",1+ind[i]);
printf("\n");
}
void gauss(int n, int *t, double a[Nmax][Nmax], double b[Nmax], double x[Nmax], int ind[Nmax], int *sing)
{
double max,s,eps;
int i,j,m,index,h;
/* Initialisierung */
*sing = 0;
for(m=0;m<n;m++) ind[m] = m; /* Permutationsvektor */
eps = 1e-12; /* Toleranz fuer Test auf Singularitaet */
/* Hinrechnung */
for(m=0;m<n;m++)
{
/* Pivotsuche */
max = 0.0;
for(i=m;i<n;i++)
{ s = a[i][m];
for(j=0;j<m;j++)
s += a[i][j]*a[j][m];
a[i][m] = s;
if(fabs(s)>fabs(max))
{ max = s;
36
index = i;
}
}
/* Test auf Singularitaet */
if(fabs(max)<eps)
{ *sing = 1;
*t = m;
printf("\nMatrix singulaer, Abbruch im Schritt %d\n",m+1);
goto _LM1;
}
/* Zeilentausch */
if(index>m)
{ h = ind[m];
ind[m] = ind[index];
ind[index] = h;
for(i=0;i<n;i++)
{ s = a[m][i];
a[m][i] = a[index][i];
a[index][i] = s;
}
s = b[m];
b[m] = b[index];
b[index] = s;
}
/* Bestimmung der Spaltenelemente */
for(i=m+1;i<n;i++)
a[i][m] = -a[i][m]/max;
/* Bestimmung der Zeilenelemente */
for(i=m+1;i<n;i++)
{ s = a[m][i];
for(j=0;j<m;j++)
s += a[m][j]*a[j][i];
a[m][i] = s;
}
s = b[m];
for(j=0;j<m;j++)
s += a[m][j]*b[j];
b[m] = s;
}
/* Rueckrechnung */
for(i=n-1;i>=0;i--)
{ s = -b[i];
for(j=n-1;j>i;j--)
s += a[i][j]*x[j];
x[i] = -s/a[i][i];
}
_LM1: ;
}
int main()
{ int n,abb,t,i,j;
double a[Nmax][Nmax],b[Nmax],x[Nmax];
int ind[Nmax];
printf("Verketteter Gauss-Algorithmus\n");
printf("mit Spaltenpivotisierung und Zeilenvertauschung\n\n");
eingabe(&n,a,b);
gauss(n,&t,a,b,x,ind,&abb);
if(abb == 1)
{ printf("Gleichungssystem nicht loesbar!\n");
getch();
return(-1);
}
ausgabe(n,x,ind);
getch();
return(0);
}
37
4.2 Aufgabe 2
Aus der Aachener Bibliothek wollen wir den Komplex LGS mit Gauß-Algorithmus auswählen.
Das Demoprogramm TGAUSS.C befindet sich im Verzeichnis \CNUM8\04\TST und um-
fasst inhaltlich mehr als den Gauß-Algorithmus.
Die dortigen Include-Anweisungen für die Header-Dateien
Nun stellt man das C-Projekt gemäß der Vorgehensweise in Abschnitt 4.1 zusammen.
Projekt tgauss mit
Rahmenprogramm tgauss.c,
Quelltexte fgauss.c, basis.c, vmblock.c,
Header-Dateien basis.h, u proto.h, vmblock.h
Klickt man den Schalter Klassen an, so erscheint im Projektfenster eine umfangreiche Liste
von Klassen und Funktionen zum Projekt.
Man klickt nun auf das Projekt tgauss und kommt zum
• Menüpunkt Ausführen
⇒ Kompilieren u. Ausführen
Es folgen Informationen zum Übersetzen und im Kompilier Log steht
Building Makefile: "C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\projekt2\Makefile.win"
Fuehrt make... aus
38
gcc.exe -c basis.c -o basis.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt2" -s
Ausfuehrung beendet
Kompilierung erfolgreich
Im Verzeichnis stehen dann die Projektdatei tgauss.dev, die ausführbare Datei tgauss.exe
sowie die Objektdateien tgauss.o, fgauss.o, basis.o, vmblock.o.
Dazu kommt zum Projekt noch das sogenannte Makefile Makefile.win.
# Project: tgauss
# Makefile created by Dev-C++ 4.9.6.0
CC = gcc.exe
WINDRES = windres.exe
RES =
OBJ = basis.o vmblock.o fgauss.o tgauss.o $(RES)
LIBS = -L"C:/Dev-Cpp/lib"
INCS = -I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt2"
BIN = tgauss.exe
CFLAGS = $(INCS) -s
clean: clean-custom
rm -f $(OBJ) $(BIN)
$(BIN): $(OBJ)
$(CC) $(OBJ) -o "tgauss.exe" $(LIBS) $(CFLAGS)
basis.o: basis.c
$(CC) -c basis.c -o basis.o $(CFLAGS)
vmblock.o: vmblock.c
$(CC) -c vmblock.c -o vmblock.o $(CFLAGS)
fgauss.o: fgauss.c
$(CC) -c fgauss.c -o fgauss.o $(CFLAGS)
tgauss.o: tgauss.c
$(CC) -c tgauss.c -o tgauss.o $(CFLAGS)
39
Beispiel Ax = b
1 2 1 ∗ −1 −2
A= , b= , x =A b=
4 6 1 1.5
n
1 0 1 2 X
det(A) = −2, A = , trace(A) = spur(A) = aii ,
4 1 0 −2
i=1
−1 −3 1 −T −3 2
A = , A =
2 −0.5 1 −0.5
0 1 4 6 1 0 4 6
p = (2, 1), P = , PA = = = LU
1 0 1 2 0.25 1 0 0.5
Eingabe- und Ergebnisfenster
Haltepunkte wie getch(); sind bei der Ausgabe großer Datenmengen als auch nach Fehler-
meldungen sinvoll.
40
——————————————————————————————–
Solution without iterative improvement, one right side vector
——————————————————————————————–
Input vector (right side elementwise):
1
1
A:
1.000000 2.000000
4.000000 6.000000
b:
1.000000 1.000000
LU:
4.000000 6.000000
0.250000 0.500000
perm:
1 0
Solution:
x: -2.000000 1.500000
——————————————————————————————–
Solution with iterative improvement
——————————————————————————————–
Input vector (right side elementwise):
1
1
A:
1.000000 2.000000
4.000000 6.000000
b:
1.000000 1.000000
LU:
4.000000 6.000000
0.250000 0.500000
perm:
1 0
Solution
x: -2.000000 1.500000
——————————————————————————————–
Solution with post iteration for right sides = identity vectors
——————————————————————————————–
b: 1.000000 0.000000
x: -3.000000 2.000000
b: 0.000000 1.000000
x: 1.000000 -0.500000
——————————————————————————————–
41
4.3 Aufgabe 3
In Abschnitt 1, Aufgabe 5, haben wir das Newtonsche Näherungsverfahren für Nullstellen
von skalaren Funktionen als Demoprogramm tnewton1.c vorgestellt.
Die Definitionen und Prototypen, also die Prozedurköpfe usw., findet man in den Header-
Files basis.h, u_proto.h, tfunc1.h als Vorabdeklarationen und werden damit bekannt
gemacht.
Ihre eigentliche Definition erfolgt in den Funktionen fnewtonc.c, tfunc1.c, basis.c.
Dazu brauchen wir die Dateien
\CNUM8\02\TST\TNEWTON.C /*Test program for newton*/
\CNUM8\02\TST\TFUNC1.C /*Definition of test functions for newton, pegasus,..*/
/*1. and 2. derivity*/
\CNUM8\02\FNEWTON.C /*Numerische Verfahren zur Loesung NLG: NV,...*/
\CNUM8\BASIS\BASIS.C /*grundlegende Funktionen: Definitionsdatei*/
Daraus machen wir nun das C-Projekt tnewton im Verzeichnis
C:\d\Neundorf\nwptexte\tech phy\05\dev cpp\projekt3,
in das alle Dateien (Bezeichner klein geschrieben) kopiert werden.
Man klickt nun auf das Projekt tnewton und kommt zum
• Menüpunkt Ausführen
⇒ Kompilieren u. Ausführen
Es folgen Informationen zum Übersetzen, es entstehen im Verzeichnis die entsprechenden
Dateien *.o, *.exe und im Kompilier Log steht
Building Makefile: "C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\projekt3\Makefile.win"
Fuehrt make... aus
42
Das Ergebnisfenster ist
f = 5∗x-exp(x)
Start value x0 = 2.000000
Return code = 1
Root = 2.5426413577735265
Function value = -3.448110e-014
Iterations =7
f = (((((x-6)∗x+15)∗x-20)∗x+15)∗x-6)∗x+1
Start value x0 = 1.000000
Return code = 0
Root = 1.0000000000000000
Function value = 0.000000e+000
Iterations =0
f = sin(x)
Start value x0 = 2.000000
Return code = 0
Root = 3.1415926535897931
Function value = 1.224606e-016
Iterations =6
f = 1+sin(x)
Start value x0 = 2.000000
Return code = 0
Root = 4.7123890100448769
Function value = 4.398608e-016
Iterations = 26
f = exp(x)-(1.0+x+x∗x∗0.5)
Start value x0 = 1.000000
Return code = 0
Root = 0.0000143482588343
Function value = 3.555099e-016
Iterations = 170
f = (x-1.0)∗(x-1.0)∗(sin(PI∗x)-log(fabs(2.0∗x/(x+1.0)))
Start value x0 = 1.000000
Return code = 0
Root = 1.0000000000000000
Function value = 0.000000e+000
Iterations =0
——————————————————————————–
43
4.4 Aufgabe 4
Nun soll ein etwas umfangreicheres Projekt zur Lösung LGS mit den Gauß-Algorithmus zu-
sammengestellt werden.
Der zentrale Datentyp ist ein Zeiger auf ein zweidimensionales Feld (Matrix) mit Kompo-
nenten vom Typ double. Vektoren werden in dieser Konvention als Feld mit einer Spalte
interpretiert. Der Datentyp laMatrix zeigt auf eine Struktur, die als Informationen die
Zeilen- und Spaltenmdimension sowie die Matrixelemente zeilenweise enthält.
Die Nummerierung der Zeilen und Spalten beginnt in C/C++ jeweils bei Null.
Der Resttableau-Gauß-Algorithmus mit Spaltenpivotisierung und Zeilenvertauschung aus
Abschnitt 4.1 (vergl. Demoprogramm gauss21.c mit Übergabeverfahren von Zeiger) muss
auf diesen Datentyp angepasst werden.
Die Koeffizientenmatrix A ist Eingabematrix und wird überschrieben durch die LU -Zerlegung
von P A, welche dann zurückgegeben wird. Deshalb werden Kopien von A und b angelegt.
Der Lösungsvektor x und der Permutationsvektor von p=perm für die Zeilenvertauschungen
sind einspaltige reelle Ergebnismatrizen. Die Komponenten von p sind wertemäßig natürliche
Zahlen, was in der formatierten Ausgabe berücksichtigt wird.
Falls der Gauß-Algorithmus nicht durchführbar ist, so weist der Ergebnisparameter sing6= 0
darauf hin, wobei mit der Größe t noch die Stufe (Schritt im Resttableau-Algorithmus) des
Abbruchs angezeigt werden kann. Gleichzeitig ist der Stand der Berechnungen bis zum even-
tuellen Abbruch abfragbar.
Die Toleranz ε=eps für den Test auf Singularität ist in der Funktion definiert und gegebe-
nenfalls zu verändern.
void gauss4c(int n, int *t, laMatrix *A, laMatrix b, laMatrix *x, laMatrix *perm, int *sing)
{
double max,s,eps,h;
int i,j,k,index;
/* Initialisierung */
*sing = 0;
*t = 0;
for(k=0;k<n;k++)
{
(*perm)[k][0] = k; /* Permutationsvektor */
(*x)[k][0] = 0;
}
eps = 1e-15; /* Toleranz fuer Test auf Singularitaet */
/* Hinrechnung */
for(k=0;k<n;k++)
{
/* Pivotsuche */
max = 0;
for(i=k;i<n;i++)
{
s = fabs((*A)[i][k]);
if(s>max)
{
max = s;
index = i;
}
}
44
/* Zeilentausch */
if(index>k)
{
h = (*perm)[k][0]; /* laVertauscheZe_(*perm,k,index); */
(*perm)[k][0] = (*perm)[index][0];
(*perm)[index][0] = h;
/*
for(i=0;i<n;i++)
{
s = (*A)[k][i];
(*A)[k][i] = (*A)[index][i];
(*A)[index][i] = s;
}
*/
laVertauscheZe_(*A,k,index);
s = b[k][0]; /* laVertauscheZe_(b,k,index); */
b[k][0] = b[index][0];
b[index][0] = s;
}
/* Rueckrechnung */
for(i=n-1;i>=0;i--)
{
s = -b[i][0];
for(j=n-1;j>i;j--)
s += (*A)[i][j]*(*x)[j][0];
(*x)[i][0] = -s/(*A)[i][i];
}
_LM1: for(k=0;k<n;k++)
(*perm)[k][0] = 1+(*perm)[k][0];
}
#include <stdlib.h>
#include <stdio.h>
45
void laMatAusgeben_(laMatrix A);
/* Gibt die Matrix A auf dem Bildschirm aus. */
46
double laSkalProd_(laMatrix A, laMatrix B);
/* Berechnet das Skalarprodukt der n*1-Matrizen (Vektoren) A und B und gibt den Wert zurueck.
Bei unzulaessigen Dimensionen Abbruch mit Fehlermeldung. */
#include <stdlib.h>
#include <stdio.h>
#include "la_.h"
if((n<1)||(m<1))
{
printf("Fehler: Dimension(en) unzulaessig\n");
getch();
exit(EXIT_FAILURE);
}
if((A = malloc(sizeof(double*)*n+2*sizeof(int)))==NULL)
{
fprintf(stderr,"Zu wenig Speicher\n");
getch();
exit(EXIT_FAILURE);
}
*((int*)A) = n;
*(((int*)A)+1) = m;
A = (double**)(((int*)A)+2);
for(i=0;i<n;i++)
if((*(A+i) = malloc(sizeof(double)*m))==NULL)
{
fprintf(stderr,"Zu wenig Speicher\n");
getch();
exit(EXIT_FAILURE);
}
return(A);
}
/*----------------------------------------------------------------------*/
void laVernichte_(laMatrix A)
{
unsigned i,n;
n = *(((int*)A)-2);
for(i=0;i<n;i++)
free(*(A+i));
free(((int*)A)-2);
}
/*----------------------------------------------------------------------*/
void laDim_(laMatrix A, int *n, int *m)
{
*n = *(((int*)A)-2);
*m = *(((int*)A)-1);
}
47
/*----------------------------------------------------------------------*/
laMatrix laTransponiere_(laMatrix A)
{
int n,m,i,j;
laMatrix B;
laDim_(A,&n,&m);
B = laMatrixNeu_(m,n);
for(i=0;i<=n;++i)
for(j=0;j<=m;++j)
B[j][i] = A[i][j];
laVernichte_(A);
return(B);
}
Die Funktionen für die Ein- und Ausgabe sind problemangepasst und im Modul laInOut_.c
zusammengefasst. Sie werden alle genutzt.
Dort aufgerufen werden auch die Funktionen laMatrixNeu_, laDim_.
// laInOut_.c
/* Eine Bibliothek fuer Lineare Algebra, Ein/Ausgaben */
/* Definitionen von laGlSysEinlesen_, laGlSysAusgeben_, laMatAusgeben_, laVektAusgeben_, laVektAusgebenI_ */
#include <stdlib.h>
#include <stdio.h>
//#include <conio.h>
#include "la_.h"
/*----------------------------------------------------------------------------*/
void laGlSysEinlesen_(laMatrix *A, laMatrix *b)
{
FILE *matIn;
int i,j,n,m;
char s[80]="Matrix.in"; // Initialisierung
for(i=0;i<n;i++)
for(j=0;j<m;j++)
fscanf(matIn,"%lf",&(*A)[i][j]);
for(i=0;i<n;i++)
fscanf(matIn,"%lf",&(*b)[i][0]);
fclose(matIn);
}
/*----------------------------------------------------------------------------*/
void laGlSysAusgeben_(laMatrix A, laMatrix b)
{
int i,j,n,m;
laDim_(A,&n,&m);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
printf(" %10.6lf ",A[i][j]);
printf(" | %10.6lf \n",b[i][0]);
}
}
48
void laMatAusgeben_(laMatrix A)
{
int i,j,n,m;
laDim_(A,&n,&m);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
printf(" %10.6lf ",A[i][j]);
printf("\n");
}
}
/*----------------------------------------------------------------------------*/
void laVektAusgeben_(laMatrix x)
{
int i,n,m;
laDim_(x,&n,&m);
for(i=0;i<n;i++)
printf(" %10.6lf ",x[i][0]);
printf("\n");
}
/*----------------------------------------------------------------------------*/
void laVektAusgebenI_(laMatrix x)
{
int i,n,m;
laDim_(x,&n,&m);
for(i=0;i<n;i++)
printf(" %2.0lf ",x[i][0]);
printf("\n");
}
Die Beispiele werden als ASCII-Dateien in der Datenreihenfolge n, m, A(1..n, 1..m), b(1..n), ...
bereitgestellt. Der Dateiname für die Daten A, b zum LGS wird eingelesen. Als Testvarianten
zeigen wir LGS mit regulären und singulären Koeffizientenmatrizen
(reg.: matrix23, matrix3, matrix40, sing.: matrix57, matrix58).
matrix23 matrix3 matrix40 matrix57 matrix58
-------- ------------------- ---------------- ------------ --------
3 3 2 2 5 5 3 3 3 3
1 -2 2 1.441969 1.040807 2 -3 1 -2 4 1 -2 2 2 2 2
-1 1 -1 1.040807 0.751250 -4 6 -2 5 -6 -1 2 -1 1 3 0
-2 -2 1 0.401162 6 -9 3 -4 10 -2 4 1 2 4 1
1 0.289557 2 -4 3 2 -3 1 5
-1 Loesung: -2 5 -3 2 -1 0 4
-3 1 7 3 7
Loesung: -1 -10 Loesung: Loesung:
1 EW: 17 1 keine
1 2.193218999999544 5 1 EW:
1 4.5595081932092e-13 1 1 0,1,5
EW: Loesung: EW:
1,1,1 14,14,13,0,2 0,2+-i*2.646
EW: 0.914
5.5713+-i*8.844
-0.0285+-i*0.489
Von den anderen selbständigen Definitionen benötigen wir eigentlich nur die Funktionen
laKopiere_, laVertauscheZe_ und wegen einiger Kontrollrechnungen auch laKopiere1_,
laAdd_, laNorm_. Aber es sollen jedoch alle zum Projekt hinzugefügt werden.
49
// laKopiere_.c, B = A
#include "la_.h"
laDim_(A,&n,&m);
laDim_(B,&r,&s);
if((n!=r)||(m!=s))
{
printf("Fehler: Matrizen sind nicht von gleicher Dimension\n");
getch();
exit(EXIT_FAILURE);
}
for(i=0;i<n;i++)
for(j=0;j<m;j++)
B[i][j] = A[i][j];
}
laDim_(A,&n,&m);
if((r<0)||(r>n-1)||(s<0)||(s>n-1))
{
printf("Fehler: Zeilennummer(n) unzulaessig\n");
getch();
exit(EXIT_FAILURE);
}
for(j=0;j<m;j++)
{
h = A[s][j];
A[s][j] = A[r][j];
A[r][j] = h;
}
}
---------------------------------------------------------------------
// laKopiere1_.c, B = A
#include "la_.h"
laDim_(A,&n,&m);
*B = laMatrixNeu_(n,m);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
(*B)[i][j] = A[i][j];
}
// laAdd_.c, C = A+B
#include "la_.h"
laDim_(A,&n,&m);
laDim_(B,&k,&l);
if((n!=k)||(m!=l))
{
printf("Fehler: Matrixdimension(en) nicht gleich\n");
getch();
exit(EXIT_FAILURE);
}
*C = laMatrixNeu_(n,m);
for(i=0;i<n;i++)
50
for(j=0;j<m;j++)
(*C)[i][j] = A[i][j]+B[i][j];
}
no = 0;
if((cc!=’u’)&&(cc!=’1’)&&(cc!=’2’)&&(cc!=’F’))
{
printf("Fehler: Falsche Norm\n");
getch();
exit(EXIT_FAILURE);
}
laDim_(A,&n,&m);
// Fallunterscheidung m=1 und m>1
if(m==1)
switch (cc)
{
case ’u’: for(i=0;i<n;i++)
if (fabs(A[i][0])>no)
no = fabs(A[i][0]);
break;
case ’1’: for(i=0;i<n;i++)
no += fabs(A[i][0]);
break;
case ’2’: for(i=0;i<n;i++)
no += A[i][0]*A[i][0];
no = sqrt(no);
break;
}
else
switch (cc)
{
case ’u’: for(i=0;i<n;i++)
{
h = 0;
for(j=0;j<m;j++)
h += fabs(A[i][j]);
if (h>no) no = h;
}
break;
case ’1’: for(j=0;j<m;j++)
{
h = 0;
for(i=0;i<n;i++)
h += fabs(A[i][j]);
if (h>no) no = h;
}
break;
case ’F’: for(i=0;i<n;i++)
for(j=0;j<m;j++)
no += A[i][j]*A[i][j];
no = sqrt(no);
break;
}
return(no);
}
---------------------------------------------------------------------
51
M = laNull_(n,m);
if(n>m) min = m; else min = n;
for (i=0;i<min;i++)
M[i][i] = 1;
return M;
}
laDim_(A,&n,&m);
laDim_(B,&k,&l);
if((n!=k)||(m!=l))
{
printf("Fehler: Matrizen sind nicht von gleicher Dimension\n");
getch();
exit(EXIT_FAILURE);
}
*C = laMatrixNeu_(n,m);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
(*C)[i][j] = A[i][j]*B[i][j];
}
if((A==*C)||(B==*C))
{
fprintf(stderr,"Fehler: Gleiche Zeiger\n");
getch();
exit(EXIT_FAILURE);
}
laDim_(A,&na,&ma);
laDim_(B,&nb,&mb);
if((na!=3)||(ma!=1)||(nb!=3)||(mb!=1))
{
fprintf(stderr,"In A,B Zeilenanzahl<>3, Spaltenanzahl<>1\n");
exit(EXIT_FAILURE);
}
*C = laMatrixNeu_(3,1);
(*C)[0][0] = A[1][0]*B[2][0]-A[2][0]*B[1][0];
(*C)[1][0] =-A[0][0]*B[2][0]+A[2][0]*B[0][0];
(*C)[2][0] = A[0][0]*B[1][0]-A[1][0]*B[0][0];
}
// laMult_.c, C = AB algebraisch
#include "la_.h"
52
h = 0;
for(k=0;k<m;k++)
h += A[i][k]*B[k][j];
(*C)[i][j] = h;
}
}
if((n<1)||(m<1))
{
printf("Fehler: Dimension(en) unzulaessig\n");
getch();
exit(EXIT_FAILURE);
}
M = laMatrixNeu_(n,m);
for (i=0;i<n;i++)
for (j=0;j<m;j++)
M[i][j] = 0;
return M;
}
laDim_(A,&n,&m);
laDim_(B,&k,&l);
if((n==k)&&(m==1)&&(l==1))
{
erg=0;
for(i=0;i<n;i++)
erg += A[i][0]*B[i][0];
return (erg);
}
printf("Fehler: Falsche Dimension(en)\n");
getch();
exit(EXIT_FAILURE);
}
laDim_(A,&n,&m);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
A[i][j] = A[i][j]*z;
}
// laSub_.c, C = A-B
#include "la_.h"
laDim_(A,&n,&m);
laDim_(B,&k,&l);
if((n!=k)||(m!=l))
{
53
printf("Fehler: Matrixdimension(en) nicht gleich\n");
getch(); exit(EXIT_FAILURE);
}
*C = laMatrixNeu_(n,m);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
(*C)[i][j] = A[i][j]-B[i][j];
}
laDim_(A,&n,&m);
if((r<0)||(r>m-1)||(s<0)||(s>m-1))
{
printf("Fehler: Spaltennummer(n) unzulaessig\n");
getch(); exit(EXIT_FAILURE);
}
for(i=0;i<n;i++)
{
h = A[i][r];
A[i][r] = A[i][s];
A[i][s] = h;
}
}
Nun fehlt nur noch der Quelltext (Rahmenprogramm) meinprog_.c mit der main-Funktion.
In ihm befinden sich die notwendigen include-Anweisungen, die Funktion gauss4c, die
Eingaben, Berechnungen, Ausgaben sowie gewisse Kontrollrechnungen zwecks Überprufung
der Richtigkeit einiger Funktionen.
// meinprog_.c
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
//#include<conio.h>
#include "la_.h"
void gauss4c(int n, int *t, laMatrix *A, laMatrix b, laMatrix *x, laMatrix *perm, int *sing)
...
int main()
{
int n,m,t,sing;
double erg;
laMatrix A,b,x,LU,c,perm,C1,C2,C3;
char kont,prot;
laGlSysEinlesen_(&A,&b);
printf("Kontrollausgabe A,b (j/n)? ");
kont = getch();
printf("\n");
if(kont==’j’)
{
laDim_(A,&n,&m);
printf("\nDimension A(n,m): n=%i, m=%i\n",n,m);
printf("\nA | b\n");
laGlSysAusgeben_(A,b);
printf("-----------------------------------------------------------------------------\n\n");
getch();
}
54
laDim_(A,&n,&m);
if(n!=m)
{
printf("\nDimension n<>m, keine Berechnung");
getch();
return (-1);
}
LU = laMatrixNeu_(n,m);
laKopiere_(A,LU);
c = laMatrixNeu_(n,1);
laKopiere_(b,c);
x = laMatrixNeu_(n,1);
perm = laMatrixNeu_(n,1);
gauss4c(n,&t,&LU,c,&x,&perm,&sing);
if(sing==0)
{
printf("Loesungsvektor x\n");
laVektAusgeben_(x);
printf("-----------------------------------------------------------------------------\n");
getch();
}
printf("\nErgebnisprotokoll (j/n)? ");
prot = getch();
if(prot==’j’)
{
printf("\n---------------------------------------------------------------------------\n");
if (sing==1)
printf("Achtung! Vorzeitiger Abbruch im Schritt t = %i\n",t);
printf("Dimension A(n,m): n=%i, m=%i\n",n,m);
printf("\nA | b\n");
laGlSysAusgeben_(A,b);
if(sing==0)
{
printf("\nLoesungsvektor x\n");
laVektAusgeben_(x);
}
printf("\nPermutationsvektor perm\n");
laVektAusgebenI_(perm);
printf("\nZerlegung PA=L\\U\n");
laMatAusgeben_(LU);
printf("-----------------------------------------------------------------------------\n");
getch();
}
printf("\n\nKontrollrechnungen (j/n)? ");
kont = getch();
if(kont==’j’)
{
printf("\nC1 = LU mittels laKopiere_\n");
C1 = laMatrixNeu_(n,m);
laKopiere_(LU,C1);
laMatAusgeben_(C1);
printf("\nC2 = LU mittels laKopiere1_\n");
laKopiere1_(LU,&C2);
laMatAusgeben_(C2);
printf("\nC3 = A+C2\n");
laAdd_(A,C2,&C3);
laMatAusgeben_(C3);
printf("\nNormen von b\n");
laVektAusgeben_(b);
printf("||b||_u=%10.6lf, ||b||_1=%10.6lf, ||b||_2=%10.6lf\n",laNorm_(’u’,b),laNorm_(’1’,b),laNorm_(’2’,b));
printf("\nNormen von A\n");
laMatAusgeben_(A);
printf("||A||_u=%10.6lf, ||A||_1=%10.6lf, ||A||_F=%10.6lf\n",laNorm_(’u’,A),laNorm_(’1’,A),laNorm_(’F’,A));
getch();
laVernichte_(C1); laVernichte_(C2); laVernichte_(C3);
}
// Speicherplatz freigeben
laVernichte_(A); laVernichte_(LU);
laVernichte_(b); laVernichte_(c); laVernichte_(x); laVernichte_(perm);
}
55
Zusammenstellung des C-Projekts gauss4c im Arbeitsverzeichnis
C:\d\Neundorf\nwptexte\tech phy\05\dev cpp\projekt4
Im Projektfenster steht der Baum des Projekts. Die wirklich verwendeten Module sind fett
hervorgehoben.
2- –ℵ≡ gauss4c
S
||− la .c
|
|− laAdd .c
|
|− laEins_.c
|
|− laElemMult_.c
|
|− laInOut .c
|
|− laKopiere .c
|
|− laKopiere1 .c
|
|− laKreuzProd_.c
|
|− laMult_.c
|
|− laNorm .c
|
|− laNull_.c
|
|− laSkalProd_.c
|
|− laSkMult_.c
|
|− laSub_.c
|
|− laVertauscheSp_.c
|
|− laVertauscheZe .c
|
− meinprog .c
Klickt man den Schalter Klassen an, so erscheint im Projektfenster eine umfangreiche Liste
von Klassen und Funktionen zum Projekt.
Man klickt nun auf das Projekt gauss4c und kommt zum
• Menüpunkt Ausführen
⇒ Kompilieren u. Ausführen
Es folgen Informationen zum Übersetzen und im Kompilier Log steht
Building Makefile: "C:\d\Neundorf\nwptexte\tech_phy\05\dev_cpp\projekt4\Makefile.win"
Fuehrt make... aus
56
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
gcc.exe -c laNull_.c -o laNull_.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
gcc.exe -c laSkalProd_.c -o laSkalProd_.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
gcc.exe -c laSkMult_.c -o laSkMult_.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
gcc.exe -c laSub_.c -o laSub_.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
gcc.exe -c laVertauscheSp_.c -o laVertauscheSp_.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
gcc.exe -c laVertauscheZe_.c -o laVertauscheZe_.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
gcc.exe -c meinprog_.c -o meinprog_.o
-I"C:/Dev-Cpp/include" -I"C:/d/Neundorf/nwptexte/tech_phy/05/dev_cpp/projekt4" -s
Ausfuehrung beendet
Kompilierung erfolgreich
CC = gcc.exe
WINDRES = windres.exe
RES =
OBJ = la_.o laAdd_.o laEins_.o laElemMult_.o laInOut_.o laKopiere_.o laKopiere1_.o laKreuzProd_.o
laMult_.o laNorm_.o laNull_.o laSkalProd_.o laSkMult_.o laSub_.o laVertauscheSp_.o laVertauscheZe_.o
meinprog_.o $(RES)
LIBS = -L"C:/Dev-Cpp/lib"
INCS = -I"C:/Dev-Cpp/include"
BIN = gauss4c.exe
CFLAGS = $(INCS) -s
$(BIN): $(OBJ)
$(CC) $(OBJ) -o "gauss4c.exe" $(LIBS) $(CFLAGS)
la_.o: la_.c
$(CC) -c la_.c -o la_.o $(CFLAGS)
laAdd_.o: laAdd_.c
$(CC) -c laAdd_.c -o laAdd_.o $(CFLAGS)
laEins_.o: laEins_.c
$(CC) -c laEins_.c -o laEins_.o $(CFLAGS)
laElemMult_.o: laElemMult_.c
$(CC) -c laElemMult_.c -o laElemMult_.o $(CFLAGS)
laInOut_.o: laInOut_.c
$(CC) -c laInOut_.c -o laInOut_.o $(CFLAGS)
laKopiere_.o: laKopiere_.c
$(CC) -c laKopiere_.c -o laKopiere_.o $(CFLAGS)
laKopiere1_.o: laKopiere1_.c
$(CC) -c laKopiere1_.c -o laKopiere1_.o $(CFLAGS)
laKreuzProd_.o: laKreuzProd_.c
$(CC) -c laKreuzProd_.c -o laKreuzProd_.o $(CFLAGS)
laMult_.o: laMult_.c
$(CC) -c laMult_.c -o laMult_.o $(CFLAGS)
laNorm_.o: laNorm_.c
$(CC) -c laNorm_.c -o laNorm_.o $(CFLAGS)
laNull_.o: laNull_.c
57
$(CC) -c laNull_.c -o laNull_.o $(CFLAGS)
laSkalProd_.o: laSkalProd_.c
$(CC) -c laSkalProd_.c -o laSkalProd_.o $(CFLAGS)
laSkMult_.o: laSkMult_.c
$(CC) -c laSkMult_.c -o laSkMult_.o $(CFLAGS)
laSub_.o: laSub_.c
$(CC) -c laSub_.c -o laSub_.o $(CFLAGS)
laVertauscheSp_.o: laVertauscheSp_.c
$(CC) -c laVertauscheSp_.c -o laVertauscheSp_.o $(CFLAGS)
laVertauscheZe_.o: laVertauscheZe_.c
$(CC) -c laVertauscheZe_.c -o laVertauscheZe_.o $(CFLAGS)
meinprog_.o: meinprog_.c
$(CC) -c meinprog_.c -o meinprog_.o $(CFLAGS)
Obwohl die Bibliotheken Dev-Cpp/lib und Dev-Cpp/include mit ihren zahlreichen Header-
Files ins Projekt eingebunden sind, ist es notwendig, in den entsprechenden Modulen noch
die Include-Anweisungen zu belassen, also
#include<stdlib.h> // fuer EXIT_FAILURE
#include<stdio.h> // fuer stdin, stderr, ...
#include<math.h> // fuer mathematische Standardfunktionen
Beispiel 1 Ax = b, A regulär
1 −2 2 1 1
∗ −1
A= −1 1 −1 , b =
−1 , eindeutige Lösung x = A b =
1 ,
−2 −2 1 −3 1
0 0 1
p = (3, 1, 2), P = 1 0 0 (Permutationsmatrix),
0 1 0
−2 −2 1 1 0 0 −2 −2 1
P A = 1 −2 2 = − 12 1 0 0 −3 5
= LU.
2
1 2 1
−1 1 −1 2
−3 1 0 0 6
Eingabe- und Ergebnisfenster
Haltepunkte wie getch() sind bei der Ausgabe großer Datenmengen als auch nach Fehler-
meldungen sinvoll.
58
Fortsetzung
2 C:\d\Neundorf\nwptexte\tech phy\05\dev cpp\projekt4\gauss4c.exe
Ergebnisprotokoll (j/n)?
————————————————————————————————————
Dimension A(n,m): n=3, m=3
A| b
1.000000 -2.000000 2.000000 | 1.000000
-1.000000 1.000000 -1.000000 | -1.000000
-2.000000 -2.000000 1.000000 | -3.000000
Loesungsvektor x
1.000000 1.000000 1.000000
Permutationsvektor perm
3 1 2
Zerlegung PA=L\U
-2.000000 -2.000000 1.000000
-0.500000 -3.000000 2.500000
0.500000 -0.666667 0.166667
————————————————————————————————————
Kontrollrechnungen (j/n)?
C1 = LU mittels laKopiere
-2.000000 -2.000000 1.000000
-0.500000 -3.000000 2.500000
0.500000 -0.666667 0.166667
C2 = LU mittels laKopiere1
-2.000000 -2.000000 1.000000
-0.500000 -3.000000 2.500000
0.500000 -0.666667 0.166667
C3 = A+C2
-1.000000 -4.000000 3.000000
-1.500000 -2.000000 1.500000
-1.500000 -2.666667 1.166667
Normen von b
1.000000 -1.000000 -3.000000
||b|| u= 3.000000, ||b|| 1= 5.000000, ||b|| 2= 3.316625
Normen von A
1.000000 -2.000000 2.000000
-1.000000 1.000000 -1.000000
-2.000000 -2.000000 1.000000
||A|| u= 5.000000, ||A|| 1= 5.000000, ||A|| F= 4.582576
Für die Ergebnisdarstellung bei größeren LGS bzw. mit mehr Mantissenstellen der Dezimal-
zahlen muss man geeignete Veränderungen an der Ein- und Ausgabefunktionen vornehmen.
59
Beispiel 2 Ax = b, A regulär, aber det(A) = 10−12 und damit sehr schlechte Kondition
der Systemmatrix
1.441969 1.040807
0.401162
1
∗ −1
A= , b= , Lösung x = A b = ,
1.040807 0.751250 0.289557 −1
1 0
p = (1, 2), P = (Permutationsmatrix),
0 1
! ! !
1441969 1040807 1441969 1040807
1000000 1000000
1 0 1000000 1000000
PA = A = 1040807 751250
= 1040807 1
=
1000000 1000000 14419691
1 0 1441969000000
! !
1 0 1.441969 1.040807
= = LU.
0.7217956835410470 1 0 0.693496 10−12
Eingabe- und Ergebnisfenster
Loesungsvektor x
1.000058 -1.000080
————————————————————————————————————
Ergebnisprotokoll (j/n)?
————————————————————————————————————
Dimension A(n,m): n=2, m=2
A| b
1.441969 1.040807 | 0.401162
1.040807 0.751250 | 0.289557
Loesungsvektor x
1.000058 -1.000080
Permutationsvektor perm
1 2
Zerlegung PA=L\U
1.441969 1.040807
0.721796 0.000000
————————————————————————————————————
60
Fortsetzung
2 C:\d\Neundorf\nwptexte\tech phy\05\dev cpp\projekt4\gauss4c.exe
Kontrollrechnungen (j/n)?
C1 = LU mittels laKopiere
1.441969 1.040807
0.721796 0.000000
C2 = LU mittels laKopiere1
1.441969 1.040807
0.721796 0.000000
C3 = A+C2
2.883938 2.081614
1.762603 0.751250
Normen von b
0.401162 0.289557
||b|| u= 0.401162, ||b|| 1= 0.690719, ||b|| 2= 0.494747
Normen von A
1.441969 1.040807
1.040807 0.751250
||A|| u= 2.482776, ||A|| 1= 2.482776, ||A|| F= 2.193219
Wählt man im Gauß-Algorithmus gauss4c() beim Test auf die Singularität der Matrix A die
Toleranz zu grob, z. B. ε ≥ 10−12 , dann wird wegen u22 = 0.693496 10−12 < ε die Matrix als
singulär eingestuft und das Programm abgebrochen. Ein Weiterrechnen in den Resttableaus
wäre bei zusätzlicher Spaltenvertauschung durchaus möglich. Dabei könnte man dann auch
den Matrixrang ermitteln. Aber die Singularität als solche bleibt natürlich bestehen.
61
Beispiel 3 Ax = b, A regulär
2 −3 1 −2 4 7 14
−4 6 −2 5 −6 −10 14
∗ −1
A= 6 −9 3 −4 10 , b =
17 , Lösung x = A b =
13 ,
2 −4 3 2 −3 5 0
−2 5 −3 2 −1 1 2
0 0 1 0 0
0 0 0 0 1
0 0
p = (3, 5, 4, 2, 1), P = 0 1 0 (Permutationsmatrix),
0 1 0 0 0
1 0 0 0 0
6 −9 3 −4 10 1 0 0 0 0 6 −9 3 −4 10
−2 5 −3 2 −1 − 31 1 0 0 0 0 2 −2 2 7
1 3 3
P A = 2 −4
3 2 −3
= 3
− 12 1 0 0 0
0 1 11
3 − 31
6
= LU.
2 7 2
−4 6 −2 5 −6 − 3 0 0 1 0 0 0 0
3 3
1
2 −3 1 −2 4 3 0 0 − 27 1 0 0 0 0 6
7
Loesungsvektor x
14.000000 14.000000 13.000000 0.000000 2.000000
————————————————————————————————————
...
Permutationsvektor perm
3 5 4 2 1
Zerlegung PA=L\U
6.000000 -9.000000 3.000000 -4.000000 10.000000
-0.333333 2.000000 -2.000000 0.666667 2.333333
0.333333 -0.500000 1.000000 3.666667 -5.166667
-0.666667 0.000000 0.000000 2.333333 0.666667
0.333333 0.000000 0.000000 -0.285714 0.857143
62
Beispiel 4 Ax = b, A singulär, rang(A) = 2
1 −2 2 1
A= −1 2 −1 , b =
0 ,
−2 4 1 3
1
∗
eine der Lösungen ist x = 1 ,
1
2c − 1
die einparametrige Lösungsmenge ist x∗ = c , c reell.
1
Abbruch des Gauß-Algorithmus im zweiten Schritt, bis dahin wird folgender “Zwischenstand“
erreicht.
0 0 1
p = (3, 2, 1), P = 0 1 0 ,
1 0 0
1 0 0 −2 4 1
1
L= ∗ 0 , U = 0 0 − 32 .
2
− 12 ∗ ∗ 0 0 5
2
63
Fortsetzung
2 C:\d\Neundorf\nwptexte\tech phy\05\dev cpp\projekt4\gauss4c.exe
Ergebnisprotokoll (j/n)?
————————————————————————————————————
Achtung! Vorzeitiger Abbruch im Schritt t = 2
Dimension A(n,m): n=3, m=3
A| b
1.000000 -2.000000 2.000000 | 1.000000
-1.000000 2.000000 -1.000000 | 0.000000
-2.000000 4.000000 1.000000 | 3.000000
Permutationsvektor perm
3 2 1
Zerlegung PA=L\U
-2.000000 4.000000 1.000000
0.500000 0.000000 -1.500000
-0.500000 0.000000 2.500000
————————————————————————————————————
Kontrollrechnungen (j/n)?
C1 = LU mittels laKopiere
-2.000000 4.000000 1.000000
0.500000 0.000000 -1.500000
-0.500000 0.000000 2.500000
C2 = LU mittels laKopiere1
-2.000000 4.000000 1.000000
0.500000 0.000000 -1.500000
-0.500000 0.000000 2.500000
C3 = A+C2
-1.000000 2.000000 3.000000
-0.500000 2.000000 -2.500000
-2.500000 4.000000 3.500000
Normen von b
1.000000 0.000000 3.000000
||b|| u= 3.000000, ||b|| 1= 4.000000, ||b|| 2= 3.162278
Normen von A
1.000000 -2.000000 2.000000
-1.000000 2.000000 -1.000000
-2.000000 4.000000 1.000000
||A|| u= 7.000000, ||A|| 1= 8.000000, ||A|| F= 6.000000
64
Beispiel 5 Ax = b, A singulär, rang(A) = 2
2 2 2 5
A= 1 3 0 , b=
4 , keine Lösung x∗ .
2 4 1 7
1 1 1 0 0 0
Die Zerlegung A = LU ist möglich, da erst im letzten Schritt die Komponente u33 = 0 wird.
Ergebnisprotokoll (j/n)?
————————————————————————————————————
Achtung! Vorzeitiger Abbruch im Schritt t = 3
Dimension A(n,m): n=3, m=3
A| b
2.000000 2.000000 2.000000 | 5.000000
1.000000 3.000000 0.000000 | 4.000000
2.000000 4.000000 1.000000 | 7.000000
Permutationsvektor perm
1 2 3
Zerlegung PA=L\U
2.000000 2.000000 2.000000
0.500000 2.000000 -1.000000
1.000000 1.000000 0.000000
65
Wir zeigen einige Modifikationen der bisherigen C-Projekts gauss4c in Bezug auf den Ver-
zicht des Befehls getch() zur Zeicheneingabe ohne Bildschirmecho (bei C automatisch
durch Einbinden der Bibliotheken vorhanden, bei C++ im Header-File conio.h).
Dies betrifft mehrere Funktionen des Projekts. Die Funktion laGlSysEinlesen_ im Quell-
text laInOut_c soll dazu als Musterbeispiel ausgewählt werden.
Bisherige Version:
...
for(i=0;i<n;i++)
for(j=0;j<m;j++)
fscanf(matIn,"%lf",&(*A)[i][j]);
for(i=0;i<n;i++)
fscanf(matIn,"%lf",&(*b)[i][0]);
fclose(matIn);
}
Mit der scanf-Eingabeanweisung wird eine Zeichenkette (Stream, String) für den Namen der
Datei eingelesen. Die Eingabe schließt mit der <Enter>-Taste ( ◭ yp -Taste) ab. Alle Zeichen
stehen zunächst im Eingabepuffer (Tastaturpuffer), um dann in die Variable s übertragen zu
werden. Ist der Name unzulässig, kommt die Fehlerausschrift auf dem Monitor. Diese bleibt
bis zu einer Tastenbetätigung angezeigt.
Nun sollen zwei Dinge berücksichtigt werden.
1. Damit man sicher ist, dass der Eingabepuffer nach der Namenseingabe auf jeden Fall wie-
der leer und damit auch das <Enter>-Zeichen nach der Zeichenketteneingabe gelöscht wird,
ergänzt man die Anweisung (Methode) fflush(stdin) mit stdin aus Header-File stdio.h.
2. Den getch()-Befehl ersetzt man durch die scanf("%c",&ret)-Anweisung mit der char-
Variablen ret.
66
matIn = fopen(s,"r");
if(matIn == NULL)
{
printf("Fehler: Datei nicht gefunden\n");
scanf("%c",&ret);
exit(EXIT_FAILURE);
}
...
}
Eine weitere Veränderung bedeutet den Verzicht auf die Anweisung fflush(stdin) durch
das Ersetzen mit der scanf()-Anweisung. Dabei werden Dateiname (Zeichenkette) und ab-
schließende <Enter>-Taste durch die scanf("%s%c",&s,&ret)-Eingabeanweisung korrekt
verarbeitet und aus dem Eingabepuffer herausgelesen.
matIn = fopen(s,"r");
if(matIn == NULL)
{
printf("Fehler: Datei nicht gefunden\n");
scanf("%c",&ret);
exit(EXIT_FAILURE);
}
fscanf(matIn,"%u %u",&n,&m);
*A = laMatrixNeu_(n,m);
*b = laMatrixNeu_(n,1);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
fscanf(matIn,"%lf",&(*A)[i][j]);
for(i=0;i<n;i++)
fscanf(matIn,"%lf",&(*b)[i][0]);
fclose(matIn);
}
Ausgehend vom C-Projekt in der Version gauss4cb soll es nun als C++-Projekt dargestellt
werden und funktionieren.
Bis auf die Speicherplatzzuweisung für den Zeigertyp typedef double **laMatrix im
Header-File la_.h klappt alles.
Nur die Anweisungen zur Allokation von dynamischen Speicher
if ((A = malloc(sizeof(double*)*n+2*sizeof(int)))==NULL)
...
if ((*(A+i) = malloc(sizeof(double)*m))==NULL)
...
67
C++ kann bei der Allokation von Speicher mit dem Befehl malloc arbeiten. Aber die allo-
kierte Variable muss als Zeigertyp mit einem Datentyp der Objekte stehen. Da man hier gar
nicht über den Zeiger auf das referenzierte Objekt zugreifen will, sondern nur Speicheradres-
sen und damit Adressen von Objekten beliebigen Typs verwaltet, ist ein Zeiger auf void
(generischer Zeiger) zu verwenden. Das ist durch den vorangestellten Typ (void*) einfach
zu machen.
Weitere Veränderungen sind nicht erforderlich.
Um später auf die referenzierten Objekte zugreifen zu können, muss der Zeiger dann aber
zuerst in einen Zeiger auf den entsprechenden Datentyp des Objekts umgewandelt werden
(Dereferenzierung, explizite Konvertierung der Adresse von void* in datentyp*).
if((n<1)||(m<1))
{
printf("Fehler: Dimension(en) unzulaessig\n");
scanf("%c",ret);
exit(EXIT_FAILURE);
}
if(((void*)A = malloc(sizeof(double*)*n+2*sizeof(int)))==NULL)
{
fprintf(stderr,"Zu wenig Speicher\n");
scanf("%c",ret);
exit(EXIT_FAILURE);
}
*((int*)A) = n;
*(((int*)A)+1) = m; // auch *((int*)A+1) = m;
A = (double**)(((int*)A) +2); // auch A = (double**)((int*)A +2);
for(i=0;i<n;i++)
if(((void*)(*(A+i)) = malloc(sizeof(double)*m))==NULL)
{
fprintf(stderr,"Zu wenig Speicher\n");
scanf("%c",ret);
exit(EXIT_FAILURE);
}
return(A);
}
Die elegantere C++-Version zur dynamischen Speicherallokation arbeitet mit dem Anwei-
sungspaar (Operatoren) new und delete zur Reservierung bzw. Freigabe von Speicher.
Man hat jedoch eine besondere Situation bei der Adressierung sowie jeweils Felder von
Objekten. Der Anfangszeiger zeigt zunächst auf eine Objekt (Bereich), in dem die beiden
Matrixdimensionen als integer-Zahlen n und m sowie die n Zeiger auf die Matrixzeilen mit
jeweils m double-Komponenten stehen.
Nachdem die Dimensionen an den ersten beiden “Stellen“ eingetragen wurden, wird der An-
fangszeiger um zwei Positionen weitergerückt. Damit steht er am Beginn des eigentlichen
Adressbereiches der Matrix mit ihren double-Elementen. Nun kann jedem Zeilenzeiger sein
Speicherbereich entsprechend der Matrixzeile “zugewiesen“ werden.
Der Zugriff auf die Matrixdimensionen geht dabei nicht verloren, denn mit dem Anfangszei-
ger kann nach Umtypisierung auf int* auch wieder rückwärts gezählt werden.
68
Version (c2): im Projekt gauss4cpp2
if((n<1)||(m<1))
{
printf("Fehler: Dimension(en) unzulaessig\n");
scanf("%c",ret);
exit(EXIT_FAILURE);
}
*((int*)A) = n;
*(((int*)A)+1) = m; // auch *((int*)A+1) = m;
A = (double**)(((int*)A) +2); // auch A = (double**)((int*)A +2);
for(i=0;i<n;i++)
if((*(A+i) = new double[m])==NULL)
{
fprintf(stderr,"Zu wenig Speicher\n");
scanf("%c",ret);
exit(EXIT_FAILURE);
}
return(A);
}
/*----------------------------------------------------------------------------*/
void laVernichte_(laMatrix A)
{
unsigned i,n;
n = *(((int*)A)-2);
for(i=0;i<n;i++)
delete [](*(A+i));
delete [](char*)(((int*)A) -2); // auch delete [](char*)((int*)A -2);
}
laMatrix
(char*)A = new char[sizeof(double*)*n+2*sizeof(int)]
↓ ւ
A→
int n
*(A+i) = new double[m]
int m ւ
A→
double∗ → 1. Matrixzeile mit m double-Elementen
double∗ → 2. Matrixzeile mit m double-Elementen
......
double∗ → n. Matrixzeile mit m double-Elementen
↑
A = (double**)((int*)A +2);
69
4.5 Aufgabe 5
Ein weiteres Projekt zur Behandlung des Algorithmus der Vektoriteration und inversen Vek-
toriteration soll folgen.
Dabei geht es um die iterative Bestimmung des einzigen betragsgrößten bzw. betragskleinsten
Eigenwerts einer Matrix sowie des zugehörigen Eigenvektors (partielles Eigenwertproblem).
Der zentrale Datentyp ist wieder ein Zeiger auf ein zweidimensionales Feld (Matrix) mit
Komponenten vom Typ double. Vektoren werden in dieser Konvention als Feld mit einer
Spalte interpretiert. Der Datentyp laMatrix zeigt auf eine Struktur, die als Informationen
die Zeilen- und Spaltenmdimension sowie die Matrixelemente zeilenweise enthält.
Die Nummerierung der Zeilen und Spalten beginnt in C/C++ jeweils bei Null.
Die Vektoriteration braucht in jedem Iterationsschritt die Matrix-Vektor-Multiplikation und
wegen der Skalierung die Berechnung der Vektornorm.
Die inverse Vektoriteration hat anstelle der Matrix-Vektor-Multiplikation die Lösung eines
LGS. Dabei wird jedoch der bisher verwendete Resttableau-Gauß-Algorithmus mit Spalten-
pivotisierung und Zeilenvertauschung
gauss4c(int n,int *t,laMatrix *A,laMatrix b,laMatrix *x,laMatrix *perm,int *sing)
aus Abschnitt 4.4 zerlegt in zwei Prozeduren zur LU -Faktorisierung der Matrix A mit Pivo-
strategie (P A = LU, P Permutationsmatrix) sowie zur Lösung von Ax = b mittels gestaf-
felter LGS gemäß
Ax = b, P Ax = LU x = L(U x) = P b, Lz = P b, U x = z.
Die Matrix A ist Eingabematrix und wird überschrieben durch die LU -Zerlegung von P A,
welche vor der Iteration einmal mit dem Aufwand O(n3 ) gemacht wird und dann zurückge-
geben wird. Deshalb wird in der inversen Vektoriteration eine Kopie von A angelegt.
Der Permutationsvektor von p=perm für die Zeilenvertauschungen ist eine einspaltige re-
elle Ergebnismatrix. Die Komponenten von p sind wertemäßig natürliche Zahlen, die zur
Vertauschung im Vektor der rechten Seite gebraucht werden. Falls die Faktorisierung nicht
durchführbar ist, so weist der Ergebnisparameter sing6= 0 darauf hin, wobei mit der Größe
t noch die Stufe (Schritt im Faktorisierungs-Algorithmus) des Abbruchs angezeigt werden
kann.
In jedem Iterationsschritt der inversen Vektoriteration wird dann mit der Faktorisierung für
die jeweils neue rechte Seite eine Vorwärts- und Rückwärtsrechnung mit dem Aufwand O(n2 )
vorgenommen. Damit ist diese Vorgehensweise natürlich effizienter als die Lösung eines LGS
mittels Gauß-Algorithmus in jedem Schritt.
Die inversen Vektoriteration ist nicht durchführbar, wenn A singulär ist. Dann wäre der
betragsgrößte Eigenwert von A−1 “unendlich“.
Für die Iteration braucht man einen nicht verschwindenden Startvektor, der wahlweise ein-
gelesen bzw. als Einsvektor oder erster Einheitsvektor definiert wird.
In allen Fällen wird die Iteration gesteuert durch eine maximale Iterationsanzahl maxiter
und die Toleranz ε=eps für den Test der Übereinstimmung aufeinander folgender Iterier-
ter (Beträge des Eigenwerts). Das Vorzeichen des gesuchten Eigenwerts wird anschließend
noch aus dem Vorzeichenvergleich einer geeigneten Komponente der beiden letzten Iterati-
onsvektoren bestimmt. Der Iterationsvektor wird skaliert und ist selber Näherung für den
Eigenvektor.
70
Zunächst die beiden Funktionen zur LU -Faktorisierung der Matrix A mit Pivostrategie sowie
zur Lösung von Ax = b mittels gestaffelter LGS.
void gauss_LU(int n, int *t, laMatrix *A, laMatrix *perm, int *sing)
{
double max,s,eps,h;
int i,j,k,index;
char ret;
/* Initialisierung */
*sing = 0;
*t = 0;
for(k=0;k<n;k++)
(*perm)[k][0] = k; /* Permutationsvektor */
eps = 1e-15; /* Toleranz fuer Test auf Singularitaet */
/* Hinrechnung */
for(k=0;k<n;k++)
{
/* Pivotsuche */
max = 0;
for(i=k;i<n;i++)
{
s = fabs((*A)[i][k]);
if(s>max)
{
max = s;
index = i;
}
}
/* Test auf Singularitaet */
if(max<eps)
{
*sing = 1;
*t = k+1;
printf("\nMatrix singulaer, Abbruch im Schritt = %d\n",k+1);
scanf("%c",&ret);
exit(EXIT_FAILURE);
}
/* Zeilentausch */
if(index>k)
{
h = (*perm)[k][0]; /* laVertauscheZe_(*perm,k,index); */
(*perm)[k][0] = (*perm)[index][0];
(*perm)[index][0] = h;
laVertauscheZe_(*A,k,index);
}
/* Bestimmung der Spaltenelemente und Zeilenelemente */
max = (*A)[k][k];
for(i=k+1;i<n;i++)
{
s = (*A)[i][k]/max;
(*A)[i][k] = s;
for(j=k+1;j<n;j++)
(*A)[i][j] = (*A)[i][j]-s*(*A)[k][j];
}
}
}
/*--------------------------------------------------------------------------------*/
void gestaffelte_LGS(int n, laMatrix LU, laMatrix b, laMatrix *x, laMatrix perm)
{
double h;
int i,j;
laMatrix bp,z;
71
for(i=1;i<n;i++)
{
h = -bp[i][0];
for(j=0;j<i;j++)
h += LU[i][j]*z[j][0];
z[j][0] = -h;
}
/* Rueckrechnung Ux=z */
for(i=n-1;i>=0;i--)
{
h = -z[i][0];
for(j=n-1;j>i;j--)
h += LU[i][j]*(*x)[j][0];
(*x)[i][0] = -h/LU[i][i];
}
laVernichte_(bp);
laVernichte_(z);
}
Die Vektoriteration und inverse Vektoriteration notieren wir ebenfalls als Funktionen.
Dabei sollen die Bibliotheksfunktionen wie
– Initialisieren und Löschen von Feldern (Matrizen und Vektoren),
– Kopieren von Feldern,
– Normberechnung eines Vektors,
– Multiplikation eines Vektors mit einer skalaren Größe,
– Matrix-Vektor-Multiplikation,
– Skalarprodukt zweier Vektoren,
die in la_.h aufgelistet sind, so weit wie möglich Anwendung finden.
void vektorit(int n, laMatrix A, int maxiter, double eps, laMatrix *x, double *la, int *iter)
{
double la_a,la_n,no;
int i,j;
laMatrix y,yn,yh;
/* Initialisierung */
*iter = 0;
y = laMatrixNeu_(n,1);
yn = laMatrixNeu_(n,1);
laKopiere_(*x,yn);
no = laNorm_(’2’,yn); // sqrt(laSkalProd_(yn,yn));
la_n = 0;
i = 0;
do
{
la_a = la_n;
laSkMult_(1.0/no,yn);
laKopiere_(yn,y);
laMult_(A,y,&yh);
laKopiere_(yh,yn);
i = i+1;
no = laNorm_(’2’,yn);
la_n = no;
} while((fabs(la_a-la_n)>eps)&&(i<maxiter));
for(j=0;j<n;j++)
if (y[j][0]*yn[j][0]!=0) break;
if(y[j][0]*yn[j][0]<0) la_n = -la_n;
laSkMult_(1.0/no,yn);
/* Ergebnisse*/
laKopiere_(yn,*x);
*iter = i;
*la = la_n;
laVernichte_(y);
laVernichte_(yn);
}
/*--------------------------------------------------------------------------------*/
72
void inv_vektorit(int n, laMatrix A, int maxiter, double eps, laMatrix *x, double *la, int *iter)
{
double la_a,la_n,no;
int i,j,t,sing;
char ret;
laMatrix y,yn,LU,perm;
/* Initialisierung */
*iter = 0;
y = laMatrixNeu_(n,1);
yn = laMatrixNeu_(n,1);
LU = laMatrixNeu_(n,n);
perm = laMatrixNeu_(n,1);
laKopiere_(A,LU);
gauss_LU(n,&t,&LU,&perm,&sing);
if(sing!=0)
{
printf("\nMatrix singulaer -> Abbruch");
scanf("%c",&ret);
exit(EXIT_FAILURE);
}
laKopiere_(*x,yn);
no = laNorm_(’2’,yn); // sqrt(laSkalProd_(yn,yn));
la_n = 0;
i = 0;
do
{
la_a = la_n;
laSkMult_(1.0/no,yn);
laKopiere_(yn,y);
gestaffelte_LGS(n,LU,y,&yn,perm);
i = i+1;
no = laNorm_(’2’,yn);
la_n = no;
} while((fabs(la_a-la_n)>eps)&&(i<maxiter));
for(j=0;j<n;j++)
if(y[j][0]*yn[j][0]!=0) break;
if(y[j][0]*yn[j][0]<0) la_n = -la_n;
laSkMult_(1.0/no,yn);
/* Ergebnisse*/
laKopiere_(yn,*x);
*iter = i;
*la = 1.0/la_n;
laVernichte_(y);
laVernichte_(yn);
laVernichte_(LU);
laVernichte_(perm);
}
Die Funktionen für die Ein- und Ausgabe sind problemangepasst und im Modul laInOut_.c
zusammengefasst. Sie werden alle genutzt und noch durch zwei neue zur Matrixeingabe und
-ausgabe ergänzt.
Dort werden auch die Funktionen laMatrixNeu_, laDim_ aufgerufen.
// laInOut_.c
/* Eine Bibliothek fuer Lineare Algebra, Ein/Ausgaben */
/* Definitionen von laGlSysEinlesen_, laGlSysAusgeben_, laMatAusgeben_, laVektAusgeben_, laVektAusgebenI_ */
#include <stdlib.h>
#include <stdio.h>
//#include <conio.h>
#include "la_.h"
...
/*----------------------------------------------------------------------------*/
void laMatEinlesen_(laMatrix *A)
{
73
FILE *matIn;
int i,j,n,m;
char s[80]="Matrix.in"; // Initialisierung
/*----------------------------------------------------------------------------*/
void laMatAusgeben_(laMatrix A)
{
int i,j,n,m;
laDim_(A,&n,&m);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
printf(" %10.6lf ",A[i][j]);
printf("\n");
}
}
Die Beispiele werden als ASCII-Dateien in der Datenreihenfolge n, m, A(1..n, 1..m), b(1..n), ...
bereitgestellt. Der Dateiname für die Daten A, b zum LGS dient auch für die Bereitstellung
der Matrix A selber. Als Testvarianten nehmen wir reguläre und singuläre Matrizen
(reg.: matrix23, matrix3, matrix31, sing.: matrix58).
74
Nun fehlt nur noch der Quelltext (Rahmenprogramm) meinprog_.c mit der main-Funktion.
In ihm befinden sich die notwendigen include-Anweisungen, die genannten vier Funktionen
zum partiellen Eigenwertproblem, Eingaben, Berechnungen und Ausgaben.
// meinprog_.c
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include "la_.h"
void gauss_LU(int n, int *t, laMatrix *A, laMatrix *perm, int *sing)
...
void gestaffelte_LGS(int n, laMatrix LU, laMatrix b, laMatrix *x, laMatrix perm)
...
void vektorit(int n, laMatrix A, int maxiter, double eps, laMatrix *x, double *la, int *iter)
...
void inv_vektorit(int n, laMatrix A, int maxiter, double eps, laMatrix *x, double *la, int *iter)
...
int main()
{
int n,m,i,iter,maxiter;
double eps,la;
laMatrix A,x,x0;
char ein,ret,kont;
75
/* Berechnung */
laKopiere_(x0,x);
vektorit(n,A,maxiter,eps,&x,&la,&iter);
printf("\nVektoriteration\n");
printf("Betragsgroesster Eigenwert la = %19.16e\n",la);
printf("Zugehoeriger skalierter Eigenvektor x\n");
laVektAusgeben_(x);
printf("Iterationsanzahl iter = %i\n",iter);
printf("---------------------------------------------------------------------------------------\n");
laKopiere_(x0,x);
inv_vektorit(n,A,maxiter,eps,&x,&la,&iter);
printf("\nInverse Vektoriteration\n");
printf("Betragskleinster Eigenwert la = %19.16e\n",la);
printf("Zugehoeriger skalierter Eigenvektor x\n");
laVektAusgeben_(x);
printf("Iterationsanzahl iter = %i\n",iter);
printf("---------------------------------------------------------------------------------------\n");
fflush(stdin);
scanf("%c",&ret);
// Speicherplatz freigeben
laVernichte_(A);
laVernichte_(x);
}
76
Beispiel 1 Ax = b, A regulär
1 −2 2
A = −1 1 −1 , EW: 1, 1, 1
−2 −2 1
Ähnlich ist es mit den Startvektoren als Einsvektor oder erster Einheitsvektor.
Beginnt man mit dem Startvektor (−1, 1, 1)T (Eigenvektor), dann konvergieren beide Va-
rianten nach 2 Schritten und es sind la=1.000000000000 und der skalierte Eigenvektor
(−0.577350, 0.577350, 0.577350)T .
77
Beispiel 2 Ax = b, A regulär und symmetrisch, det(A) = 10−12
1.441969 1.040807
A= , EW: 2.193218999999544, 4.5595081932092e − 13
1.040807 0.751250
Eingabe- und Ergebnisfenster
2 C:\d\Neundorf\nwptexte\tech phy\05\dev cpp\projekt5\vektorit.exe
Vektoriteration und inverse Vektoriteration fuer Eigenwerte einer Matrix
VI: y(m+1)=Ay(m), | la(A)| max ∼ ky(m+1)k/ky(m)k
Inv. VI: Ay(m+1)=y(m), | la(A)| min = 1/|la(A∧ − 1 | max
Loesung des LGS mittels LU-Faktorisierung und gestaffelter Systeme
——————————————————————————————————–
Dateiname fuer Daten zur Matrix A : matrix3
Kontrollausgabe A (j/n)? n
Eingabe/Belegung des Startvektors
Definition/Einsvektor/1.Einheitsvektor (d/e/i): d
x0[0] = 1
x0[1] = 2
Eingabe Toleranz eps>0: 1e-15
Eingabe maximale Iterationsanzahl maxiter>0: 10
Vektoriteration
Betragsgroesster Eigenwert la = 2.1932189999995439e+000
Zugehoeriger skalierter Eigenvektor x
0.810843 0.585263
Iterationsanzahl iter = 3
——————————————————————————————————–
Inverse Vektoriteration
Betragskleinster Eigenwert la = 4.5591736506873682e-013
Zugehoeriger skalierter Eigenvektor x
-0.585263 0.810843
Iterationsanzahl iter = 3
——————————————————————————————————–
Ähnlich ist es mit den Startvektoren als Einsvektor oder erster Einheitsvektor.
Auch bei noch kleineren Toleranzen erhält man die gleiche Anzahl von Iterationen.
Mit der double-Genauigkeit können bei der Berechnung des betragskleinsten Eigenwerts nur
ungefähr die ersten 4 Dezimalstellen garantiert werden.
Noch eine Rechnung mit dem Startvektor (100, −100)T und sonst ohne Veränderungen.
...
Vektoriteration
Betragsgroesster Eigenwert la = 2.1932189999995444e+000
Zugehoeriger skalierter Eigenvektor x
0.810843 0.585263
Iterationsanzahl iter = 3
——————————————————————————————————–
Inverse Vektoriteration
Betragskleinster Eigenwert la = 4.5591736506873682e-013
Zugehoeriger skalierter Eigenvektor x
0.585263 -0.810843
Iterationsanzahl iter = 4
——————————————————————————————————–
78
Beispiel 3 Ax = b, A symmetrisch positiv definit, damit regulär
1 5 3 9
5 26 16 47
A= 3 16 14
,
35
9 47 35 95
Die betragsgrößten und betragskleinsten Eigenwerte sind gut separiert von den anderen, so
dass die Iterationen schnell konvergieren.
79
Weitere Berechnungen mit anderen Startvektoren
...
Dateiname fuer Daten zur Matrix A : matrix31
Kontrollausgabe A (j/n)? n
Eingabe/Belegung des Startvektors
Definition/Einsvektor/1.Einheitsvektor (d/e/i): i
Eingabe Toleranz eps>0: 1e-12
Eingabe maximale Iterationsanzahl maxiter>0: 20
Vektoriteration
Betragsgroesster Eigenwert la = 1.3227354373654939e+002
Zugehoeriger skalierter Eigenvektor x
0.081311 0.424912 0.310068 0.846579
Iterationsanzahl iter = 7
——————————————————————————————————–
Inverse Vektoriteration
Betragskleinster Eigenwert la = 3.1058762099130676e-002
Zugehoeriger skalierter Eigenvektor x
0.980914 -0.140818 0.116582 -0.066234
Iterationsanzahl iter = 8
——————————————————————————————————–
80
Beispiel 4 Ax = b, A singulär, rang(A) = 2
2 2 2
A= 1 3 0 , EW: 0, 1, 5
2 4 1
Die inverse Vektoriteration für den betragskleinsten Eigenwert ist nicht durchführbar. Schon
bei der LU -Faktorisierung der Matrix A wird ihre Singularität festgestellt und signalisiert.
Weitere Berechnungen
Startvektor (1, 1, 1)T , ε = 10−12 : la = 5.0000000000002496e+000, iter = 19
Startvektor (1, 1, 1)T , ε = 10−15 : la = 5.0000000000000000e+000, iter = 27
Startvektor (1, 0, 0)T , ε = 10−12 : la = 5.0000000000000009e+000, iter = 3
Startvektor (1, 0, 0)T , ε = 10−15 : la = 5.0000000000000000e+000, iter = 5
Startvektor (1,−2, 3)T , ε = 10−12 : la = 5.0000000000001625e+000, iter = 21
Startvektor (1,−2, 3)T , ε = 10−15 : la = 5.0000000000000009e+000, iter = 25
81
5 Felder in C++ und C
In den Programmen matsum.cpp, matsum.c (Abschnitt 1.4) sowie den gerade genannten
Projekten gauss4c, gauss4ca, gauss4cb, gauss4cpp1, gauss4cpp2, vektorit zum
Gauß-Algorithmus / Vektoriteration und speziell in den zahlreichen Definitionen/Modulen
wie z. B. laMatrixNeu_, laVernichte_, laGlSysEinlesen_, ist der Umgang mit Matrizen
und Vektoren und darauf aufbauenden Objekten schon implementiert worden.
Es soll jedoch noch einmal in übersichtlicher Form die Deklaration, Definition und Verar-
beitung von Feldern unter verschiedenen Aspekten dargestellt werden. Das betrifft nicht nur
die Unterschiede zwischen den Sprachdialekten C++ und C, sondern auch die Verwendung
von statischen und dynamischen Strukturen.
Zunächst noch einmal die Zuordnung von einigen Objekten und Standardbezeichnern zu
Header-Files.
C++
// fuer Objekte wie
#include <iostream.h> // cin, cout,...
#include <conio.h> // getch, printf, scanf, stdin,...
#include <stdlib.h> // EXIT_FAILURE,...
C
//#include <iostream.h> // muss entfallen
#include <math.h> // falls mathematische Standardfunktionen auftreten
//getch, printf, scanf, ... werden automatisch erkannt
82
C++
// a1stat.cpp
// Felder: statisch
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
#include <iostream.h>
#include <conio.h>
//#define nmax 50
int main()
{
const int nmax=50; // bzw. int nmax=50;
double A[nmax][nmax],sum,max;
int n,m,i,j;
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
cout<<"\nZeilensummennorm = "<<max;
getch();
return 0;
}
C
// a1stat.c
// Felder: statisch
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
//#include <iostream.h>
#include <conio.h>
#include <math.h>
//#define nmax 50
int main()
{
const int nmax=50; // bzw. int nmax=50;
double A[nmax][nmax],sum,max;
int n,m,i,j;
char ret;
83
scanf("%i",&n);
} while((n<=0)||(n>50));
do
{
printf("Eingabe Spaltenzahl m (0<m<=50): ");
scanf("%i",&m);
} while((m<=0)||(m>50));
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
printf("A[%i,%i] = ",i,j);
scanf("%lf",&A[i][j]);
}
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
printf("\nZeilensummennorm = %lf",max);
// Tastaturpuffer leeren
fflush(stdin); // stdin in stdio.h bzw. conio.h
scanf("%c",&ret); // anstelle von getch()
return 0;
}
Zeilensummennorm = 16.000000
84
5.2 Dynamische Felder
Dynamische Felder (Array) sind ebenfalls Objekte gleichen Datentyps. Hier muss die Anzahl
der Dimensionen und Elemente in einem Feld erst zur Laufzeit des Programms feststehen
und kann sich daher den aktuellen Gegegebenheiten anpassen. Die dynamische Reservierung
von Feldern ist mit der Verwendung von Zeigern verbunden. Die Anwendung des Indizie-
rungsoperators auf den Feldnamen ist deshalb möglich, weil der Compiler den Feldnamen in
Anweisungen als Zeiger auf das erste Element de Feldes ansieht. Die Indizierung und Zeiger-
berechnung sind ineinander umwandelbar.
Die dynamische Speicherallokation mittels den Zeiger reserviert den gewünschten Speicher-
platz, der dann üblicherweise auch wieder freizugeben ist, bevor der Zeiger nicht mehr ge-
nutzt, ungültig oder umgelenkt wird (Vermeidung von so genannten Speicherlecks).
Speicherallokation Speicherfreigabe
-----------------------------------------------------
C++ new delete
C++/C malloc() free()
Halbdynamische Felder
Zunächst soll speicherplatzsparend dadurch gearbeitet werden, dass bei fester maximaler
Matrixzeile mit spmax Elementen (=Spalten) die Anzahl der Zeilen in Abhängigkeit von der
aktuell eingegebenen Größe n festgelegt wird. Für die Matrixelemente braucht man dann
n*spmax Speicherplatz von gegebenem Elementtyp (hier double). Dazu kommt noch Spei-
cherplatz für etwas Adressverwaltung.
C++
Das ist die kurze und elegante Version unter Verwendung eines Zeigervektors (Vektor von
Zeigern).
Damit liegen die Matrixzeilen im Speicher genau hintereinander und es ist A[i] = *(A+i).
Die Matrixelemente können mittels A[i][j] oder *(*(A+i)+j) aufgerufen werden.
// a1hdyn1.cpp
// Felder: halbdynamisch, Zeigervektor, new-delete
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
#include <iostream.h>
#include <conio.h>
85
//#define spmax 50
int main()
{
const int spmax=50; // maximale Spaltenzahl
typedef double vektor[spmax]; // Typ des Zeilenvektors
int i,j,n,m;
double max,sum;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
cout<<"A["<<i<<","<<j<<"]= ";
cin>>A[i][j];
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
cout<<"\nZeilensummennorm = "<<max;
delete []A;
getch();
return 0;
}
C
Verwendung des Zeigervektors.
Ein Feld von Zeigern (Zeigerfeld) auf den Datentyp T wird als T *ptr[anzahl] deklariert.
Dies ist nicht mit einem Zeiger auf ein Feld vom Typ T gemäß T (*ptr)[anzahl] zu ver-
wechseln.
Da die Deklaration des Zeigerfelds mit einer festen Feldgrenze erfolgen muss, gibt man dort
eine maximale obere Schranke an. Die eingegebene Anzahl der Zeilen sollte dann nicht größer
als diese Schranke sein. Die Dynamik der Allokation von Speicherplatz für die Matrixzeilen
besteht dann darin, dass man nur Platz für die gewünschten Zeilen allokiert. Ist die eingege-
bene Zeilenzahl größer als die Schranke, wird es i. Allg. während der Programmabarbeitung
zur Fehlermeldung und damit zum Abbruch kommen.
Programmfehler
a1stat.exe hat Fehler verursacht und wird geschlossen. Starten Sie das Programm neu.
Ein Fehlerprotokoll wird erstellt.
Damit ist die dynamische Speicherverwaltung bezüglich der Zeilen nicht vollständig machbar.
86
// a1hdyn1.c
// Felder: halbdynamisch mit Kontrolle, Zeigervektor, malloc-free
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
#include <conio.h>
#include <stdlib.h>
#include <math.h>
//#define spmax 50
//#define zemax 50
int main()
{
const int spmax=50; // maximale Spaltenzahl
const int zemax=50; // maximale Zeilenzahl
typedef double vektor[spmax]; // Typ des Zeilenvektors
double *A[zemax]; // Feld (Vektor) von Zeigern
int i,j,n,m;
double max,sum;
char ret;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
printf("A[%i,%i] = ",i,j);
scanf("%lf",&A[i][j]);
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
// sum=sum+fabs(*(*(A+i)+j));
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
printf("\nZeilensummennorm = %lf",max);
fflush(stdin);
for(i=0;i<n;i++) free(*(A+i));
scanf("%c",&ret);
return 0;
}
87
// a1hdyn2.c
// Felder: halbdynamisch mit Kontrolle, Zeiger auf Zeiger, malloc-free
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
#include <conio.h>
#include <stdlib.h>
#include <math.h>
//#define spmax 50
int main()
{
const int spmax=50; // maximale Spaltenzahl
typedef double vektor[spmax]; // Typ des Zeilenvektors
double **A;
int i,j,n,m;
double max,sum;
char ret;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
printf("A[%i,%i] = ",i,j);
scanf("%lf",&A[i][j]);
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
printf("\nZeilensummennorm = %lf",max);
fflush(stdin);
for(i=0;i<n;i++) free(*(A+i));
free(A);
scanf("%c",&ret);
return 0;
}
88
Dynamische Felder
Verwendung des Konzepts Zeiger auf Zeiger für beide Sprachdialekte.
C++
4 Programmversionen
// a1dyn1.cpp
// Felder: dynamisch, Zeiger auf Zeiger, new-delete
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
#include <iostream.h>
#include <conio.h>
int main()
{
typedef double **matrix; // Typ der Matrix
matrix A;
// double **A; // einfache Schreibweise
int i,j,n,m;
double max,sum;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
cout<<"A["<<i<<","<<j<<"]= ";
cin>>A[i][j];
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
cout<<"\nZeilensummennorm = "<<max;
getch();
return 0;
}
/*-------------------------------------------------------------------------------------*/
89
// a1dyn3.cpp
// Felder: dynamisch mit Kontrolle, Zeiger auf Zeiger, new-delete
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
typedef double **matrix; // Typ der Matrix
matrix A;
// double **A; // einfache Schreibweise
int i,j,n,m;
double max,sum;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
cout<<"A["<<i<<","<<j<<"]= ";
cin>>A[i][j];
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
cout<<"\nZeilensummennorm = "<<max;
getch();
return 0;
}
/*-------------------------------------------------------------------------------------*/
90
// a1dyn4.cpp
// Felder: dynamisch mit Kontrolle, Zeiger auf Zeiger, malloc-free
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
//#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
typedef double **matrix; // Typ der Matrix
matrix A;
// double **A; // einfache Schreibweise
int i,j,n,m;
double max,sum;
char ret;
if(((void*)A = malloc(n*sizeof(double*)))==NULL)
{
printf("Zu wenig Speicher\n");
scanf("%c",&ret);
exit(EXIT_FAILURE);
}
for(i=0;i<n;i++)
if(((void*)(*(A+i)) = malloc(m*sizeof(double)))==NULL)
{
printf("Zu wenig Speicher\n");
scanf("%c",&ret);
exit(EXIT_FAILURE);
}
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
printf("A[%i,%i] = ",i,j);
scanf("%lf",&A[i][j]);
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
printf("\nZeilensummennorm = %lf",max);
fflush(stdin);
for(i=0;i<n;i++) free(*(A+i));
free(A);
scanf("%c",&ret);
return 0;
}
Die Analogie zur Version a1dyn4.cpp ohne den generischen Zeiger void* gibt es auch in C.
91
C
// a1dyn4.c
// Felder: dynamisch mit Kontrolle, Zeiger auf Zeiger, malloc-free
// Berechnen der Zeilensummennorm einer (n,m)-Matrix
#include <conio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
typedef double **matrix; // Typ der Matrix
matrix A;
// double **A; // einfache Schreibweise
int i,j,n,m;
double max,sum;
char ret;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
printf("A[%i,%i] = ",i,j);
scanf("%lf",&A[i][j]);
}
max=0.0;
for(i=0;i<n;i++)
{
sum=0.0;
for(j=0;j<m;j++)
sum=sum+fabs(A[i][j]); // sum+=fabs(A[i][j]);
max=(sum>max?sum:max); // if (sum>max) max=sum;
}
printf("\nZeilensummennorm = %lf",max);
fflush(stdin);
for(i=0;i<n;i++) free(*(A+i));
free(A);
scanf("%c",&ret);
return 0;
}
92
Anhang
Programmbeispiele in C++ und C
Zunächst noch einmal die Zuordnung von einigen Objekten und Standardbezeichnern zu
Header-Files.
C++
// fuer Objekte wie
#include <iostream.h> // cin, cout,...
#include <conio.h> // getch, printf, scanf, stdin,...
#include <stdlib.h> // EXIT_FAILURE,...
C
//#include <iostream.h> // muss entfallen
#include <math.h> // falls mathematische Standardfunktionen auftreten
//getch, printf, scanf, ... werden automatisch erkannt
In den C++-Programmen verwenden wir nicht die Objekte cin, cout, sondern wie in C
die Befehle scanf, printf.
Neben der zum Teil abweichenden Einbindung von Header-Files in den beiden Sprachdialek-
ten, können noch andere kleine Unterschiede in der Syntax auftreten. So verlangt z. B. C++
bei der Definition von Konstanten zusätzlich die Typangabe. Darüber hinaus gibt es i. Allg.
Übereinstimmung zwischen den Versionen.
(1) Quadratwurzel
// wurzel1.c
// Quadratwurzelberechnung sqrt(x)
#include <stdio.h>
#include <math.h>
int main()
{
int i,n;
double xi,x;
n = 19;
printf("Quadratwurzelberechnung\n");
printf("--------------------------------------------------------------\n");
printf(" i sqrt(i) xi=i,sqrt(xi) x double,sqrt(x)\n");
for(i=1,x=1.0;i<=n;i++,x=x+1.0)
{
xi = i;
printf("%2i %19.16lf %19.16lf %19.16lf\n",i,sqrt(i),sqrt(xi),sqrt(x));
}
getch();
return 0;
}
-------------------------------------------------------------------------------------
// wurzel1.cpp
// Quadratwurzelberechnung sqrt(x)
#include <conio.h>
#include <math.h>
93
int main()
{
int i,n;
double xi,x;
n = 19;
printf("Quadratwurzelberechnung\n");
printf("--------------------------------------------------------------\n");
printf(" i sqrt(i) xi=i,sqrt(xi) x double,sqrt(x)\n");
for(i=1,x=1.0;i<=n;i++,x=x+1.0)
{
xi = i;
printf("%2i %19.16lf %19.16lf %19.16lf\n",i,sqrt(i),sqrt(xi),sqrt(x));
}
getch();
return 0;
}
(2) Kreiszahl π
// pi1.c
// Kreiszahl Pi durch Integration des Einheitskreises
#include <conio.h>
#include <math.h>
int main()
{
int i,n;
double x,delta_x,pi,Rl,y;
const double Pi = 3.1415926535897932; // exakt als Vergleichswert
n = 1000;
delta_x = 1.0/n;
94
----------------------------------------------------------------------------------------------
// pi1.cpp, Kreiszahl Pi durch 1.Quadranten des Einheitskreises
#include <conio.h>
#include <stdlib.h> // kann entfallen
#include <math.h> // kann entfallen
//#define M_PI 3.14159265358979323846
int main()
{
int i,n;
double x,delta_x,pi,Rl,y;
const double Pi = 3.14159265358979323846; // exakt als Vergleichswert
...
}
// pi2.c
// Kreiszahl Pi nach Archimedes mittels Umfang von im Kreis einbeschriebenen regelmaessigen Vielecken
#include <conio.h>
#include <math.h>
int main()
{
int j;
double s1,s2,p1,p2,ix;
const double Pi = 3.1415926535897932; // exakt als Vergleichswert
#include <conio.h>
#include <math.h>
//#define M_PI 3.14159265358979323846
int main()
{
int j;
double s1,s2,p1,p2,ix;
const double Pi = 3.14159265358979323846; // exakt als Vergleichswert
...
}
95
2 C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc\pi2.exe
Pi nach Archimedes
j s1 Pi1 s2 Pi2
————————————————————————————————————-
1 1.000000000000000 3.000000000000000 1.000000000000000 3.000000000000000
2 0.517638090205042 3.105828541230250 0.517638090205041 3.105828541230249
3 0.261052384440103 3.132628613281237 0.261052384440103 3.132628613281238
4 0.130806258460286 3.139350203046872 0.130806258460286 3.139350203046867
5 0.065438165643553 3.141031950890530 0.065438165643552 3.141031950890509
6 0.032723463252972 3.141452472285344 0.032723463252974 3.141452472285462
7 0.016362279207873 3.141557607911622 0.016362279207874 3.141557607911858
8 0.008181208052471 3.141583892148936 0.008181208052470 3.141583892148318
9 0.004090612582340 3.141590463236762 0.004090612582328 3.141590463228050
10 0.002045307360705 3.141592106043048 0.002045307360677 3.141592105999271
11 0.001022653813994 3.141592516588155 0.001022653814027 3.141592516692156
12 0.000511326923607 3.141592618640789 0.000511326923725 3.141592619365383
13 0.000255663463975 3.141592645321216 0.000255663463951 3.141592645033690
14 0.000127831731987 3.141592645321216 0.000127831732237 3.141592651450766
15 0.000063915865994 3.141592645321216 0.000063915866151 3.141592653055036
16 0.000031957932997 3.141592645321216 0.000031957933080 3.141592653456103
17 0.000015978971709 3.141593669849427 0.000015978966540 3.141592653556370
18 0.000007989482381 3.141592303811738 0.000007989483270 3.141592653581437
19 0.000003994762034 3.141608696224804 0.000003994741635 3.141592653587703
20 0.000001997367121 3.141586839655041 0.000001997370818 3.141592653589270
21 0.000000998711352 3.141674265021758 0.000000998685409 3.141592653589662
22 0.000000499355676 3.141674265021758 0.000000499342704 3.141592653589759
23 0.000000249788979 3.143072740170040 0.000000249671352 3.141592653589784
24 0.000000125559416 3.159806164941135 0.000000124835676 3.141592653589791
25 0.000000063220273 3.181980515339464 0.000000062417838 3.141592653589792
26 0.000000033320009 3.354101966249685 0.000000031208919 3.141592653589793
27 0.000000021073424 4.242640687119286 0.000000015604460 3.141592653589793
28 0.000000014901161 6.000000000000000 0.000000007802230 3.141592653589793
29 0.000000000000000 0.000000000000000 0.000000003901115 3.141592653589793
30 0.000000000000000 0.000000000000000 0.000000001950557 3.141592653589793
31 0.000000000000000 0.000000000000000 0.000000000975279 3.141592653589793
32 0.000000000000000 0.000000000000000 0.000000000487639 3.141592653589793
33 0.000000000000000 0.000000000000000 0.000000000243820 3.141592653589793
34 0.000000000000000 0.000000000000000 0.000000000121910 3.141592653589793
35 0.000000000000000 0.000000000000000 0.000000000060955 3.141592653589793
36 0.000000000000000 0.000000000000000 0.000000000030477 3.141592653589793
37 0.000000000000000 0.000000000000000 0.000000000015239 3.141592653589793
38 0.000000000000000 0.000000000000000 0.000000000007619 3.141592653589793
39 0.000000000000000 0.000000000000000 0.000000000003810 3.141592653589793
40 0.000000000000000 0.000000000000000 0.000000000001905 3.141592653589793
41 0.000000000000000 0.000000000000000 0.000000000000952 3.141592653589793
96
(3) Primzahlen
// prim1.c
// Die ersten n Primzahlen
#include <math.h>
int main()
{
const n = 100; // auch int const n = 100;
int i,j,k,prim;
double is;
i = 1;
k = 0;
printf("Die ersten n Primzahlen\n");
do
{
i++;
is = sqrt(i);
prim = 1;
for(j=2;j<=is;j++)
if((i%j)==0) // Modulo = Rest der Division
{
prim = 0;
break;
}
if(prim!=0)
{
k++;
printf("%3i.te Primzahl = %i\n",k,i);
}
} while(k<n);
getch();
}
-----------------------------------------------------------------------------------------
// prim1.cpp
// Die ersten n Primzahlen
#include <conio.h>
int main()
{
int const n = 100; // auch const int n = 100;
int i,j,k,prim;
double is;
...
}
97
// prim2.c
// Die ersten n Primzahlen als Vektor
#include <math.h>
int main()
{
const n = 100;
int i,j,k,prim,vprim[n];
i = 2;
k = 0;
printf("Die ersten n Primzahlen als Vektor\n");
vprim[0] = 2;
printf("%3i. Primzahl = %i\n",k+1,i);
do
{
i++;
prim = 1;
for(j=0;j<k;j++)
if((i%vprim[j])==0)
{
prim = 0;
break;
}
if(prim!=0)
{
++k;
vprim[k] = i;
printf("%3i. Primzahl = %i\n",k+1,i);
}
} while(k<n-1);
getch();
printf("\nAusgabe des Vektors der Primzahlen\n");
for(k=0;k<n;k++) printf("vprim[%3i] = %i\n",k,vprim[k]);
getch();
}
---------------------------------------------------------------------------
// prim3.c
// Die ersten n Primzahlen als Vektor
#include <math.h>
int main()
{
const n = 10;
int i,j,k,prim,is,vprim[n+1];
i = vprim[0] = 1;
k = 2;
vprim[1] = 2;
vprim[2] = 3;
printf("Die ersten n Primzahlen als Vektor\n");
printf("%3i. Primzahl = %i\n",1,vprim[1]);
do
{
i = i+2;
is = (int)sqrt(i); // Typumwandlung
prim = 1;
j = 2;
while((vprim[j]<=is)&&(prim!=0))
{
prim = i%vprim[j];
j++;
}
if(prim!=0) printf("%3i. Primzahl = %i\n",k++,vprim[k]=i);
} while(k<=n);
getch();
printf("\nAusgabe des Vektors der Primzahlen\n");
for(k=1;k<=n;k++) printf("vprim[%3i] = %i\n",k,vprim[k]);
getch();
}
98
2 C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc\prim3.exe
Die ersten n Primzahlen
1. Primzahl = 2
2. Primzahl = 3
3. Primzahl = 5
...
10. Primzahl = 29
// prim4.c
// Alle Primzahlen <= n, Sieb des Eratosthenes
#include <math.h>
int main()
{
const nmax = 1000;
int i,k,n,ns,vprim[nmax+1];
vprim[0] = 0;
vprim[1] = 1;
for(i=2;i<=n;i++) vprim[i]=i;
ns = (int)sqrt(n);
for(i=2;i<=ns;i++)
if(vprim[i]!=0)
{
k = 2*i;
while(k<=n)
{
vprim[k] = 0;
k = k+i;
}
}
printf("\nPrimzahlen <= %i\n",n);
for(i=2;i<=n;i++)
{
if(vprim[i]!=0) printf(" %i",i);
if(i%30==0) getch();
}
getch();
}
99
// prim5.c
// Primzahltest mittels ganzzahliger Division
#include <math.h>
int main()
{
int n,ns,teiler,kleinster_teiler,prim;
prim = 1;
teiler = 2;
kleinster_teiler = 2;
ns = (int)sqrt(n);
while(teiler<=ns)
{
if((n%teiler==0)&&(n>3))
{
prim = 0;
kleinster_teiler = teiler;
break;
}
teiler++;
}
if(prim)
printf("\n%i ist Primzahl",n);
else
{
printf("\n%i ist keine Primzahl",n);
printf("\nKleinster Teiler = %i",kleinster_teiler);
}
getch();
}
----------------------------------------------------------------------------------------------
// prim5.cpp
// Primzahltest mittels ganzzahliger Division
#include <conio.h>
int main()
{
int n,ns,teiler,kleinster_teiler,prim;
...
}
100
(4) Summenberechnungen
// summe1_gauss.c
// Summe 1+2+...+n=n(n+1)/2 Gauss-Formel
main()
{
int i,n,s,g;
n = 100;
s = 0;
for(i=1;i<=n;i=i+1)
s = s+i; // s+=i;
g = n*(n+1)/2; // Ergebnis ist ganzzahlig
printf("Gauss-Formel 1+2+...+n=n(n+1)/2\n");
printf("n=%i\n",n);
printf("g=n(n+1)/2 = %i\n",g);
printf("s=0+1+2+...+n = %i\n",s);
getch();
}
----------------------------------------------------------------------
// summe1_gauss.cpp
// Summe 1+2+...+n=n(n+1)/2 Gauss-Formel
#include <conio.h>
main()
{
int i,n,s,g;
...
}
// summe2_geom.c
// Summe 2=1+1/2+1/2^2+1/2^3+1/2^4+.... geometrische Reihe
int main()
{
int i,n;
double s,a;
n = 16;
a = 1.0;
s = 1.0;
for(i=1;i<=n;i=i+1)
{
a = a/2.0;
s = s+a;
}
printf("Geometrische Reihe 2=1+1/2+1/2^2+1/2^3+1/2^4+....\n");
printf("Partialsumme s(n)=s(%i)=%14.12lf\n",n,s);
getch();
return 0;
}
101
// summe3_sin.c
// Summe sin(x)=x-x^3/3!+x^5/5!-x^7/7!+x^9/9!-... Potenzreihe
#include <math.h>
int main()
{
int i,n;
double x,x2,s,a;
x = 1.5;
x2 = x*x;
n = 15;
a = x;
s = x;
for(i=2;i<=n;i=i+2)
{
a = -a*x2/(i*(i+1));
s = s+a;
}
printf("Potenzreihe sin(x)=x-x^3/3!+x^5/5!-x^7/7!+x^9/9!-...\n");
printf("sin(%lf)=%17.15lf\n",x,sin(x));
printf("Partialsumme s(n)=s(%i)=%17.15lf\n",n,s);
getch();
return 0;
}
// summe4_sin.c
// Summe sin(x)=x-x^3/3!+x^5/5!-x^7/7!+x^9/9!-... Potenzreihe
// nach Transformation von x auf das Intervall [-Pi,Pi]
#include <math.h>
int main()
{
const double Pi = 3.1415926535897932;
int i,n,Q,h,vz;
double xe,x,x2,sinx,xt,s,a;
printf("Potenzreihe sin(x)=x-x^3/3!+x^5/5!-x^7/7!+x^9/9!-...\n");
printf("nach Transformation von x auf das Intervall [-Pi,Pi]\n\n");
n = 100;
vz = 1;
printf("x = ");
scanf("%lf",&xe);
102
printf("\nErgebnisse\n");
printf("x =%19.15lf\n",xe);
printf("xt=%19.15lf\n\n",xt);
printf("sin(%19.15lf)=%19.15lf\n",xe,sin(xe));
printf("Partialsumme s(n)=s(%i)=%19.15lf\n",n,sinx);
getch();
return 0;
}
x = 0.5
Ergebnisse
x = 0.500000000000000
xt = 0.500000000000000
Ergebnisse
x = 2.200000000000000
xt = 0.941592653589793
Ergebnisse
x = 3.500000000000000
xt = -2.783185307179586
Ergebnisse
x = 6.000000000000000
xt = -2.858407346410207
Ergebnisse
x =100.000000000000000
xt = -2.610627738716413
103
// summe5_sin.c
// Summe sin(x)=x-x^3/3!+x^5/5!-x^7/7!+x^9/9!-... Potenzreihe
// nach Transformation von x auf das Intervall [0,Pi/2]
#include <math.h>
int main()
{
const double Pi = 3.1415926535897932;
int i,n,vz,ix,vorz;
double xe,x,x2,sinx,s,a;
printf("Potenzreihe sin(x)=x-x^3/3!+x^5/5!-x^7/7!+x^9/9!-...\n");
printf("nach Transformation von x auf das Intervall [0,Pi/2]\n\n");
n = 100;
vz = 1;
vorz = 1;
printf("x = ");
scanf("%lf",&xe);
printf("\nErgebnisse\n");
printf("x =%19.15lf\n",xe);
printf("xt=%19.15lf\n\n",x);
printf("sin(%19.15lf)=%19.15lf\n",xe,sin(xe));
printf("Partialsumme s(n)=s(%i)=%19.15lf\n",n,sinx);
getch();
return 0;
}
-----------------------------------------------------------------------------------
// summe5_sin.cpp
// Summe sin(x)=x-x^3/3!+x^5/5!-x^7/7!+x^9/9!-... Potenzreihe
// nach Transformation von x auf das Intervall [0,Pi/2]
#include <conio.h>
int main()
{
const double Pi = 3.1415926535897932;
int i,n,vz,ix,vorz;
double xe,x,x2,sinx,s,a;
...
}
104
2 C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc\summe5 sin.exe
Potenzreihe sin(x)=x-x∧ 3/3!+x∧ 5/5!-x∧ 7/7!+x∧ 9/9!-...
nach Transformation von x auf das Intervall [-Pi,Pi]
x = 0.5
Ergebnisse
x = 0.500000000000000
xt = 0.500000000000000
Ergebnisse
x = 2.200000000000000
xt = 0.941592653589793
Ergebnisse
x = 3.500000000000000
xt = 0.358407346410207
Ergebnisse
x = 6.000000000000000
xt = 0.283185307179586
Ergebnisse
x =100.000000000000000
xt = 0.503964914873373
Ergebnisse
x = -99.000000000000000
xt = 1.530964914873373
105
(5) Integration, Quadraturformeln
// integrate1.c
// Zusammengesetzte Newton-Cotes-Formel: Trapezregel, Simpson-Regel
#include <math.h>
// Integrand
double f(double x)
{
return exp(x);
}
h = (b-a)/n;
s1 = 0.5*(f(a)+f(b));
for(i=1;i<=n-1;i++) s1 = s1+f(a+i*h);
return s1*h;
}
h = (b-a)/(2*n);
s1 = f(a)+f(b);
i = 2;
while(i<=(2*n-2))
{
s1 = s1+2*f(a+i*h);
i = i+2;
}
i = 1;
while(i<=(2*n-1))
{
s1 = s1+4*f(a+i*h);
i = i+2;
}
return s1*h/3;
}
int main()
{
int n;
double a,b,T1,T2,S;
T1 = trapez_z(a,b,n);
printf("T_z(n) = %12.9lf\n",T1);
T2 = trapez_z(a,b,2*n);
printf("T_z(2n) = %12.9lf\n",T2);
S = simpson_z(a,b,n);
printf("S_z(n) = %12.9lf\n",S);
106
2 C:\d\Neundorf\nwptexte\tech phy\05\cpp gpp gcc\integrate1.exe
Bestimmtes Integral Int(f(x),x=a..b)
Numerische Integration mittels Newton-Cotes-Quadraturformeln
Zusammengesetzte Trapezregel, Simpson-Regel
Int(exp(x),x=0..1) = exp(1)-1 = 1.718281828459045
Anzahl der Teilintervalle n = 10
T z(n) = 1.719713491
T z(2n) = 1.718639789
S z (n) = 1.718281888
Kontrolle S z(n)=(4T z(2n)-T z(n))/3
(4T z(2n)-T z(n))/3 = 1.718281888
// integrate2.c
// Duale adaptive Trapezregel mit Grob- und Feinrechnung
#include <math.h>
// globale Groessen
int anz;
double hmin;
// andere Integranden
// return sin(x);
// return sqrt(sqrt(sqrt(fabs(x))));
}
// hmin,anz,f global
{
double I1,I2,I12,xm,fm;
xm = (x1+x2)*0.5;
fm = f(xm);
anz++;
h = 0.5*h; if(h<hmin) hmin = h;
I1 = 0.5*h*(f1+fm);
I2 = 0.5*h*(fm+f2);
I12 = I1+I2;
if(fabs(I-I12)<eps*(fabs(I)+eps)) (*s) = (*s)+I12;
else
{
Integral(x1,xm,f1,fm,I1,h,eps,s); // Integral(x1,xm,f1,fm,I1,h,eps,&*s);
Integral(xm,x2,fm,f2,I2,h,eps,s);
}
}
int main()
{
double a,b,eps,fa,fb,h,s,I;
107
// Vorbereitung des rekursiven Prozeduraufrufes
hmin = b-a;
fa = f(a);
fb = f(b);
anz = 2;
h = b-a;
s = 0.0;
I = 0.5*h*(fa+fb);
Integral(a,b,fa,fb,I,h,eps,&s);
printf("Integralwert s = %15.12lf\n",s);
printf("Anzahl der FW-Auswertungen anz = %i\n",anz);
printf("Minimaler Knotenabstand hmin = %11.9lf\n",hmin);
getch();
}
Beispiel
Z1
dx
= 200 arctan(100) = 312.159 332 021 646 276 20.
10−4+ x2
−1
108
// integrate3.c
// Zusammengesetzte Trapezregel mit Grob- und Feinrechnung sowie Intervallhalbierung
#include <math.h>
// Prototypen
double integrate1(double(*funktion)(double),double,double,double);
double integrate2(double(*funktion)(double),double,double,double);
double myf(double);
int main()
{
double a,b,eps,I;
a = 0.0;
b = 1.0;
eps = 1e-6;
109
xi = a+i*dx;
Ineu = Ineu+(*funktion)(xi); // rekursive Berechnung
// damit weniger FW-Berechnungen
}
diff = fabs(Ineu*dx-Ialt*2.0*dx);
}
while(diff>eps);
return Ineu*dx;
}
/*---------------------------------------------------------------------------*/
double myf(double x)
{
return x*x; // Normalparabel
}
Beispiel
Zb
1 3
x2 dx = (b − a3 ), a = 0, b = 1, ε = 10−6 .
3
a
// integrate4.c
// Vergleich verschiedener Integrationsmethoden fuer Integrand = Polynom
// - Zusammengesetzte Trapezregel
// - Monte-Carlo-Methode
// - exaktes Verfahren mit Stammfunktion
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define maxgrad 4 // maximaler Grad des Polynoms
// Prototypen
double direkt(double,double);
double Trapezregel(double(*funktion)(double),double,double,double);
double Monte_Carlo(double(*funktion)(double),double,double,double);
double polynom(double);
/* Globale Variablen */
double ai[maxgrad+1]; // Koeffizienten des Polynoms
int grad; // Grad des Polynoms
/*---------------------------------------------------------------------------*/
int main()
{
double a,b,eps,Id,It,Im;
int i,NN,td,tt,tm;
time_t ta,te;
110
scanf("%i",&grad);
} while ((grad<0)||(grad>maxgrad));
printf("Polynomkoeffizienten a[i] von pn(x)=a[0]+a[1]x+...+a[n]x^n\n");
for(i=0;i<=grad;i++)
{
printf("a[%i] = ",i);
scanf("%lf",&ai[i]);
}
for(i=grad+1;i<=maxgrad;i++) ai[i] = 0.0;
ta = time(NULL);
for(i=1;i<=NN;i++) Id = direkt(a,b);
te = time(NULL);
td = te-ta;
ta = time(NULL);
for(i=1;i<=NN;i++) It = Trapezregel(polynom,a,b,eps);
te = time(NULL);
tt = te-ta;
ta = time(NULL);
for(i=1;i<=NN;i++) Im = Monte_Carlo(polynom,a,b,eps);
te = time(NULL);
tm = te-ta;
printf("Integrationsmethoden\n");
printf("Direkt Id = %12.9lf Zeit in sec = %ld\n",Id,td);
printf("Tapezregel It = %12.9lf Zeit in sec = %ld\n",It,tt);
printf("Monte-Carlo Im = %12.9lf Zeit in sec = %ld\n",Im,tm);
getch();
}
/*---------------------------------------------------------------------------*/
double direkt(double a,double b)
{
int i;
double I;
I = 0.0;
for(i=0;i<=grad;i++) I = I+ai[i]/(i+1)*(pow(b,i+1)-pow(a,i+1));
return I;
}
/*---------------------------------------------------------------------------*/
double Trapezregel(double (*funktion)(double x),double a,double b,double eps)
{
int i,N;
double Ialt,Ineu,xi,dx;
111
int i,anzp;
double fmittel,fmittelalt,xr,r;
fmittel = 0.0;
for(i=1;i<=N;i++)
{
//xr = drand48();
xr = a+(b-a)*rand()/r;
fmittel = fmittel+(*funktion)(xr);
}
anzp = N;
do
{
fmittelalt = fmittel;
for(i=1;i<=N;i++)
{
//xr = drand48();
xr = a+(b-a)*rand()/r;
fmittel = fmittel+(*funktion)(xr);
}
anzp = anzp+N;
// printf("I: %lf AP: %i\n", fmittel/anzp*(b-a), anzp);
} while(fabs(fmittel/anzp-fmittelalt/(anzp-N))*(b-a)>eps);
return fmittel/anzp*(b-a);
}
/*---------------------------------------------------------------------------*/
double polynom(double x)
{
int i;
double p;
p = 0.0;
for(i=0;i<=grad;i++) p = p+ai[i]*pow(x,i);
return p;
}
----------------------------------------------------------------------------------------
// integrate4.cpp
// Vergleich verschiedener Integrationsmethoden fuer Integrand = Polynom
// - Zusammengesetzte Trapezregel
// - Monte-Carlo-Methode
// - exaktes Verfahren mit Stammfunktion
#include <stdlib.h>
#include <conio.h>
#include <math.h>
#include <time.h>
#define maxgrad 4 // maximaler Grad des Polynoms
// Prototypen
double direkt(double,double);
double Trapezregel(double(*funktion)(double),double,double,double);
double Monte_Carlo(double(*funktion)(double),double,double,double);
double polynom(double);
/* Globale Variablen */
double ai[maxgrad+1]; // Koeffizienten des Polynoms
int grad; // Grad des Polynoms
/*---------------------------------------------------------------------------*/
int main()
{
double a,b,eps,Id,It,Im;
int i,NN,td,tt,tm;
time_t ta,te;
...
}
...
112
Beispiel
Zb Zb
pn (x) dx = (a0 + a1 x + ... + an xn ) dx
a a
h 1 1 ib
= a0 x + a1 x2 + ... + an xn+1
2 n+1 a
n
X 1
= ai (bi+1 − ai+1 ).
i=0
i + 1
Das Verfahren von Monte-Carlo ist im Vergleich mit Abstand am langsamsten und
sehr ungenau.
113