ggeo1 Δημοσ. 2 Αυγούστου 2011 Δημοσ. 2 Αυγούστου 2011 Λοιπόν,προσπαθώ να υλοποιήσω το πολυώνυμο hermite σύμφωνα με τον τύπο που επισυνάπτω. Το πρόβλημά μου είναι ότι παίρνω λάθος τιμές.Επειδή οι υπολογισμοί για τους συντελεστές lagrnage είναι σωστοί (χάρη σε βοήθεια από προηγούμενο ποστ) ,το λάθος πιστεύω ότι είναι στις παραγώγους των συντελεστών lagrange. > #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> using namespace std; const double pi=3.1415926535897932; // my function double f(double x){ return (cos(pi*x)); } //compute the numerical differention (forward) double fd(double x){ double h=0.5; return ((-3.0*f(x)+4.0*f(x+h)-f(x+2.0*h))/2.0*h); } double hermite(int N,double x,double *xpts,double *L_coeff,double *L_coeff_deriv){ //N=degree of polynomial //L_coeff=hold lagrange coeff ,L //L_coeff_deriv=hold derivatives of lagrange coeff , L' double *A=new double[N+1];//hold hermite terms double *B=new double [N+1];//hold hermite terms int k,i; double eps=10e-9; //error //computations for finding lagrange polynomial for (k=0;k<N+1;k++){ L_coeff[k]=1.0; for ( i=0;i<N+1;i++){ if (k!=i){ if (fabs(xpts[k]-xpts[i])<eps) { cout << "error : coincident nodes. Aborting..."; exit(1); } L_coeff[k]*=(x-xpts[i])/(xpts[k]-xpts[i]); } } L_coeff_deriv[k]=fd(L_coeff[k]); //εδώ μάλλον έχω λάθος //compute hermites terms A[k]=(1.0-2.0*L_coeff_deriv[k]*(x-xpts[k]))*(L_coeff[k]*L_coeff[k]); B[k]=(x-xpts[k])*(L_coeff[k]*L_coeff[k]); } double sum1=0; for(int p=0;p<N+1;p++){ sum1+=A[p]*f(xpts[p])+ B[p]*fd(xpts[p]); } return sum1; } int main() { int deg; double *xpts=new double [deg+1]; double *L_coeff=new double [deg+1]; double *L_coeff_deriv=new double [deg+1]; double result,x; cout <<"Give the degree of the polynomial :"<<endl; cin >>deg; int i; for (i=0;i<deg+1;i++){ cout <<"\nGive the points of interpolation : "<<endl; cin >> xpts[i]; } cout <<"\nGive the point to interpolate : \n"; cin >>x; result=hermite(deg,x,xpts,L_coeff,L_coeff_deriv); cout <<"\nThe polynomial value is :\n "<<endl; cout <<result; return 0; } Η άσκηση λέει: Find hermite's polynomial approximation for y(x)=cos(π x), x ∈(−1,1) using 5 points (x = -1, -0.5, 0, 0.5, and 1)
V.I.Smirnov Δημοσ. 2 Αυγούστου 2011 Δημοσ. 2 Αυγούστου 2011 Κοιτώντας τον κώδικα μακροσκοπικά, η εντολή L_coeff_deriv[k]=fd(L_coeff[k]); //εδώ μάλλον έχω λάθος όπου υποψιάζεσαι ότι έχεις λάθος είναι πράγματι λαθεμένη. Αναμένεις να υπολογιστούν αριθμητικά οι παράγωγοι των συντελεστών Langrange. Ωστόσο, η συνάρτηση που βρίσκει τις αριθμητικές παραγώγους, δηλ. η fd(...), χρησιμοποιεί αποκλειστικά την f(x), δηλ. την cos(πx), κι' όχι την Lj(x) όπως θα έπρεπε. Η συνάρτηση fd που υπολογίζει την αριθμητική παράγωγο δέχεται ως όρισμα μόνον μια τιμή. Πρέπει επιπροσθέτως να δέχεται και την συνάρτηση, έστω g(x), για την οποία υπολογίζονται οι παράγωγοι. Ή εναλλακτικά να γράψεις μια ακόμη συνάρτηση, αντίστοιχη της fd, που όμως θα υπολογίζει τις παραγώγους των Lj(x)... -
ggeo1 Δημοσ. 2 Αυγούστου 2011 Μέλος Δημοσ. 2 Αυγούστου 2011 Καλά,το είχα ξεχάσει τελείως αυτό!! Οκ,βρήκα ότι οι συντελεστές L' μπορούν να γραφούν και ως : L'=1/x[k]-x ,οπότε το έκανα έτσι . .... L_coeff[k]*=(x-xpts)/(xpts[k]-xpts); L_coeff_deriv+=1.0/(xpts[k]-xpts); ....... Αν όμως ήθελα να κάνω αυτό που είπες,δηλ να φτιάξω μια συνάρτηση που να υπολογίζει τους συνετελεστές L' ,πώς θα το χειριζόμουν? Δηλ , πως είχε πρόσβαση η συνάρτησή μου στα δεδομένα της συνάρτησης hermite ,όπου περιέχονται οι L_coeff. Ευχαριστώ πολύ!
ggeo1 Δημοσ. 3 Αυγούστου 2011 Μέλος Δημοσ. 3 Αυγούστου 2011 Αν κάνω το εξής : Φτιάχνω τη συνάρτηση > double lderiv(double *x){ if (x!=0) return (1.0/(*x)); } η οποία θα υπολογίζει τα L'.(για απλούστευση υποθέτουμε ότι ισχύει : L'=1/L ) και μέσα στη συνάρτηση Hermite βάλω : > .... L_coeff[k]*=(x-xpts[i])/(xpts[k]-xpts[i]); L_coeff_deriv+=lderiv(L_coeff[k]); ... μου βγάζει σφάλμα : error: cannot convert ‘double’ to ‘double*’ for argument ‘1’ to ‘double lderiv(double*)’ Κάνω κάποιο λάθος με τους pointers?
ggeo1 Δημοσ. 3 Αυγούστου 2011 Μέλος Δημοσ. 3 Αυγούστου 2011 δεν υπαρχει κανενας λογος να εχεις δεικτη. Όντως!Δουλεύει χωρίς Pointer. >double lderiv(double x){ if (x!=0) return (1.0/(x)); } > .... L_coeff[k]*=(x-xpts[i])/(xpts[k]-xpts[i]); L_coeff_deriv+=lderiv(L_coeff[k]); ... Δεν το καταλαβαίνω όμως. Το L_coeff είναι pointer. Στη συνάρτηση lderiv βάζω δηλ ως όρισμα έναν pointer αλλά τη συνάρτηση την ορίζω με μια απλή μεταβλητή ως όρισμα?
migf1 Δημοσ. 3 Αυγούστου 2011 Δημοσ. 3 Αυγούστου 2011 Το L_coeff[k] που περνάς στην lderiv δεν είναι pointer, είναι απλό double... οπότε γιατί στον ορισμό της συνάρτησης δηλώνεις το όρισμά της ως pointer to double (αφού σκέτο double της περνάς στην main) Το L_coeff είναι pointer, αλλά τα L_coeff[k] δεν είναι (είναι σκέτο double). Όντως!Δουλεύει χωρίς Pointer. >double lderiv(double x){ if (x!=0) return (1.0/(x)); } > .... L_coeff[k]*=(x-xpts[i])/(xpts[k]-xpts[i]); L_coeff_deriv+=lderiv(L_coeff[k]); ... Δεν το καταλαβαίνω όμως. Το L_coeff είναι pointer. Στη συνάρτηση lderiv βάζω δηλ ως όρισμα έναν pointer αλλά τη συνάρτηση την ορίζω με μια απλή μεταβλητή ως όρισμα?
ggeo1 Δημοσ. 3 Αυγούστου 2011 Μέλος Δημοσ. 3 Αυγούστου 2011 Καταρχήν,ξαναβάζω τον κώδικα γιατί είχα κάνει κάποιες αλλαγές. > using namespace std; const double pi=3.1415926535897932; // my function double f(double x){ return (cos(pi*x)); } //compute the numerical differention (forward) double fd(double x,int N){ double h=0.5; for(int i=0;i<N+1;i++){ if (i==1){ return (-(1.0/2.0*h)*(3.0*f(i)-4.0*f(i+1.0)+f(i+2.0))); } if (i==N){ return ((3.0*f(i)-4.0*f(i-1.0)+f(i-2.0))/2.0*h); } if((1<i & i<N)) { return ((f(i+1.0)-f(i-1.0))/2.0*h); } } } double lderiv(double x){ if (x!=0) return (1.0/(x)); } double hermite(int N,double x,double *xpts,double *L_coeff){ //N=degree of polynomial //L_coeff=hold lagrange coeff ,L //L_coeff_deriv=hold derivatives of lagrange coeff , L' double *A=new double[N+1];//hold hermite terms double *B=new double [N+1];//hold hermite terms int k,i; double eps=10e-12; //error //computations for finding lagrange polynomial for (k=0;k<N+1;k++){ L_coeff[k]=1.0;double L_coeff_deriv=0; for ( i=0;i<N+1;i++){ if (k!=i){ if (fabs(xpts[k]-xpts[i])<eps) { cout << "error : coincident nodes. Aborting..."; exit(1); } L_coeff[k]*=(x-xpts[i])/(xpts[k]-xpts[i]); L_coeff_deriv+=lderiv(L_coeff[k]); } } //compute hermites terms A[k]=(1.0-2.0*(x-xpts[k])*L_coeff_deriv)*(L_coeff[k]*L_coeff[k]); B[k]=(x-xpts[k])*(L_coeff[k]*L_coeff[k]); } double sum1=0; for(int p=0;p<N+1;p++){ sum1+=A[p]*f(xpts[p])+ B[p]*fd(xpts[p],N+1); } return sum1; } int main() { int deg; double *xpts=new double [deg+1]; double *L_coeff=new double [deg+1]; double result,x; cout <<"Give the degree of the polynomial :"<<endl; cin >>deg; int i; for (i=0;i<deg+1;i++){ cout <<"\nGive the points of interpolation : "<<endl; cin >> xpts[i]; } cout <<"\nGive the point to interpolate : \n"; cin >>x; result=hermite(deg,x,xpts,L_coeff); cout <<"\nThe polynomial value is :\n "<<endl; cout <<result; return 0; } Όπως βλέπεις,το L_coeff είναι pointer! Kάτσε,τώρα αρχίζω να το καταλαβαίνω.. Δηλ το L_coeff είναι Pointer,ok αφού το δηλώνω. Όμως τα L_coeff[k] είναι τιμές ,εφόσον στον Pointer L_coeff περνάω δεδομένα. Τα λέω καλά?
migf1 Δημοσ. 3 Αυγούστου 2011 Δημοσ. 3 Αυγούστου 2011 Το L_coeff[ k ] όμως (που περνάς στην lderiv() ) τι είναι; ΥΓ. Τα λες σχεδόν καλά, δεν είναι τιμές, είναι μεταβλητές τύπου double. Και το L_coeff στην ουσία δεν είναι απλός pointer, είναι array (πίνακας) Αν μου επιτρέπεις μια φιλική συμβουλή, από τη στιγμή που δεν έχεις ξεκάθαρα στα μυαλό σου τα περί δεικτών, προτίμησε να κάνεις τον κώδικά σου όσο πιο κατανοητό μπορείς (σε σένα πρώτα). Π.χ. αν δεν έχεις κάποιο ιδιαίτερο λόγο τον L_coeff να τον δηλώσεις δείκτη και να τον κάνεις allocate δυναμικά, όπως κάνεις τώρα, δήλωσέ τον κανονικό πίνακα. > double L_coeff[ deg+1 ]; Το να μπλέκεις έννοιες που δεν τις κατέχεις καλά (τους δείκτες εννοώ) σε πρόγραμμα που έτσι κι αλλιώς έχει αρκετή πολυπλοκότητα και χωρίς αυτούς, λόγω της μαθηματικής του φύσης, δεν νομίζω πως θα σε βοηθήσει να καταλάβεις καλύτερα τους δείκτες. Μάλλον το αντίθετο θα έλεγα πως είναι πιθανό συμβεί (πόσο μάλλον δείκτες σε συναρτήσεις, που λέγαμε στο άλλο νήμα Υπάρχουν πολύ πιο απλές ασκήσεις που μπορείς να δοκιμάσεις για να κατανοήσεις τους δείκτες
ggeo1 Δημοσ. 3 Αυγούστου 2011 Μέλος Δημοσ. 3 Αυγούστου 2011 Οκ,σε ευχαριστώ! Απλά, σιγά σιγά μπαίνω στο νόημα,σίγουρα θέλει δουλειά και μάλιστα προσεκτική αλλά τι να κάνουμε ,πειραματιζόμαστε και λίγο..
migf1 Δημοσ. 3 Αυγούστου 2011 Δημοσ. 3 Αυγούστου 2011 Ότι χρειαστείς πάντως, ρώτα (αν ξέρουμε θα βοηθήσουμε ) Υπάρχουν πολλές και καλές πηγές για δείκτες, κυρίως στα Αγγλικά. Μπορείς όμως να ρίξεις μια ματιά σε αυτή την εισαγωγή που έχω γράψει σε άλλο φόρουμ, στα Ελληνικά: http://www.gvrteam.gr/forum/viewtopic.php?p=46913#p46913
ggeo1 Δημοσ. 4 Αυγούστου 2011 Μέλος Δημοσ. 4 Αυγούστου 2011 Ok ,ευχαριστώ! (το διάβασα το tutorial,ωραίο,κατανοητό)
migf1 Δημοσ. 4 Αυγούστου 2011 Δημοσ. 4 Αυγούστου 2011 Ok ,ευχαριστώ! (το διάβασα το tutorial,ωραίο,κατανοητό) [OffTopic ON] Χαίρομαι Αν θέλεις να εξασκηθείς σε δείκτες, για αρχή θα σου πρότεινα να το κάνεις με ασκήσεις πάνω σε C-Strings. Παρόλο που στη C++ η std::string έχει απλοποιήσει πολύ τα πράγματα, η διαχείριση των C-strings χρησιμοποιώντας δείκτες είναι σχολείο για την εκμάθηση των βασικών εννοιών στους δείκτες. Μπορείς να ξεκινήσεις με απλά πράγματα, όπως π.χ. να φτιάξεις τη δική σου έκδοση της strlen που επιστρέφει το τρέχον μήκος ενός C-string χωρίς τον μηδενικό χαρακτήρα στο τέλος, και να αυξάνεις σταδιακά τη δυσκολία (π.χ. να φτιάξεις τις δικές σου: strcpy και strncpy, κατόπιν π.χ. τις strchr & strstr και πάει λέγοντας). Αλλά να τα διαχειρίζεσαι ως δείκτες και όχι ως πίνακες... π.χ. για την strlen: > int mystrlen(const char *s) { const char *cp = s; while ( cp && *cp++ ) ; return s ? --cp-s : -1; } αν θες να την κάνεις full-proof ακόμα κι αν της περαστεί NULL ως s ή > int mystrlen(const char *s) { const char *cp = s; while ( *cp++ ) ; return --cp-s; } αν δεν σε ενδιαφέρει να ελέγχεις για NULL μέσα στη συνάρτηση. Και τα δυο παραπάνω σαφώς και δεν είναι από τα πιο... ευανάγνωστα που υπάρχουν αλλά τα έγραψα επίτηδες έτσι ως παράδειγμα κώδικα που χρησιμοποιεί αποκλειστικά δείκτες και τίποτε άλλο. Αν μπορέσεις να διαβάζεις με σχετική άνεση τέτοιον κώδικα κι ακόμα καλύτερα να τον γράφεις και μόνος σου, σημαίνει πως σε μεγάλο ποσοστό έχεις κάνεις κτήμα σου τις βασικές έννοιες των δεικτών και θα μπορείς να πας και σε πιο προχωρημένα πράγματα (όπως π.χ. οι δείκτες σε συναρτήσεις, και το πέρασμα συναρτήσεων ως ορίσματα σε άλλες συναρτήσεις, που λέγαμε στο άλλο νήμα ) ΥΓ. Όταν θα τα έχεις κάνει κτήμα σου τότε θα αρχίσεις από μόνος σου έτσι κι αλλιώς να αποφεύγεις πράγματα σαν το παραπάνω, εις όφελος του "ευ αναγιγνώσκειν" (αλλά τότε θα το κάνεις συνειδητά και από επιλογή ) [/OfftTpic OFF]
ggeo1 Δημοσ. 4 Αυγούστου 2011 Μέλος Δημοσ. 4 Αυγούστου 2011 Να σαι καλά για το ενδιαφέρον! Ευχαριστώ για τις συμβουλές. Εντάξει,έχει πολύ δουλειά η c++..Τεράστιο βάθος! Σιγά σιγά θα προχωράμε.
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.