ABA


"בעיה מוזרה ביותר בתוכנית C"
גירסת הדפסה        
קבוצות דיון פיתוח, תיכנות ובניית אתרים נושא #15472 מנהל    סגן המנהל    מפקח   Winner    צל"ש   מומחה  
אשכול מספר 15472
ronen333 
חבר מתאריך 20.2.03
6069 הודעות
   14:59   23.09.09   
אל הפורום  
  בעיה מוזרה ביותר בתוכנית C  
 
   בעיה מוזרה מאוד שנתקלתי בתוכנית, והייתי שמח אם כמה מכם תביעו את דעתכם בנושא.
הבעיה טמונה בפונקציה swap , בהחלפת ערכי המשתנים אחד בשני מסיבה מסוימת זה לא מבצע את תפקידו כמו שצריך..

#include <stdio.h>
int linear_search (int a[], int n, int num);
int binary_search(int a[], int n, int num);
int find_min (int a[], int start, int n);
void swap (int *a, int *b);
void selection_sort (int a[], int n);

void selection_sort (int a[], int n)
{
int i,mini;
for(i=0;i<n;i++)
{
mini=find_min(a,i,n);
swap(&a[i],&a[mini]);
}


}
void swap (int *a, int *b)
{

*a=*a+*b;
*b=*a-*b;
*a=*a-*b;

}

int find_min(int a[], int start, int n)
{
int min=a[start],index=start,i;
for(i=start+1;i<n;i++)
{
if(min>a[i])
{
min=a[i];
index=i;
}

}
return index;
}

int binary_search(int a[], int n, int num)
{
int high=n-1,low=0,middle;
while(low<=high)
{
middle=(high+low)/2;
if(a[middle]==num)
return middle;
else
{
if(a[middle]>num)
high=middle-1;
else
low=middle+1;
}
}

return -1;

}


int linear_search (int a[], int n, int num)
{
int i;
for(i=0;i<n;i++)
{
if(a[i]==num)
return 1;
}
return 0;

}
int main(void)
{
int arr[6]={3,2,1,4,5,6};
int i,n=6;

selection_sort(arr,n);
for(i=0;i<n;i++)
printf("%d,",arr[i]);


return 0;
}


מבחינה לוגית אני לא רואה פה בעיה.. מתבצעת החלפה בצורה חשבונית פשוטה שאמורה לעבוד, אבל הסוואפ דופק את כל הרעיון של המיון משום מה. ואם הייתי מחליף אותה בפונקציה שמחליפה עם משתנה עזר זמני אז זה כן היה עובד.

מישהו יודע איפה הבעיה טמונה?


                                שתף        
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

  האשכול     מחבר     תאריך כתיבה     מספר  
  למה לך לעשות את הקומבינות הדפוקות האלה? shay86  23.09.09 17:55 1
  לא רואה שם משהו לא תקין. בטוח שהבעיה שם? ניסית להפעיל ידנית? ldan192  23.09.09 18:46 2
  פתרון + כמה הערות TTAsnn 23.09.09 21:34 3
     כן, בדיוק. ldan192  23.09.09 22:18 4
     וואלה גדול אתה ronen333  23.09.09 22:47 5
         הערה בנוגע לזכרון, Deuce  24.09.09 14:18 6
             חחח לא באופנה.. ronen333  24.09.09 16:30 7
         אתה חושב בקטן, זה לא נותן הרבה. TTAsnn 24.09.09 17:16 8
             מבלי לשכוח שמערכת ההפעלה עושה בערך כפול מזה ldan192  24.09.09 17:27 9
                 ממש לא קשור TTAsnn 25.09.09 13:46 14
                     מה שאני אומר זה שבמקרה הזה זה זניח, וכמו לכל דבר ldan192  25.09.09 23:33 15
             כע אני יודע ronen333  24.09.09 21:18 10
                 מכתב Deuce  25.09.09 00:24 11
                     בדיוק, באופן כללי, חשוב להכיר לעומק את סביבת העבודה. TTAsnn 25.09.09 13:38 13
                 מכתב TTAsnn 25.09.09 13:37 12

       
shay86 
חבר מתאריך 13.5.06
197 הודעות
   17:55   23.09.09   
אל הפורום  
  1. למה לך לעשות את הקומבינות הדפוקות האלה?  
בתגובה להודעה מספר 0
 
   זה סתם יוצר קוד לא קריא, רק בגלל שזה כביכול "מגניב".
עדיף לך להשתמש במשתנה עזר וזהו.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ldan192 
חבר מתאריך 14.9.08
95119 הודעות
   18:46   23.09.09   
אל הפורום  
  2. לא רואה שם משהו לא תקין. בטוח שהבעיה שם? ניסית להפעיל ידנית?  
בתגובה להודעה מספר 0
 


בברכה,
עידן


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
TTAsnn

   21:34   23.09.09   
אל הפורום  
  3. פתרון + כמה הערות  
