C Programmierung - Vorlesung 15 Matrixmultiplikation in C

Transcrição

C Programmierung - Vorlesung 15 Matrixmultiplikation in C
Matrixmultiplikation in C
Das Produkt zweier Matrizen ist nur definiert, wenn die Zahl
der Spalten des ersten Faktors mit der Zahl der Zeilen des
zweiten Faktors übereinstimmt,
für
C Programmierung - Vorlesung 15
Hochschule Regensburg
11.05.2012
Universitätsstraße 31, 93053 Regensburg
Prof. Dr. Jan Dünnweber

a0,0
 ...

A :=  ai ,0
 ...
ak,0
...
...
...
...
...
a0,j
...
ai ,j
...
ak,j
...
...
...
...
...

a0,l
.... 

ai ,l 
.... 
ak,l

b0,0
 ...

B :=  bp,0
 ...
bm,0
...
...
...
...
...
b0,q
...
bp,q
...
bm,q
...
...
...
...
...

b0,n
.... 

bp,n 
.... 
bm,n
und
also genau dann, wenn l = m
Prof. Dr. Jan Dünnweber, Folie 2 von 14
Berechnung der Elemente der Produktmatrix
Programmierung 1
Darstellung der Matrizen in C
Wir verwenden wieder unseren Listentyp
Das Produkt einer k × l Matrix A und einer l × n Matrix B ist
somit eine k × n Matrix

C := 
c0,0
...
ck,0
...
ci ,j
....

c0,k
... 
ak,n
typedef struct {
int width; int height;
list *elements;
matrix;
}
deren Elemente definiert sind als
ci ,j :=
l
P
ai ,k · bk,j
k=0
d. h. es werden zusammengehörige Spalten- bzw.
Zeilenprodukte gebildet und aufsummiert
Es ist also z. B.
5
−12
18
4
=
2
−5
3
5
−1
3

3
· 0
1
matrix.c

