תכנות וזיהוי/התוכנה ממבט של הנדסת תוכנה
עקרונות בהנדסת תוכנה
עריכהישנם מספר עקרוֹנוֹת ראשיים בהנדסת תוֹכנה :
- קריאוּת - יצירת קוֹד קריא, להקלה על המתכנת להבין ולמצוא כל קטע.
- יעילוּת - יצירת פוּנקציוֹת יעילוֹת : משתמשוֹת במעט משאבי מחשב, פוֹעלוֹת מהר, וקצרוֹת.
- גמישוּת לשינויים - יצירת קוד שכל מתכנת אחר יוכל להמשיך לפתח אותו בקלוּת.
- שימוש יעיל בפונקציות ובמבני הנתונים שהשפה נותנת לך - לא לכתוב אותן מחדש.
- ידידוּתיוּת למשתמש . עיין כאן בפרק יצירת ממשק ידידותי.
- אחידוּת - להישאר עד כמה שאפשר באותה שיטה לאורך כל התוכנה.
- גלובליזציה- תוכנה שיכולה לפעול על כמה שיותר מכשירים, ולהשתלב עם כמה שיותר תוכנות אחרות.
- תכנוּת מהיר - בסופו של דבר רוצים תוצאה (אפילו לא הכי טובה) כמה שיותר מהר.
- אמינוּת - לדוגמה: התוכנה קוראת תמיד את האות - 'ה' נכון .
- תכנות על פי עקרונות של תכנות מונחה עצמים ולא על פי העקרונות המיושנים של תכנות פונקציונלי.
לפעמים העקרונות סותרים זה את זה כמו שנראה כאן בדוגמאות מהתוכנה,
ולפעמים עקרונות אחרים סותרים עקרונות אלו כגון :
- שמירה על זכויות יוצרים.
- הנאה בתכנות.
- השתלמות בתכנות.
עיון במיון
עריכההקדמה
עריכהכדי להציג דיון בהנדסת תוכנה קודם הדיון יוצג, ורק אחר כך יוסברו המונחים המקצועיים.
הצגת הדיון
עריכההמיון בתוכנה הוא מיון בועות פשוט , לא משתמשים במיון מהיר כמו בדוגמת האנימציה
(כאן בעמוד משמאל ) אף על פי שבמיון מהיר המערך מתמיין בפחות פעולות, ולכן הוא יותר יעיל.
הסיבה היא שהאלגוריתם של מיון מהיר הוא הרבה יותר ארוך ולכן צריך לכתוב בשבילו יותר שורות קוד.
וזה יוצר בעיות בעקרונות של קריאות ותכנות מהיר.
בכל זאת היה אפשר להשתמש בפונקצייה qsort הנמצאת בספרייה stdlib.h אבל אני לא משתמש בה
כי עדיין לא ניסיתי אותה , ולכן שימוש בה יוצר חוסר אמינות בתוכנה.
אולי כדי להשתלם בחומר בכל זאת נלמד להשתמש בה ?
משום שהכי חשוב לסיים את התוכנה מהר לא נשתמש בה .
ולא מובן מה מציבים במשתנים הללו :
void qsort (const void* pTheBase, size_t cntOfTheObjects, size_t sizeOfTheObject,
_pfunccmp_t pfuncOfCmp);
אלא אם כן מוצאים תיעוד של הפונקציה לדוגמה בגלישה באינטרנט.
לא מתכנתים את הפונקציה של מיון בועות על פי עקרונות של תכנות מונחה עצמים : לא יוצרים מארז
בו יוצרים כימוס לפונקציה, ויוצרים פונקציה כללית המתאימה להרבה סוגי נתונים , כי תכנות מונחה עצמים
מתאים לסביבה בה אפשר לפרק את התוכנה לחלקים בעלי משמעות שיש מעט קלט פלט בניהם , ואילו לחלק נכבד מהתוכנה
שלנו ממשק חלוני בו יש תפריט והרבה ופקדים . ולכן נצטרך לתכנת חלק מהתוכנה על פי עקרונות של תכנות פונקציונאלי
וחלק על פי עקרונות של תכנות מונחה עצמים, שגורם לחוסר אחידות בתוכנה. בכל זאת מי שרוצה להשתלם בתכנות מונחה
עצמים יכול להתחיל את התוכנה מהדוגמה הגרפית באתר של לימוד וידאו המוזכרת בפרקים הקודמים הבנויה על פי עקרונות של תכנות מונחה עצמים.
כשאומרים מיון בתוכנה - למה מתכוונים ?
עריכהכשמזכירים מיון בקשר לתוכנה בדרך כלל מתכוונים לסדרת מספרים בשורה(הנקראת מערך) שצריך לסדר אותם בסדר עולה, לכל מספר יש מספר נוסף המיצג את מיקומו בשורה (הוא ניקרא אינדקס המערך).
מה עושים עם נשארות כפילויות בסוף המיון?
עריכה- לפעמים צריך להשאיר כפילויות באותו סדר שהם היו בקלט.
- לפעמים צריך להשמיט כפילויות כמו אצלנו בתוכנה.
- לפעמים צריך להשאיר כפילויות אבל הסדר לא משנה (עיין בציור משמאל).
איך פועלים מיון בועות ומיון מהיר ?
עריכההסבר מיון קל להבנה כהקדמה
עריכהלפני שנסביר אותם נסביר מיון אחר שאני מכנה אותו "מיון קל להבנה".
הוא דומה לשני המיונים האחרים כי הוא פועל על החלפת אברים במערך.
הוא בדרך כלל הוא לא יעיל כי הוא צורך הרבה בדיקות והרבה החלפות. הוא פועל בעזרת שני דברים :
- בדיקה.
- החלפה.
- בודקים בו כל שני אברים סמוכים במערך (בדרך כלל שני מספרים ובודקים את גודלם).
- אם הם לא מסודרים מחליפים אותם אחד בשני .
- כשמגיעים לסוף המערך בודקים אם הייתה איזו שהיא החלפה בין שני אברים:
- אם לא סימן שהמערך ממוין.
- אם כן חוזרים על התהליך שוב מתחילת המערך.
התהליך במיון בועות
עריכההוא נקרא מיון בועות כי בכל שלב מעלים למעלה את חוסר הסדר,
כמו שבועות אויר עולות למעלה.
היתרונות במיון בועות:
- כתוב קצר.
- אין בדיקות.
- מעט החלפות לעומת "מיון קל להבנה".
- לא צריך לתפוס מקום נוסף בזיכרון המחשב לעוד מערכי עזר.
התהליך :
- משווים את האיבר הראשון במערך אם כל האברים הבאים אחריו במערך.
- במקרה של חוסר סדר מחליפים.
- את אותו הדבר עושים על האיברים הבאים במערך לפי הסדר: השני השלישי וכולי.
מיון בועות המופיע בתוכנה :
void SumAllAttsInL()
{int MySign,MoneKeys,TheAtt,Locate;
int AllAtts[AllComps],Atts,Save,Locate2;
.
.
.
// מיון בועות
for(Locate=0;Locate<Atts;Locate++)
for(Locate2=Locate+1;Locate2<Atts;Locate2++)
if(AllAtts[Locate2]<AllAtts[Locate])
{Save=AllAtts[Locate];
AllAtts[Locate]=AllAtts[Locate2];
AllAtts[Locate2]=Save;
}
}
התהליך במיון מהיר
עריכה- בודקים אם גודל המערך קטן מ - 7 איברים.
- אם כן ממינים אותו במיון בועות.
- אם לא בוחרים 3 איברים מהמערך (בדרך כלל בחירה רנדומלית - אקראית).
- מוצאים את הגודל הממוצע של 3 איברי במערך, הגודל הממוצע נקרא "איבר הציר".
- פותחים 2 מערכים חדשים (בדרך כלל כל אחד תופס מקום כמו המערך הקודם).
- במערך אחד מציבים את האיברים הגדולים מאיבר הציר.
- במערך השני מציבים את האיברים הקטנים או השווים לאיבר הציר.
- על כל מערך בנפרד מפעילים את התהליך מהתחלה (שלב 1).
- בתוך מערך בגודל המערך הראשוני מסדרים את כל המערכים לפי הסדר שהם פוצלו.
היכן בתוכנה מוצג מיון ?
עריכהבתוכנה כל עצם מובדל מעצם אחר על יד כמה תכונות, בתוכנה מוצגת רשימה מסודרת של התכונות שהמחשב
בחר, ואם המשתמש רוצה לראות איך תכונה מסוימת מבדילה בין עצם אחד לשני הוא מפעיל את התכונה
על העצמים. כדי להגיע לרשימה מסודרת צריך למיין את המספרים הסידוריים המיצגים תכונות.
מבוא לתכנות מונחה עצמים
עריכהבשנות ה - 70 התכנות הפונקציונאלי היה נפוץ , כל חברה גדולה הייתה מחזיקה תכנת , ועיקר
תפקידו היה לתחזק את התוכנה - לשנות אותה על פי צרכי הארגון, אבל מה שהסתבר שרוב התכנתים
עובדים כמו גרז'ניקים : על כל תיקון קטן הורסים הרבה חלקים אחרים של התוכנה.
אחד הפתרונות היה פזילה לכיוון עקרונות תעשיית האלקטרוניקה, כי כשקונים שבב אלקטרוני בדרך כלל
הוא עושה את מה שנדרש לעשות, ואם רוצים לשנות את המערכת קונים שבב אחר יותר מתאים,
ובדרך כלל זה לא הורס את המערכת.
איך יוצרים תוכנה הבנויה כמו שבב אלקטרוני ?
עריכהאוגדים קבוצת נתונים (לדוגמה : פונקציות) עם קשר מהותי בתוך חלק מהתוכנה הנקרא "מארז" או "מחלקה" (באנגלית Class או Package ), המארז מכיל שני חלקים עיקריים:
- אופיין המארז (באנגלית Specification), החלק בו מוסבר איך משתמשים בפונקציות, מקביל בשבב למה שכתוב על השבב.
- גוף המארז (באנגלית Class body), החלק בו כתובות הפונקציות, מקביל בשבב למבנה השבב.
גוף המארז בנוי כך שפונקציות מחוץ למארז לא יכולות לשנות את מבנהו, בדומה לשבב שבדרך כלל המשתמש לא משנה אתו.לשמירה על מבנה המארז קוראים כימוס. יוצרים כמה מארזים כל אחד נקרא על פי הרעיון המאגד את נתוניו אחד נקרא "מיון" (שים לב! שמות עצם) השני נקרא "פס הגלילה" וכו'
המארזים מדברים אחד עם השני כמו שפונקציות מתקשרות זו עם זו.
כמו שבונים שבב כך שיתאים לכמה שיותר אפשרויות, כך בדרך כלל מנסים להתאים כל מארז לכמה שיותר סוגי נתונים.
עיון בדוגמת שיבוץ במערך ערכי דגימת התמונה
עריכה/* דגום חלק מהאות
שמור את ערכי הבהירות במערך */
void SelectPicInC(HDC hdcMe,
float X1,float Y1,float X2,float Y2,
int TheImage1[RowsPerPic][ColsPerPic],
LineBrightness FilterType,int FilterN )
{int PixPicCol,PixPicRow=0;
int xcordi,ycordi,TheColor;
float MyPixPerRowDot,MyPixPerColDot;
InitiateMyMatInC(TheImage1);
MyPixPerRowDot=(X2-X1)/fXSections;
MyPixPerColDot=(Y2-Y1)/fYSections;
for(PixPicRow=0;PixPicRow<RowsPerPic;PixPicRow++)
for(PixPicCol=0;PixPicCol<ColsPerPic;PixPicCol++)
{xcordi=int(X1)+
int(MyPixPerColDot*PixPicCol);
ycordi=int(Y1)+
int(MyPixPerRowDot*PixPicRow);
TheColor=MyPixelColorInC(hdcMe,xcordi,ycordi);
TheImage1[PixPicCol][PixPicRow] =TheColor;
} // אל תתן לוקטור לחדור
FillingGapsInC(TheImage1); // באלכסון דרך האות
if (FilterType !=AnyChange) // נקה את השינויים ברקע
EraseBackground(TheImage1,FilterN);
}
מבחינת קריאות
עריכההפונקציה SelectPicInC המוצגת למעלה, מושקעת בהערות, בצבעים המאפשרים להבחין בין מרכיבי הפונקציה ,
בהזחות שורה של לולאה בתוך לולאה ובשמות פחות או יותר בעלי משמעות בשפה האנגלית .
שם הפונקציה מסתיים ב- InC כדי לרמוז שהפונקציה נמצאת בקובץ Conclude.cpp.
למרות ההשקעה המרובה שגורמת לפגיעה במהירות התכנות, בכל זאת קשה להבין את מנגנון הפונקציה ,
ולכן יש פגיעה בגמישות לשינויים ,ובגלובליזציה.
האם תרשים זרימה יעזור ?!
עריכההיינו חושבים שבמקרה הזה תרשים זרימה היה יכול להסביר את מנגנון הפונקציה .
תרשים הזרימה המוצג כאן לא מספק מכמה סיבות :
- אף על פי שהוא תרשים זרימה שקיצצו ממנו את הקלט והפלט הוא מורכב וגדול.
- לא מובן מה הקשר בין הפעולות שבו לתוכנה.
- לכתוב תרשים זרימה כזה לוקח הרבה זמן.
אולי כדאי לפרק את תרשים הזרימה לכמה תרשימים
שבכל אחד מהם יוסברו משתני הקלט - פלט כמו בשרטוט השני .
גם זה לא מובן כי מורכבות התרשימים גדלה.
האם פחות משתנים בקלט הפונקציה יפתרו את הבעיה ?!
עריכהאולי כדאי לאגד את 4 משתני הקלט : ( X1 , Y1 ,X2 ,Y2 )
למשתנה מסוג RECT המכיל שתי נקודות שכל נקודה מוגדרת על ידי 2 משתנים.
גם זה לא קריא, כי קשה להבין מיד מה זה RECT, אולי זה קיצור של :
אפשרות | באנגלית | פירוש |
---|---|---|
1 | recto | עמוד ימני |
2 | rector | נשיא המכללה |
3 | rectum | פי הטבעת |
4 | rectify | לתקן |
5 | rectangle | מלבן |
6 | rectory | בית הכומר |
ונניח שמצאנו ש -rect זה קיצור
של rectangle - מלבן,
עדיין לא מובן איזה ערכים מיצגים 4 המספרים ,
ואפילו הבנו שהם קובעים את גבולות המלבן,
יש כמה אפשרויות לקבוע את גבולותיו ע"י 4 מספרים :
- נקודה שמאלית עליונה (2 מספרים) ונקודה ימנית תחתונה (2 מספרים) .
- נקודה שמאלית עליונה (2 מספרים) גובה ורוחב.
לי ידוע ש - RECT מוגדר כאפשרות ה-שנייה על פי שני מקומות :
- הוא מוגדר בקובץ windef.h שבא עם מהדר DEVCPP הנמצא בתיקייה Include .
- גלישה באינטרנט בחיפוש פירוש ל- RECT.
אולי אם נדע היכן קוראים לפונקציה זה יפתור את הבעיה ?
עריכהקוראים לפונקציה מהפונקציה SelectFileMatInL בקובץ AtLearn.cpp.
/* טען מערך בתמונת מופע של אוביקט*/
void SelectFileMatInL(HDC hdcMe,int Variant,int Object,
LineBrightness FilterKind, int ColorLimit )
Rc=PicLocationInL(Object,Variant);
SelectPicInC(hdcMe,
float(Rc.left),float(Rc.top),
float(Rc.right),float(Rc.bottom),// קודם רוחב ואחר כך גובה
OneImage,FilterKind,ColorLimit);
}
ושם מסתבר שמשתני המיקום מוגדרים בפונקציה PicLocationInL בקובץ LoadRects.cpp,
וגם מסתבר שהקבועים המגדירים את המיקום נמצאים במערך של קבועים בשם DataRects.
אחרי חיפוש מוצאים אותו בקובץ Myprocs.h .
מכאן יוצא שכדי להבין את הפונקציות צריך לדעת איזו פונקציה קוראת לאיזו פונקציה.
תרשים המקשר בין שמות הפונקציות לבין משתני הקלט פלט שלהן נקרא : "תרשים זרימת נתונים" או באנגלית
Data Flow Diagram או בראשי תיבות באנגלית : "DFD"
איך יודעים איזה פונקציה משתמשת בפונקציה הנידונה ?
עריכהעל ידי חיפוש בכל קבצי הקוד את שם הפונקציה. לדוגמה : אצלנו הפונקציה SelectFileMatInL (הנמצאת בקובץ AtLearn.cpp)
והפונקציה PerformenceInC ( נמצאת בקובץ Conclude.cpp) משתמשות בפונקציה SelectPicInC .
כשתופסים מחלון וידאו תמונה בעזרת התוכנה, כמעט תמיד נוספים לתמונה נקודות שחורות קטנטנות.
התוכנה בנויה לזהות אותיות, ומה שמבדיל בין האותיות לרקע, זה צבען הכהה. הנקודות השחורות
מתווספות לאותיות והורסות את הזיהוי. לנקודות הללו קוראים רעש או אבק (אנגלית Noise או Dust).
איך פותרים את בעיית הרעש ללא פגיעה בעקרונות הנדסת תוכנה ?
(הבעיה הזאת עדיין לא פתורה בקוד בהמשך הפרקים).
שיטה יעילה לכאורה
עריכהאחרי שדוגמים את התמונה לתוך מערך(עיין בפרק אלגורתמים נוספים),
בודקים במערך היכן יש נקודות שחורות שלא נוגעות בשום נקודה שחורה אחרת, ומחליפים אותם לנקודות לבנות.
השיטה הזאת יעילה לכאורה כי החלפת כמה מספרים במערך זה תהליך מאד מהיר.
אבל מי שפותר כך את הבעיה מראה שהוא לא מבין את התוכנה , כי המערך נוצר אחרי דגימת מספר נקודות מועט מהתמונה.
ולכן סביר שנקודה במערך היא חלק חשוב באות, לדוגמה: החלק השמאלי התחתון של האות - 'ה' .
שיטת SetPixel , GetPixel
עריכהעוברים על כל תמונת מפת הסיביות,
- מחפשים נקודות כהות שלא נוגעות בשום נקודה כהה בעזרת GetPixel.
- ומחליפים אותן ללבן בעזרת SetPixel.
איך משתמשים ב : SetPixel ו - GetPixel
עריכהSetPixel מקבל 4 משתנים מסוג : SetPixel (HDC,int,int,int) תפקידם :
SetPixel (צבע ,קואורדינטת הגובה של הנקודה , קואורדינטת הרוחב של הנקודה , מצביע לחלק הגרפי של החלון )
כדי לסמן שהצבע הוא שחור מציבים במקום משתנה הצבע את המספר 0.
להסבר פעולת GetPixel עיין בתוכנת זיהוי צבע.
כדי לדעת מה מציבים בשאר משתני GetPixel שים לב להקבלה בין שתי הפונקציות.
החיסרון בשיטת SetPixel , GetPixel
עריכהפעולה איטית מאד.
שיטת תמונת DIB
עריכההופכים את התמונה לקובץ DIB ואז מבצעים את ההחלפה. איך הופכים לקובץ DIB ואיך מוצאים את הנקודות בקובץ ?
עיין בסוף הפרק טיפול בתמונות מפת סיביות.