| Autor |
Nachricht |
Yarox
Unregistrierter
|
Yarox Unregistrierter
16:24:12 14.04.2012 Titel: |
Abstand von Vektoren berechnen |
Zitieren |
Hallo Leute,
ich habe zur Zeit ein Problem, wo ich bereits seit ein paar Stunden nicht richtig weiterkomme.
Es geht um folgendes: Ich habe einen Zeilenvektor 3. Dimension gegeben mit tr(v)=1, sowie eine fixe stochastische Matrix, nennen wir sie M. Nun möchte ich die Verteilungen berechnen, das geht so: v*M = v'. Darauf folgend soll der Abstand der Vektoren v zu v' berechnet werden, Stichwort ist da die Euklidsche Metrik, kurz: d(v,v')=sqrt( (v-v')^2 ).
Ich poste einfach mal meinen Code an dieser Stelle, und erläutere im Nachhinein:
| Code: | double mult_matrix_vector(double *matrix, double *vector, int i) {
double tmp;
tmp=vector[0]*matrix[i] + vector[1]*matrix[i+3] + vector[2]*matrix[i+6];
return tmp;
} | | Diese Routine soll den neuen Eintrag an der Stelle i berechnen, konkreter: v=(i=0 i=1 i=2)*M=(i=0 i=1 i=2)=v' Dabei ist die Matrix M zeilenweise in einem Array gespeichert.
| Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 | double d_euklid (double* vector_old, double* vector_new) {
int i; double abstand; double array[3]={0};
for(i=0;i<3;i++) {
array[i] = pow((vector_old[i]-vector_new[i]),2); // (x-y)^2 //
array[i] = (int) (array[i]*100000); // Hier wird gerundet //
array[i] = array[i]/100000; // Hier wird gerundet //
}
abstand = sqrt(array[0]+array[1]+array[2]); // ||x-y|| //
abstand = (int) (abstand*1000000); // Hier wird gerundet //
abstand = abstand/1000000; // Hier wird gerundet //
return abstand;
} | | Nicht viel zu erklären. Hier wird der Abstand der Vektoren v zu v' berechnet. Dabei runde ich großzügig, da die Vektoren v,v' Einträge mit einigen Nachkommastellen haben können, und sonst ein underflow auftritt, bzw die Ausgabe nicht mehr schön ist.
Kommen wir zum Automatismus:
| Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void plot (double* matrix, double* vector_new, int n) {
double vector_old[3]={0};
double *array_abstand;
array_abstand = (double*) malloc(n*sizeof(double));
FILE *file;
file = fopen("abstandplot.txt", "w");
int i,k;
for(k=0;k<n;k++){
for(i=0;i<3;i++) {
vector_old[i]=vector_new[i];
vector_new[i]=mult_matrix_vector(matrix,vector_new,i);
}
array_abstand[k]=d_euklid(&vector_old,&vector_new);
printf("\nVerteilung nach Iteration %d:(%f %f %f)\n",k+1, vector_new[0],vector_new[1],vector_new[2]);
printf ("d(%d,%d)=%g\n",k,k+1,array_abstand[k]);
fprintf( file, "(%d,%g)\n", k, array_abstand[k]);
}
fclose(file);
} | | n wird in der main definiert als die Anzahl der Wiederholungen, oder anders gesagt, wie viele von zwei aufeinanderfolgenden Vektoren verglichen werden sollen.
Hier habe ich ein Bild der Ausgabe hochgeladen.http://s14.directupload.net/images/120414/k9zua8tn.png
Was fällt also auf: Offenbar wird v' für k>1 nicht mehr berechnet. Ich kann mir aber nicht erklären, wieso. Vielleicht kann mir da einer von euch Tipps geben oder gar zeigen, wo der Fehler liegt und bedanke mich jetzt schon mal für eure Hilfe.
Grüße,
Yarox |
|
|
|
 |