2
4 
−2
matrix *createMatrix(int x, int y) {
register i, j;
matrix *newMatrix = (matrix *)malloc(sizeof(matrix));
newMatrix−>width = x, newMatrix−>height = y;
newMatrix−>elements = createList();
for (i = 0; i < x; ++i)
for (j = 0; j < y; ++j) {
double *value = (double *)malloc(sizeof(double));
*value = 0.0L;
insertElement(newMatrix−>elements, value);
}
return newMatrix;
}
intern sind die Element linear organisiert
Prof. Dr. Jan Dünnweber, Folie 3 von 14
Programmierung 1
Prof. Dr. Jan Dünnweber, Folie 4 von 14
Programmierung 1
Zugriff auf einzelne Matrixelemente
Matrizen strukturiert ausgeben
Zugriff mittels Indizes (Koordinaten) via get & set
Zur Kontrolle unserer Berechnungen verwenden wir folgende
printMatrix-Funktion
getValue
printMatrix
double getValue(matrix *source, int x, int y) {
node *position = getNode( source−>elements,
y * source−>width + x );
return *(double *)position−>element;
}
void printMatrix(matrix *m) {
register z, s;
for (z = 0; z < m−>width; ++z) {
for (s = 0; s < m−>height; ++s)
printf("%.1d ", (float)getValue(m, z, s));
printf("\n");
}
}
Beim Speichern neuer Werte ist auf korrektes
Speichermanagement (malloc & free) zu achten
setValue
void setValue(matrix *target, int x, int y, double value)
double *vp = malloc(sizeof(double));
*vp = value;
node *position = getNode( target−>elements,
y * target−>width + x );
position−>element = vp;
}
Prof. Dr. Jan Dünnweber, Folie 5 von 14
{
Programmierung 1
Berechnung des Produkts in C
Die Formel von Folie 3 lässt sich direkt in den Code
übernehmen:
Auslesen der Werte mittels getValue (→ Folie 5)
Beachte: Die Quellmatrix muss durch den Parameter m
wieder explizit angegeben werden!
Prof. Dr. Jan Dünnweber, Folie 6 von 14
Programmierung 1
Anwendung: Computergrafik - Berechnung einer Drehung
Rotationsmatrix
Die Rotationsmatrix für eine Drehung um den Ursprung ist im
euklidischen Raum definiert als:
Die mult-Funktion
matrix *mult(matrix *m1, matrix *m2) {
register i, j;
matrix *product = createMatrix(m1−>width, m2−>height);
for (i = 0; i < product−>width; ++i)
for (j = 0; j < product−>height; ++j) {
register k; double sum = 0.0;
for (k = 0; k < m1−>height; ++k)
sum = sum + getValue(m1, i, k) * getValue(m2, k, j);
setValue(product, i, j, sum);
}
return product;
}
Alternative: Algorithmus von V. Strassen
(’69, → Wikipedia)
Prof. Dr. Jan Dünnweber, Folie 7 von 14
Die Ausgabe der einzelnen Elemente erfolgt auf eine
Nachkommestelle genau
Programmierung 1
Rα :=
cosα −sinα
sinα cosα
Für eine Drehung um einen beliebigen Punkt ist vorher und
nachher je eine Translation durchzuführen
Wir verwenden diese Matrix nun testweise,
um ein Rechteck zu rotieren
Prof. Dr. Jan Dünnweber, Folie 8 von 14
Programmierung 1
Darstellung der Grafik: Die XWindow-Bibliothek
Die Standardtechnologie für grafische Benutzerobeflächen ist
unter UNIX das 1984 am MIT entwickelte XWindow-System
Für das Setup sind folgende Aufrufe notwendig:
1
2
3
4
XOpenDisplay → liefert Display-Handle zu $DISPLAY
createSimpleWindow → öffnet ein Fenster
createGC → liefert GraphicContext
... und los geht’s: XMapWindow, XSync, XDraw...
Dokumentation aller XLib-Routinen
http://users.actcom.co.il/~choo/lupg/tutorials/xlib-programming
Wir verwenden die libxhelper-Funktionen von der
Vorlesungs-Homepage und vertiefen Windows nicht weiter
(reale GUIs verwenden ohnehin higher-level Frameworks,
z. B. CDE, QT, ..)
Übersetzen von Code der XLib verwendet:
gcc test.c -o prog -L/usr/X11/lib -lX11
Prof. Dr. Jan Dünnweber, Folie 9 von 14
Programmierung 1
Funktionen mit ...-Parametern, z. B. beliebig viele Punkte
Wir verwenden die Makros va start, va arg und va list
(alle sind in stdarg.h definiert) wie folgt:
Beispiel: beliebig viele Zahlen addieren
#include <stdarg.h>
int add(int zahlen, ...) {
va_list zeiger;
int zahl;
va_start(zeiger,zahlen);
do {
zahl = va_arg(zeiger,int);
zahlen += zahl;
} while(zahl != 0);
va_end(zeiger);
return zahlen;
}
Die Rotationsfunktion
Die Darstellung unseres gedrehten Rechtecks berechnen wir
Ecke-für-Ecke:
rotateRect
XPoint *rotateRect(int x, int y, int w, int h, int a) {
static XPoint points[5];
points[0].x = x; points[0].y = y;
points[1].x = x + w; points[1].y = y;
points[2].x = x + w; points[2].y = y + h;
points[3].x = x; points[3].y = y + h;
points[4].x = x; points[4].y = y;
rotate( 5, a, &points[0], &points[1], &points[2], &points[3],
&points[4], &points[5] );
return points;
}
Die Funktion rotate projiziert dabei eine beliebige Menge
von Punkten (Typ: XPoint aus XLib)
⇒ Wir sehen uns die Verarbeitung der variablen
Parameterliste genauer an
Prof. Dr. Jan Dünnweber, Folie 10 von 14
Programmierung 1
Anwendung der Matrix und Grafik-Bibliotheksfunktionen
Berechnung der Rotation
void rotate(int n, int a, ...) {
va_list varpoints; auto i; XPoint *point;
va_start(varpoints, a);
for (i = 0; i < n; ++i) {
XPoint *point = va_arg(varpoints, XPoint *);
matrix *vector = createMatrix(1, 2),
*rotation = createMatrix(2, 2), *projection;
setValue(vector, 0, 0, point−>x);
setValue(vector, 0, 1, point−>y);
setValue(rotation, 0, 0, cos((double)a * M_PI / 180));
setValue(rotation, 1, 0, −sin((double)a * M_PI / 180));
setValue(rotation, 0, 1, sin((double)a * M_PI / 180));
setValue(rotation, 1, 1, cos((double)a * M_PI / 180));
projection = mult(vector, rotation);
point−>x = getValue(projection, 0, 0);
point−>y = getValue(projection, 0, 1);
}
va_end(varpoints); }
Aufruf z. B. mittels
printf("%d\n",add(11,12,13,0));
Es gilt aber: mind. ein Parameter muss bekannt sein
Prof. Dr. Jan Dünnweber, Folie 11 von 14
Programmierung 1
Da Winkel in Radiant (Bogenmaß) angegeben werden, müssen
diese vor Aufruf der trigonometrischen Funktionen noch mit
π/180 multipliziert werden
Prof. Dr. Jan Dünnweber, Folie 12 von 14
Programmierung 1
Das Hauptprogramm zur Darstellung des Rechecks
Das Hauptprogramm stellt das gedrehte Rechteck dar:
main
int main(int argc, char* argv[]) {
Display* display = XOpenDisplay(getenv("DISPLAY")); ...
if (argc < 2) { printf("specify an angle...\n"); exit(1); }
win = createSimpleWindow(display, width, height, 0, 0);
gc = createGC(display, win, 0); ... XMapWindow (display, win);
... angle = atoi(argv[[1]);
XDrawLines( display, win, gc,
rotateRect(140, 30, width / 4, height / 3, angle),
5, CoordModeOrigin );
XFlush(display); XSync(display, False);
getchar( ); XCloseDisplay(display);
return 0;
}
Mit atoi wird der ASCII Parameter zu int konvertiert
Prof. Dr. Jan Dünnweber, Folie 13 von 14
Programmierung 1
Zusammenfassung
Was haben wir gelernt?
Die Matrixmultiplikation ist nur für bestimmte Matrizen
definiert (z. B. quadratische, orthogonale, ...)
Die Implementierung in C kann mittels unterschiedlicher
Verbundtypen realisiert werden (z. B. Arrays oder Listen)
Die Multiplikation (aber auch jeder einzelne Zugriff und die
Ausgabe von Werten) erfordern auf die verwendeten
Datentypen angepasste Funktionen (im Beispiel getValue,
setValue, printMatrix, mult, ...)
Sollen einzelne Funktionen variable Paramterlisten haben, so
kann darauf mittels der Makros aus stdargs zugegriffen
werden (va start, va arg und va list)
Anwendungen ergeben sich z. B. (in Kombination mit der
XLib) in der Grafikprogrammierung
Für die Zusammenfassung der nicht-Standard Funktionen
bietet sich wieder benutzerdefinierte Bibliotheken an
Prof. Dr. Jan Dünnweber, Folie 14 von 14
Programmierung 1

Documentos relacionados