Λιγο βοήθεια με τη C
Giorgos Keramidas
keramida at ceid.upatras.gr
Fri Jun 2 18:50:32 EEST 2006
On 2006-06-01 23:26, Dimitris Mexis <m65 at vivodinet.gr> wrote:
> Exo ton parakato kodika, pistevo oti tha nai efkolo poli, se
> kapoion na to trexi me ena gcc apla...
Πρώτα από όλα, το πρόγραμμά σου δεν είναι C. Χρησιμοποιεί C++
features (όπως το 'cout' και οι δηλώσεις μεταβλητών σε τυχαία
σημεία), οπότε με C compiler ούτε κατά διάνοια δεν παίζει.
Αυτό δεν είναι πρόβλημα όμως. Το πρόβλημα είναι τα 'λάθη' που
έχει το πρόγραμμα. Κοίτα παρακάτω τα σχόλια γραμμή-προς-γραμμή
και διόρθωσέ τα πριν ασχοληθείς με πιο δύσκολα πράγματα.
1 void freq_array( double mtx[], int elements ){
2 //The mtx is a ghost of the matrix I transfer, VORSICHT!!!
Τι εννοείς 'ghost'; Και τί σημαίνει το `VORSICHT!!!' ακριβώς;
3
4 selsort( mtx, elements );
Δεν υπάρχει visible prototype για την selsort εδώ. Αυτό σημαίνει
πως ο compiler δε μπορεί ακόμα να κάνει σωστά type-checking στα
ορίσματα που της περνάς.
Επίσης, γιατί ακριβώς χρειάζεται να ΤΑΞΙΝΟΜΗΣΕΙΣ τον πίνακα πριν
μετρήσεις τις συχνότητες εμφάνισης των αριθμών;
5
6 int found = 0;
7
Δεν υπάρχει κανένας καλός λόγος αυτό το declaration να είναι χύμα
σε κάποιο «τυχαίο» σημείο του πηγαίου κώδικα. Είτε βάλ' το στην
αρχή της συνάρτησης (όπως συνήθως γίνεται σε C προγράμματα), είτε
εκεί που χρησιμοποιείται.
8 cout << "...after!" << endl;
Παρακαλώ; Τι ρόλο ακριβώς εξυπηρετεί αυτό το μήνυμα;
9 for ( int i = 0; i < elements; i++ ){
10 for ( int x = 0; x < elements; x++ ){
11 if ( mtx[x] == mtx[i] ){
12 found++;
13 }
14 }
15 cout << "Found value :" << mtx[i] << ", times :" << found << endl;
16 found = 0;
17 }
18 }
Αυτός ο αλγόριθμος είναι πολυπλοκότητας O(N^2). Αν ο πίνακας έχει
μέγεθος 100, θα κάνει 100 * 100 συγκρίσεις. Αν έχει μέγεθος 1000, θα
κάνεις ένα εκατομμύριο. Αν έχει μέγεθος 1,000,000, φτιάξε καφέ όσο θα
τρέχει... θα περιμένεις πολύ.
Είναι ο πιο απλός να υλοποιήσει κανείς όμως όταν ξέρει ότι ο πίνακας
`mtx' θα έχει σχετικά μικρό μέγεθος. Ολες οι εναλλακτικές λύσεις που
είναι πιο γρήγορες κοστίζουν είτε σε χώρο είτε σε πολυπλοκότητα του
αλγορίθμου.
Ο τρόπος που το υλοποίησες όμως έχει ένα πρόβλημα. Το found δεν
αρχικοποιείται σε μηδέν για κάθε στοιχείο mtx[i] του πίνακα mtx[].
Αυτό σημαίνει ότι στις εμφανίσεις του mtx[x] καταλογίζεις και όλες τις
εμφανίσεις του mtx[x-1], mtx[x-2], ... mtx[0].
Είμαι σχεδόν σίγουρος ότι δεν ήθελες κάτι τέτοιο :)
Αντίθετα, κάτι σαν αυτό, θα δουλέψει πιο σωστά:
for (int i = 0; i < elements; i++) {
int nitems = 0;
for (k = 0; k < elements; k++) {
if (mtx[i] == mtx[k])
nitems++;
}
cout << "Value " << mtx[i] << " found " << nitems << " times." << endl;
}
Ακόμα κι αυτό όμως έχει πρόβλημα. Δε μπορείς έτσι απλά να συγκρίνεις
`double' τιμές με το == operator. Για περισσότερες πληροφορίες σχετικά
με την floating-point αριθμητική και τα προβλήματα που έχει η
αναπαράσταση των floating point αριθμών σε τέτοιες συγκρίσεις, σου
προτείνω ανεπιφύλακτα το:
David Goldberg, ``What Every Computer Scientist Should Know About
Floating-Point Arithmetic''. Appendix to ``Numerical Computation
Guide'' by Sun Microsystems. Published in the March, 1991 issue of
Computing Surveys. Copyright 1991, Association for Computing
Machinery, Inc.
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Πρέπει να βρεις κάποιο πιο καλό τρόπο να κάνεις αυτές τις συγκρίσεις.
Πως μπορείς τώρα να κρατήσεις αυτές τις `nitems' τιμές σε ένα άλλο
πίνακα, που έχει το ίδιο μέγεθος με τον mtx[]? Ισως με κάτι σαν:
void
freq_array(size_t elements, double mtx[], double freq[])
{
size_t i, k, count;
for (i = 0; i < elements; i++) {
count = 0;
for (k = 0; count < elements; k++) {
if (cmpdouble(mtx[i], mtx[k]) == 0)
count++;
freq[i] = count;
}
}
Τώρα το μόνο που μένει είναι να φτιάξεις το cmpdouble(a, b) function,
το οποίο θα συγκρίνει δυο `double' αριθμούς και θα επιστρέφει:
-1 Αν το a είναι μεγαλύτερο από το b τόσο που να μην πέφτει μέσα
στο threshold που θεωρείς ότι δεν έχει σημασία για σένα.
0 Αν η διαφορά του a από το b είναι πολύ μικρή, κάτω από το
threshold που έχει σημασία για σένα.
1 Αν το α είναι μικρότερο από το b (σύμφωνα, πάντα, με το
threshold που σε ενδιαφέρει.
Αφού διαβάσεις το ``What Every Computer Scientist Should Know About
Floating-Point Arithmetic'' δε θα είναι δύσκολο να γράψεις κάτι τέτοιο.
Δε θα είναι δύσκολο να γράψεις ακόμα και την freq_array() να παίρνει ως
παράμετρο αυτό το threshold.
19
20 //Selection Sort function
21 //Takes two parameters:
22 //int *array- the array with the numbers to be sorted
23 //int size- the size of the array
Τα μεγέθη αντικειμένων δεν είναι σωστό να τα αποθηκεύεις σε `int'.
Ο σωστός τύπος είναι `size_t'. Αυτό σημαίνει βέβαια ότι πρέπει να
γράφεις κάτι σαν:
void
selsort(double *array, size_t nelem)
{
size_t k;
if (array == NULL)
return;
for (k = 0; k < nelem; k++)
...
24 void selsort( double *array,int size){
25 int min;int b;
26 //This loop goes through the whole array
27 for( int a = 0; a < size-1; a++ ){
28 b=a;
29 min=array[b]; //Get the current value
30 //...and check if any of the rest numbers is lower
Είναι ΠΟΛΥ ΚΑΚΗ ΙΔΕΑ να αποθηκεύεις ένα double value, όπως το array[b],
σε ένα `int'.
31 for(int j=a+1;j<size;j++){
32 if( array[j]< min ){
Λάθος σύγκριση, με χρήση του < operator, για floating-point τιμή.
33 b = j;
34 min = array[b]; //...and if yes, then get it
Επίσης.
35 }
36 }
37 //Switch the values...
38 array[b]=array[a];
39 array[a]=min;
Λάθος ανάθεση `int' σε θέση που έχει τύπο `double'.
40 }
41 }
42
43 int main(int argc, char *argv[])
44 {
45 double matrix[10];
46 cout << "before..." << endl;
47 for ( int i = 0; i < 10; i++ ){
48 matrix[i] = 10 - i;
49 matrix[3] = 3;
50 matrix[4] = 3;
51 matrix[1] = 2;
52 matrix[0] = 0;
53 cout << matrix[i] << endl;
54 }
55 freq_array( matrix, ( sizeof( matrix )/sizeof( matrix[0] ) ) );
56
57 exit(0);
58 }
> To provlima einai oti stelno loipon, mia matrix[] array stin sinartisi
> selsort(), mou sortari tin array, pame kala, stelno meta tin matrix[]
> array sto freq_array() kai pragmati petixeno na perno, poses times
> ehei vrei...OMOS. Exo kolisi sto pos telika na paro mia struct(?),
> array(?), list(? den xero kai STL ), me tis metavlites kai tin
> sixnotita apla pou emfanizontai...diladi mia nea isos matrix,
Πολύ απλά, όπως έδειξα στην freq_array() παραπάνω:
void
freq_array(size_t elements, double mtx[], double freq[])
{
size_t i, k, count;
for (i = 0; i < elements; i++) {
count = 0;
for (k = 0; count < elements; k++) {
if (cmpdouble(mtx[i], mtx[k]) == 0)
count++;
freq[i] = count;
}
}
Αρκετά απλός τρόπος, αλλά θα πρέπει να περάσεις στην freq_array() ΔΥΟ
ΠΙΝΑΚΕΣ...
More information about the Linux-greek-users
mailing list