Yarox
Mitglied
Benutzerprofil
Anmeldungsdatum: 14.04.2012
Beiträge: 2
|
Yarox Mitglied
16:55:35 14.04.2012 Titel: |
|
Zitieren |
Ich bins nochmal, registriert und wollte eine Demo-Version unten posten:
| Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #include <stdio.h>
#include <stdlib.h>
#include <math.h>
double mult_matrix_vector(double *matrix, double *vector, int i)
{
double tmp;
tmp=vector[0]*matrix[i] + vector[1]*matrix[i+3] + vector[2]*matrix[i+6];
return tmp;
}
double d_euklid (double* vector_old, double* vector_new)
{
int i;
double abstand;
double array[3]= {0};
for(i=0; i<3; i++)
{
array[i] = pow((vector_old[i]-vector_new[i]),2); // (x-y)^2 //
array[i] = (int) (array[i]*100000); // Hier wird gerundet //
array[i] = array[i]/100000; // Hier wird gerundet //
}
abstand = sqrt(array[0]+array[1]+array[2]); // ||x-y|| //
abstand = (int) (abstand*1000000); // Hier wird gerundet //
abstand = abstand/1000000; // Hier wird gerundet //
return abstand;
}
void plot (double* matrix, double* vector_new, int n)
{
double vector_old[3]= {0};
double *array_abstand;
array_abstand = (double*) malloc(n*sizeof(double));
int i,k;
for(k=0; k<n; k++)
{
for(i=0; i<3; i++)
{
vector_old[i]=vector_new[i];
vector_new[i]=mult_matrix_vector(matrix,vector_new,i);
}
array_abstand[k]=d_euklid(&vector_old,&vector_new);
printf("\nVerteilung nach Iteration %d:(%f %f %f)\n",k+1, vector_new[0],vector_new[1],vector_new[2]);
printf ("d(%d,%d)=%g\n",k,k+1,array_abstand[k]);
}
}
int main()
{
double matrix_P[9]= {0.5,0.3333333333333333333,0.166666667,
0.75,0,0.25,
0,1.,0
};
double startverteilung[3]= {1,0,0};
plot (matrix_P,startverteilung,5);
return 0;
} | |
Vielleicht hilfts |
|
|
|
 |
SeppJ
Moderator
Benutzerprofil
Anmeldungsdatum: 10.06.2008
Beiträge: 17947
|
SeppJ Moderator
17:14:45 14.04.2012 Titel: |
|
Zitieren |
In Zeile 45 gehören die & dort nicht hin.
Der Cast vom malloc gehört dort nicht hin.
Das malloc hat kein free.
Zum Thema Runden: WTF? Wenn du in der Ausgabe runden willst, dann runde in der Ausgabe (guck mal die Formatoptionen von printf an), aber doch nicht in der Rechnung! Wie kommst du auf so eine Idee?
Deine Matrixmultiplikation ist, zumindest nach gängiger Konvention, falsch. Du multiplizierst den Vector mit einer Spalte der Matrix, nicht mit einer Zeile. Du meinst vermutlich
| C++: | | tmp=vector[0]*matrix[3*i] + vector[1]*matrix[3*i+1] + vector[2]*matrix[3*i+2]; | |
Das sind die direkten Fehler, die mir aufgefallen sind. Andernfalls ist das Programm natürlich unendlich umständlich, aber das ist dir vermutlich bewusst. Mit den Fehlern behoben sieht die Ausgabe so aus:
| Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 | Verteilung nach Iteration 1:(0.500000 0.375000 0.375000)
d(0,1)=0.728869
Verteilung nach Iteration 2:(0.437500 0.421875 0.421875)
d(1,2)=0.0911086
Verteilung nach Iteration 3:(0.429688 0.427734 0.427734)
d(2,3)=0.0113886
Verteilung nach Iteration 4:(0.428711 0.428467 0.428467)
d(3,4)=0.00142357
Verteilung nach Iteration 5:(0.428589 0.428558 0.428558) | | Ist dies das, was du suchtest? |
_________________ Du brauchst Hilfe?, Buchempfehlungen für C++,
Wie man in Fragen den richtigen Code postet,
The Definitive C++ Book Guide and List
|
|
 |
Yarox
Mitglied
Benutzerprofil
Anmeldungsdatum: 14.04.2012
Beiträge: 2
|
Yarox Mitglied
17:35:55 14.04.2012 Titel: |
|
Zitieren |
Hallo.
Ja, danke dir. Das ist genau das, was ich haben wollte. Der Abstand geht gegen 0, hervorragend Mir ists ja schon ein wenig peinlich, die Matrixmultiplikation falsch implementiert zu haben.
Ich danke dir auch für deine weiteren Hinweise. Ich bin noch Neuling im Programmieren, da ist sowas sehr hilfreich.
-Der Cast von malloc gehört da nicht rein, weil das array bereits ein double ist, oder?
-free - mal wieder- vergessen. Hätte ich aber in valgrind spätestens gemerkt, danke trotzdem.
-Zum Thema runden: Das Problem ist, dass wenn ich
| Code: | | printf ("d(%d,%d)=%.6g\n",k,k+1,array_abstand[k]); | |
schreibe, die Ausgabe so aussieht:
| Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 0.5 0.333 0.167
0.75 0 0.25
0 1 0
Zufaellig generierte Startverteilung:(0.803345 0.096380 0.100276)
Bestimme n: 10
Verteilung nach Iteration 1:(0.450511 0.362953 0.362953)
d(0,1)=0.514346
...
Verteilung nach Iteration 5:(0.400490 0.400469 0.400469)
d(4,5)=0.000124647
Verteilung nach Iteration 6:(0.400479 0.400477 0.400477)
d(5,6)=1.55808e-005
...
Verteilung nach Iteration 10:(0.400478 0.400478 0.400478)
d(9,10)=3.84806e-009 | |
Das Programm ist in der Tat ein wenig umständlich, wollte es anfangs etwas anders handhaben, bin aber daran gescheitert, dass eine double foo() kein array zurückgeben kann. Darum hab ich nach einer alternative gesucht. Schlägt sich das denn auf die Laufzeit des Programmes negativ aus, so, wie ich das Programm realisiert habe?
edit:
ok, mit | Code: | | printf ("d(%d,%d)=%.6f\n",k,k+1,array_abstand[k]); | | funktionierts einwandfrei. Somit hat sich das auch geklärt. Nochmals danke dir für deine Hilfe. |
Zuletzt bearbeitet von Yarox am 17:37:39 14.04.2012, insgesamt 1-mal bearbeitet |
|
 |