בתגובה להודעה מספר 0
 
   דבר ראשון, כשאתה משתמש בפונקציה כמו זו, שנקראית כל הזמן, (swap) עדיף להשתמש במאקרו, למרות שסביר להניח שכל קומפיילר נורמלי יעשה לזה אופטימיזציה ויעשה inline, אבל זה עדיין יותר "נקי".
אבל יתרון נוסף לשימוש במאקרו זה ש swap עם מאקרו, יהיה ג'נרי, כלומר יוכל לעשות החלפה לכל סוגי המשתנים (הפשוטים, כלומר לא struct), וכמו שאציין מיד, עדיף להשתמש ב xor.

דבר שני, בעקרון מטעמי integer overflow עדיף לעשות את הטריק של swap עם xor ולא עם חיבור וחיסור.

דבר שלישי, כמו שאמרת, הבעיה היא ב swap, ליתר דיוק, הבעיה היא ב swap כאשר אתה מקבל פעמיים את אותה כתובת, הרי מה קורה:
לדוגמא עבור:
a = b שהוא האיבר השני, כלומר הערך ש a ו b מצביאים אליו (אותו תא) הוא 2.


when a = b (i.e the same address)
*a=*a+*b
means that
*a=4
but a and b point to the same place, which means that
*b = 4
and then
*b = *a - *b
means *b is 4-4 which is 0
and that means *a = 0 as well
so *a = *a - *b
means
*a = 0

ולכן חוץ מהראשון (ההחלפה האמיתי היחידה שלך) הכל מתאפס.

איך לפתור, או להשתמש במשתנה עזר, או להוסיף בתחילת swap תנאי שהוא יבצא את ההחלפה רק אם a!=b.
אולי יש עוד רעיונות "מגניבים יותר" איך לתקן את זה, אבל אין לי כח לחשוב עכשיו, מה שאמרתי זה רק מה שקפץ לי לראש בנושא.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ldan192 
חבר מתאריך 14.9.08
95119 הודעות
   22:18   23.09.09   
אל הפורום  
  4. כן, בדיוק.  
בתגובה להודעה מספר 3
 


בברכה,
עידן


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ronen333 
חבר מתאריך 20.2.03
6069 הודעות
   22:47   23.09.09   
אל הפורום  
  5. וואלה גדול אתה  
בתגובה להודעה מספר 3
 
   ערכתי לאחרונה בתאריך 23.09.09 בשעה 22:51 בברכה, ronen333
 
לא חשבתי על המקרה הזה..

וזה לא קטע של להיות מגניב, זה לנסות לפתח הרגלים לחסוך כמה שיותר בזכרון(גם אם הוא זמני בסטאק לאורך הפונקציה) ובעקרון להימנע מלגשת אילו יותר משצריך .

תודה רבה על העזרה


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Deuce 
חבר מתאריך 1.9.08
6225 הודעות
   14:18   24.09.09   
אל הפורום  
  6. הערה בנוגע לזכרון,  
בתגובה להודעה מספר 5
 
באמת שהחסכון הזה בקבועים כאלו קטנים הוא חסר משמעות מבחינת אופטימיזציה.
בכל מקרה, לחבר מספרים זה לא באופנה - תעבוד עם XOR.






                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ronen333 
חבר מתאריך 20.2.03
6069 הודעות
   16:30   24.09.09   
אל הפורום  
  7. חחח לא באופנה..  
בתגובה להודעה מספר 6
 
   סבבה


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
TTAsnn

   17:16   24.09.09   
אל הפורום  
  8. אתה חושב בקטן, זה לא נותן הרבה.  
בתגובה להודעה מספר 5
 
   זה לא נקרא לחסוך בזכרון, כי זה זכרון זמני שנמחק תוך שניה, לחסוך בזכרון זה אומר לבחור מבני נתונים ששומרים כמות מידע בצורה יעילה עם חתימת זכרון נמוכה, כלומר, שימוש בזכרון לאורך זמן.

במקרה הזה זה עוד פחות רלוונטי כי אם כבר אתה רוצה לחסוך זכרון, אז אתה יכול להשתמש ב "register" אשר אומר לקומפיילר לשמור את המשתנה בתוך אוגר, ולא בזכרון, בד"כ אופטימיזציה אוטומטית של פונקציות כמו שאתה הראית אמורה לעשות דברים דומים, אבל כמו שאמרתי, אתה יכול לעשות את זה.
void swap (register int *a,register int *b);
יגרום לכך שהפרמטרים לפונקצייה יעברו באוגרים.

ד"א, כשאתה קורא לפונקצייה קורים הדברים הבאים (בלי להכנס לפרטים):
דחיפת הפרמטרים למחסנית
דחיפת אוגר הפקודות למחסנית
דחיפת אוגר הבסיס למחסנית
העתקת אוגר המחסנית לאוגר הבסיס
ואז שחזור של כל מה שאמרתי עד עכשיו (פעולות הפוכות)