SeppJ
Moderator
Benutzerprofil
Anmeldungsdatum: 10.06.2008
Beiträge: 17947
|
SeppJ Moderator
18:40:15 14.04.2012 Titel: |
|
Zitieren |
| Yarox schrieb: |
-Der Cast von malloc gehört da nicht rein, weil das array bereits ein double ist, oder? | Nein, der gehört da nicht hin, weil malloc einen void* zurückliefert, der implizit in alle anderen Datenzeiger überführt werden kann. In C++ wäre solch ein Cast nötig (aber dann auch besser ganz anders und malloc benutzt man dort sowieso nicht). Durch den Cast verdeckst du bloß Compilerfehler, falls du mal malloc falsch benutzt haben solltest, hast aber keine Vorteile.| Zitat: |
-Zum Thema runden: Das Problem ist, dass wenn ich
[...]
Schlägt sich das denn auf die Laufzeit des Programmes negativ aus, so, wie ich das Programm realisiert habe?
| Ein bisschen. Viel schlimmer ist, dass dein Ergebnis nicht stimmt und du machst ja anscheinend irgendetwas numerisches. Man rundet niemals Zwischenergebnisse.| Zitat: |
edit:
ok, mit | Code: | | printf ("d(%d,%d)=%.6f\n",k,k+1,array_abstand[k]); | | funktionierts einwandfrei. Somit hat sich das auch geklärt. Nochmals danke dir für deine Hilfe. | So ist's recht.
printf ist sehr mächtig, da bleibt kein (normaler) Wunsch bei der Formatierung offen. |
_________________ Du brauchst Hilfe?, Buchempfehlungen für C++,
Wie man in Fragen den richtigen Code postet,
The Definitive C++ Book Guide and List
|
|
 |
Wutz
Mitglied
Benutzerprofil
Anmeldungsdatum: 15.04.2010
Beiträge: 2696
|
Wutz Mitglied
19:43:42 14.04.2012 Titel: |
|
Zitieren |
| Yarox schrieb: |
| C++: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* hier kannst du jeweils noch ein 'const' spendieren, du kaufst du damit kostenlose Prüfungen des Compilers ein und hilfst ihm beim Optimieren */
double mult_matrix_vector(double *matrix, double *vector, int i)
double mult_matrix_vector(const double *matrix, const double *vector, int i)
/* hier ebenso */
double d_euklid (const double* vector_old, const double* vector_new)
/* hier suggerierst du dem Quellcodeleser eine dir unbekannte Genauigkeit */
double matrix_P[9]= {0.5,0.3333333333333333333,0.166666667,
/* lasse den Compiler für dich rechnen, also besser */
double matrix_P[9]= {0.5,1.0/3,1.0/6, | |
| |
_________________ Java, the best argument for Smalltalk since C++. -- Frank Winkler
|
|
 |
DirkB
Unregistrierter
|
DirkB Unregistrierter
20:01:34 14.04.2012 Titel: |
|
Zitieren |
| SeppJ schrieb: | | printf ist sehr mächtig, da bleibt kein (normaler) Wunsch bei der Formatierung offen |
Die Unterdrückung der führenden Nullen im Exponenten bei %e (und %g) hätte ich gerne. |
|
|
|
 |
SeppJ
Moderator
Benutzerprofil
Anmeldungsdatum: 10.06.2008
Beiträge: 17947
|
SeppJ Moderator
20:07:47 14.04.2012 Titel: |
|
Zitieren |
|
 |
|
Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben. Sie können auf Beiträge in diesem Forum antworten. Sie können Ihre Beiträge in diesem Forum nicht bearbeiten. Sie können Ihre Beiträge in diesem Forum nicht löschen. Sie können an Umfragen in diesem Forum nicht mitmachen.
|
|
|
|
|