לכן, כמו שאמרתי, עדיף לך במקרים האלה להשתמש במאקרו, אשר יחסוך את כל ה overhead הזה. במיוחד שאתה אפילו לא צריך את המקום הנוסף שמוקצה, אתה אשכרה רוצה פשוט לבצא פעולה על שני משתנים (ולכן הרי אתה מעביר את הכתובות שלהם, כי אתה רוצה שינוי בערך).

או בקיצור, במקרה הזה, עדיף מאקרו, לא סתם בכל ספר לימוד C שתראה הפונקצייה swap היא תמיד מאקרו


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ldan192 
חבר מתאריך 14.9.08
95119 הודעות
   17:27   24.09.09   
אל הפורום  
  9. מבלי לשכוח שמערכת ההפעלה עושה בערך כפול מזה  
בתגובה להודעה מספר 8
 
תוך כדי context switching אפילו מאות פעמים בשניה.


בברכה,
עידן


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
TTAsnn

   13:46   25.09.09   
אל הפורום  
  14. ממש לא קשור  
בתגובה להודעה מספר 9
 
   אז מה אם המערכת הפעלה עושה כפול מזה?
זה עדיין עוד פעולות, ושוב, לא מדובר על פעולה שתיים, אלא על swap שיכול לקרות 10000000 פעמים בתוך לולאה שממיינת מערך באורך 10000000.
זה כמובן לא נכון במקרים של פונקציות אחרות, ולכן דיברתי רק על הפונקציה swap.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ldan192 
חבר מתאריך 14.9.08
95119 הודעות
   23:33   25.09.09   
אל הפורום  
  15. מה שאני אומר זה שבמקרה הזה זה זניח, וכמו לכל דבר  
בתגובה להודעה מספר 14
 
לשימוש בפונקציות במקום איטרציות יש יתרונות וגם להיפך הוא הנכון.
הכל תלוי בשימושים באותו רכיב תוכנה.


בברכה,
עידן


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ronen333 
חבר מתאריך 20.2.03
6069 הודעות
   21:18   24.09.09   
אל הפורום  
  10. כע אני יודע  
בתגובה להודעה מספר 8
 
   אבל אני עושה כעקרון מה שביקשו ממני. וכמו שאמרתי זה סתם לנסות לפתח הרגלים.. בתכל'ס אני יודע שזה לא כזה מועיל ברמות.
בנתיים צריך לכתוב את התרגילים בסי טהור אז אני לא מערבב בהן אסמבלי(אל תתפוס אותי במשפט הזה, אני יודע שהוא לא נכון).

וחוץ מזה.. טוב שעשיתי את הטעות. C היא שפה שחדשה לי יחסית ובזכות הטעות הזאת אני לא אפול בה שוב במקרים אחרים.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Deuce 
חבר מתאריך 1.9.08
6225 הודעות
   00:24   25.09.09   
אל הפורום  
  11. מכתב  
בתגובה להודעה מספר 10
 
שים לב רק שניתן להצהיר ב-C על משתנים מסוג register בידיוק כמו שאפשר להכריז על משתנים כ-static (יש עוד סוגים נוספים) - שווה להכיר.






                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
TTAsnn

   13:38   25.09.09   
אל הפורום  
  13. בדיוק, באופן כללי, חשוב להכיר לעומק את סביבת העבודה.  
בתגובה להודעה מספר 11
 
  


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
TTAsnn

   13:37   25.09.09   
אל הפורום  
  12. מכתב  
בתגובה להודעה מספר 10
 
   מי ביקש את זה ממך? בכל מקרה, הפואנטה שלי היא, תחשוב בגדול, שינויים קטנים במקומות שוליים לא עושים הבדל, וחבל להתעכב עליהם.
בקשר ל סי טהור מול אסמבלי, בעקרון לשלב אסמבלי עושה דבר אחד גרוע מאוד, גורם לקוד לך שלא להיות נייד, כלומר, לא תוכל לקמפל אותו על פלטפורמות אחרת, וזה רע רע רע (לפחות כאפשר להמנע) כמובן שיש מקרים בהם אין ברירה וחייבים את התוספת ביצועים של אסמבלי, אז כותבים באסמבלי, אבל בכל מקרה שהוא לא כתיבת קרנל או מערכת הנחייה לטילים, אפשר לוותר על שילוב אסמבלי

ברור שטוב שעשית את הטעויות, טעויות זה ממש טוב (כל עוד אף אחד לא מת\נפצע קשה) מטעויות לומדים דברים מגניבים, ד"א, גם מטעויות של אחרים לומדים דברים מגניבים, אני לדוגמא לא הייתי חושב על מקרה כזה אם לא הייתי רואה את הקוד הזה שלך, אז גם אני החכמתי.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

תגובה מהירה  למכתב מספר: 
 
___________________________________________________________________

___________________________________________________________________
למנהלים:  נעל | תייק בארכיון | מחק | העבר לפורום אחר | מחק תגובות | עגן אשכול
       



© כל הזכויות שמורות ל-רוטר.נט בע"מ rotter.net