תרגיל בית מספר 1#

‫אוניברסיטת תל אביב ‪ -‬בית הספר למדעי המחשב‬
‫מבוא מורחב למדעי המחשב‪ ,‬אביב ‪2014‬‬
‫תרגיל בית מספר ‪ - 2‬להגשה עד ‪ 20‬במרץ בשעה ‪23:55‬‬
‫קראו בעיון את הנחיות העבודה וההגשה המופיעות באתר הקורס‪ ,‬תחת התיקייה‬
‫‪ .assignments‬חריגה מההנחיות תגרור ירידת ציון ‪ /‬פסילת התרגיל‪.‬‬
‫הנחיות והערות ספציפיות לתרגיל זה‪:‬‬
‫הגשה‪:‬‬
‫• תשובות לשאלות מילוליות תוגשנה בקובץ ‪ pdf‬יחיד‪.‬‬
‫•‬
‫מימושים לפונקציות יש להוסיף לקובץ השלד )‪ (skeleton2.py‬המצורף לתרגיל זה‪ .‬אין לצרף‬
‫לקובץ ה ‪ py‬את הקוד ששימש לפתרון יתר השאלות‪.‬‬
‫לא לשכוח לשנות את שם הקובץ למספר ת"ז שלכם לפני ההגשה‪ ,‬עם סיומת ‪.py‬‬
‫•‬
‫בסה"כ מגישים שני קבצים בלבד‪ .‬עבור סטודנט שמספר ת"ז שלו הוא ‪ 012345678‬הקבצים‬
‫שיש להגיש הם ‪ 012345678.pdf‬ו‪.012345678.py -‬‬
‫•‬
‫הקפידו לענות על כל מה שנשאלתם‪.‬‬
‫•‬
‫בתרגיל זה ניתן להניח כי הקלט לפונקציות אותן תכתבו תקין‪ ,‬כלומר אין צורך לבדוק את‬
‫תקינותו‪.‬‬
‫•‬
‫תשובות מילוליות והסברים צריכים להיות תמציתיים‪ ,‬קולעים וברורים‪.‬‬
‫להנחיה זו מטרה כפולה‪:‬‬
‫‪ .1‬על מנת שנוכל לבדוק את התרגילים שלכם בזמן סביר‪.‬‬
‫‪ .2‬כדי להרגיל אתכם להבעת טיעונים באופן מתומצת ויעיל‪ ,‬ללא פרטים חסרים מצד אחד‬
‫אך ללא עודף בלתי הכרחי מצד שני‪ .‬זוהי פרקטיקה חשובה במדעי המחשב‪.‬‬
‫עמ' ‪ 1‬מתוך ‪7‬‬
‫‪CC BY-NC-SA 3.0‬‬
‫אוניברסיטת תל אביב ‪ -‬בית הספר למדעי המחשב‬
‫מבוא מורחב למדעי המחשב‪ ,‬אביב ‪2014‬‬
‫שאלה ‪1‬‬
‫אלגוריתם שמבצע את פעולתו בַּ מָּ קום )‪ (in-place algorithm‬הוא אלגוריתם שמעתיק לכל היותר‬
‫כמות קבועה מהקלט שלו למשתני עזר )ב"כמות קבועה" הכוונה לכמות שאינה תלויה בגודל‬
‫הקלט(‪.‬‬
‫בפרט‪ ,‬אלגוריתם כזה לא יוצר העתק של הקלט שלו‪ ,‬אלא משנה אותו במידת הצורך‪.‬‬
‫ראשית‪ ,‬נבחן בהקשר זה את פעולת היפוך סדר באיברים של רשימה נתונה בשם ‪.lst‬‬
‫א‪.‬‬
‫ב‪.‬‬
‫ג‪.‬‬
‫ד‪.‬‬
‫האם הפקודה ]‪ lst = lst[ : :-1‬הופכת את סדר האיברים במקום? הסבירו בקצרה את‬
‫תשובתכם‪.‬‬
‫האם הפקודה )(‪) lst.reverse‬המתודה ‪ reverse‬של המחלקה ‪ (list‬הופכת את סדר‬
‫האיברים במקום? מה מחזירה הפונקציה? הסבירו בקצרה את תשובתכם‪.‬‬
‫האם ניתן לכתוב פונקצית ‪ reverse‬במקום עבור מחרוזת? הסבירו‪.‬‬
‫הוסיפו לקובץ השלד המצורף מימוש לפונקציה )‪ ,reverse_sublist(lst,start,end‬אשר‬
‫מקבלת רשימה ושני אינדקסים‪ ,‬והופכת במקום את סדר האיברים בחלק הרשימה‬
‫שמתחיל באינדקס ‪ start‬ונגמר באינדקס ‪.end-1‬‬
‫לשם הפשטות ניתן להניח כי )‪.0<=start<end<=len(lst‬‬
‫דוגמאות הרצה‪:‬‬
‫]‪>>> lst = [1, 2, 3, 4, 5‬‬
‫)‪>>> reverse_sublist (lst,0,4‬‬
‫‪>>> lst‬‬
‫]‪[4, 3, 2, 1, 5‬‬
‫]"‪>>> lst = ["a","b‬‬
‫)‪>>> reverse_sublist (lst,0,1‬‬
‫‪>>> lst‬‬
‫]"‪["a", "b‬‬
‫כעת נדון בפעולת ה ‪-k‬סיבוב של רשימה‪.‬‬
‫בהנתן פרמטר ה ‪- k‬סיבוב‪ ,‬פעולת ה ‪-k‬סיבוב על רשימה באורך ‪ m‬מוגדרת באופן הבא‪:‬‬
‫הרשימה תסודר מחדש כך שאיבר שהופיע באינדקס ‪ i‬יועתק לאינדקס ‪.(i+k)mod m‬‬
‫לדוגמה‪,‬‬
‫אם נבצע על הרשימה ]‪-1 [1,2,3,4,5‬סיבוב נקבל ]‪[5,1,2,3,4‬‬
‫אם נבצע על הרשימה ]‪-2 [1,2,3,4,5‬סיבוב נקבל ]‪[4,5,1,2,3‬‬
‫ואם נבצע על הרשימה ]‪-(-1) [1,2,3,4,5‬סיבוב נקבל ]‪.[2,3,4,5,1‬‬
‫שימו לב שפעולת הסיבוב מעתיקה לתוך כל תא איבר יחיד‪ .‬בנוסף‪ ,‬הפרמטר ‪ k‬חייב להיות שלם‪,‬‬
‫אבל יכול להיות שלילי )כמו בדוגמה האחרונה(‪.‬‬
‫ה‪ .‬הוסיפו לקובץ השלד מימוש לפונקציה )‪ ,rotate1(lst‬אשר מקבלת רשימה ומבצעת‬
‫‪-1‬סיבוב של אבריה במקום‪.‬‬
‫דוגמת הרצה‪:‬‬
‫]‪>>> lst = [1, 2, 3, 4, 5‬‬
‫)‪>>> rotate1 (lst‬‬
‫‪>>> lst‬‬
‫]‪[5, 1, 2, 3, 4‬‬
‫עמ' ‪ 2‬מתוך ‪7‬‬
‫‪CC BY-NC-SA 3.0‬‬
‫אוניברסיטת תל אביב ‪ -‬בית הספר למדעי המחשב‬
‫מבוא מורחב למדעי המחשב‪ ,‬אביב ‪2014‬‬
‫ו‪ .‬הוסיפו לקובץ השלד מימוש לפונקציה )‪ ,rotatek_v1(lst,k‬אשר מקבלת רשימה ומבצעת‬
‫סיבוב‪ k-‬של אבריה במקום באמצעות קריאה לפונקציה )(‪ .rotate1‬ניתן להניח ש ‪ k‬שלם‪.‬‬
‫דוגמת הרצה‪:‬‬
‫]‪>>> lst = [1, 2, 3, 4, 5‬‬
‫)‪>>> rotatek_v1 (lst,2‬‬
‫‪>>> lst‬‬
‫]‪[4, 5, 1, 2, 3‬‬
‫ז‪ .‬הוסיפו לקובץ השלד מימוש לפונקציה )‪ ,rotatek_v2(list,k‬אשר מקבלת רשימה ומבצעת‬
‫סיבוב‪ k-‬של אבריה במקום באמצעות קריאה לפונקציה )(‪.reverse_sublist‬‬
‫פלט לדוגמה‪ :‬בדיוק כמו בסעיף הקודם‪ ,‬בשינוי שם הפונקציה‪.‬‬
‫)רמז‪ :‬התבוננו ברשימה‬
‫]‪[1,2,3,4,5‬‬
‫ובתוצאת הסיבוב‪ 2-‬שלה‬
‫]‪.[4,5,1,2,3‬‬
‫כיצד ניתן להפוך את הרשימה הראשונה לשנייה באמצעות פעולות היפוך עוקבות ?(‪.‬‬
‫הנחיות הגשה‪:‬‬
‫ בקובץ ה ‪ pdf‬הגישו‪:‬‬‫• את התשובות לסעיפים א'‪,‬ב'‪,‬ג'‪.‬‬
‫ בקובץ ה ‪ py‬הגישו‪:‬‬‫• את הפונקציות שמימשתם בסעיפים ד'‪,‬ה'‪,‬ו'‪,‬ז'‪.‬‬
‫עמ' ‪ 3‬מתוך ‪7‬‬
‫‪CC BY-NC-SA 3.0‬‬
‫אוניברסיטת תל אביב ‪ -‬בית הספר למדעי המחשב‬
‫מבוא מורחב למדעי המחשב‪ ,‬אביב ‪2014‬‬
‫שאלה ‪2‬‬
‫בשאלה זו נבצע פעולת חישוב על רשימה של מספרים‪ .‬כיוון שרשימת המספרים עשויה להיות‬
‫ארוכה מאד‪ ,‬הכרחי לממש את הפעולה באופן יעיל‪.‬‬
‫נגדיר סכום מתחלף )‪ (alternating sum‬של סדרת מספרים ‪ 𝑎0 , 𝑎1 , … , 𝑎𝑛−1‬כתוצאת החישוב‬
‫‪n‬‬
‫‪.∑n−1‬‬
‫… ‪𝑖=0 (−1) 𝑎𝑖 = 𝑎0 − 𝑎1 + 𝑎2 − 𝑎3‬‬
‫א‪ .‬מצאו במספר ‪ 5200,000‬סכום מתחלף מקסימלי של ‪) 50,000‬חמישים‪-‬אלף( ספרות עוקבות‪.‬‬
‫שימו לב‪ :‬אנו מגדירים את סדר הספרות במספר משמאל לימין‪ ,‬ולכן בכל רצף עוקב הספרה‬
‫השמאלית ביותר היא זו שתסומן כ ‪ 𝑎0‬ותפתח את הסכום בסימן חיובי‪.‬‬
‫לדוגמה‪ ,‬המספר ‪ 43805‬מכיל את הסכומים המתחלפים באורך ‪ 3‬הבאים‪:‬‬
‫‪4-3+8‬‬
‫‪3-8+0‬‬
‫‪8-0+5‬‬
‫על הריצה להסתיים תוך לכל היותר דקה אחת על מחשב סביר )למשל המחשבים בחוות‬
‫המחשבים בבניין שרייבר(‪.‬‬
‫בקובץ השלד ממשו את הקוד כפונקציה‪ .‬שם הפונקציה יהיה )‪ altsum_digits(n, d‬והיא‬
‫תחזיר את הסכום המקסימלי של ‪ d‬ספרות סמוכות במספר ‪.n‬‬
‫דוגמת הרצה‪:‬‬
‫)‪>>> altsum_digits(5**36, 12‬‬
‫‪18‬‬
‫הדרכה‪:‬‬
‫נסו לחשוב בתחילה כיצד הייתם מחפשים באופן יעיל את הסכום הרגיל )לא מתחלף( של ‪d‬‬
‫ספרות עוקבות‪ .‬בפרט‪ ,‬שימו לב שעל מנת שהתכנית תרוץ מספיק מהר‪ ,‬לא ניתן לממש את‬
‫הפתרון הטריוויאלי‪ ,‬אשר סוכם בנפרד כל תת סדרה רציפה באורך ‪ .d‬חשבו איך בהינתן‬
‫הסכום של ‪ d‬הספרות הראשונות ניתן לחשב ביעילות את הסכום של ‪ d‬הספרות אשר‬
‫מתחילות בספרה השנייה בסדרה‪.‬‬
‫ב‪ .‬נסמן ב ‪ nmult, nminus, nplus‬את מספר פעולות החיבור‪ ,‬חיסור וכפל )בהתאמה(‬
‫שהפונקציה שכתבתם בסעיף א' מבצעת בריצה נתונה‪.‬‬
‫רשמו ביטויים מתמטיים )פשוטים( למספרים אלה כפונקציה של הפרמטרים ‪ n‬ו ‪.d‬‬
‫ניתן להשמיט מהחישוב כל פעולה שבוצעה מספר קבוע של פעמים )כלומר שאינה נמצאת‬
‫בתוך לולאה כלשהי(‪.‬‬
‫הנחיות הגשה‪:‬‬
‫ בקובץ ה ‪ pdf‬הגישו‪:‬‬‫• את התשובה שחישבתם בסעיף א'‬
‫• את התשובה לסעיף ב'‬
‫ בקובץ ה ‪ py‬הגישו‪:‬‬‫• את הפונקציה שכתבתם כדי לענות על סעיף א'‬
‫עמ' ‪ 4‬מתוך ‪7‬‬
‫‪CC BY-NC-SA 3.0‬‬
‫אוניברסיטת תל אביב ‪ -‬בית הספר למדעי המחשב‬
‫מבוא מורחב למדעי המחשב‪ ,‬אביב ‪2014‬‬
‫שאלה ‪3‬‬
‫מספר מושלם )‪ (perfect number‬הינו מספר שלם חיובי ששווה לסכום המחלקים שלו‪ ,‬כאשר לא‬
‫כוללים בסכום את המספר עצמו )קבוצה זו נקראת גם קבוצת המחלקים‪-‬ממש של המספר(‪.‬‬
‫לדוגמה‪ ,‬המספר ‪ 6‬הוא מספר מושלם מכיוון שמתקיים‪. 6 = 3 + 2 + 1 :‬‬
‫לעומת זאת‪ ,‬המספר ‪ 4‬אינו מספר מושלם משום שמתקיים‪. 4 ≠ 2 + 1 :‬‬
‫א‪ .‬הוסיפו לקובץ השלד המצורף מימוש לפונקציה )‪ ,sum_divisors(n‬אשר מקבלת מספר שלם‬
‫חיובי ‪ ,n‬ומחזירה את סכום המחלקים‪-‬ממש שלו‪.‬‬
‫דוגמת הרצה‪:‬‬
‫)‪>>> sum_divisors(6‬‬
‫‪6‬‬
‫)‪>>> sum_divisors(4‬‬
‫‪3‬‬
‫הנחייה מחייבת‪ :‬על הפונקציה לרוץ ב– )𝑛√(𝑂‪ .‬מימוש יעיל פחות יגרור זמן ריצה ארוך‬
‫בסעיף ג' )בהמשך השאלה(‪ ,‬ולכן יאבד נקודות‪.‬‬
‫ב‪ .‬הוסיפו לקובץ השלד המצורף מימוש לפונקציה )‪ ,is_perfect(n‬אשר מקבלת מספר שלם‬
‫חיובי ‪ ,n‬ומחזירה ערך בוליאני באופן הבא‪ :‬אם המספר ‪ n‬הינו מספר מושלם הפונקציה‬
‫תחזיר ‪ ,True‬אחרת תחזיר ‪.False‬‬
‫דוגמת הרצה‪:‬‬
‫)‪>>> is_perfect(6‬‬
‫‪True‬‬
‫)‪>>> is_perfect(4‬‬
‫‪False‬‬
‫ג‪ .‬נרצה לדעת כמה מספרים מושלמים שקטנים מ ‪ 100,000‬קיימים‪.‬‬
‫הוסיפו לקובץ השלד המצורף מימוש לפונקציה )‪ ,count_perfect_numbers(limit‬אשר‬
‫מקבלת מספר חיובי ‪ ,limit‬ומחזירה כמה מספרים מושלמים קטנים או שווים ל ‪.limit‬‬
‫בנוסף‪ ,‬את התוצאה שקיבלתם עבור ‪ limit = 100,000‬הוסיפו לקובץ ה ‪. pdf‬‬
‫הנחיות הגשה‪:‬‬
‫ בקובץ ה ‪ pdf‬הגישו‪:‬‬‫• את התשובה שחישבתם בסעיף ג'‬
‫ בקובץ ה ‪ py‬הגישו‪:‬‬‫• את הפונקציות שכתבתם כדי לענות על סעיפים א'‪,‬ב'‪,‬ג'‬
‫עמ' ‪ 5‬מתוך ‪7‬‬
‫‪CC BY-NC-SA 3.0‬‬
‫אוניברסיטת תל אביב ‪ -‬בית הספר למדעי המחשב‬
‫מבוא מורחב למדעי המחשב‪ ,‬אביב ‪2014‬‬
‫שאלה ‪4‬‬
‫בשאלה זו נעסוק בהיבטים שונים של ייצוג מספרים בבסיסים שונים‪.‬‬
‫א‪ .‬כמה ספרות יש למספר ‪ 51209‬בייצוג עשרוני ?‬
‫ענו על השאלה באמצעות הנוסחה שראיתם בשיעור )שקף ‪ 33‬במצגת שיעור ‪ ,(4‬וגם באמצעות‬
‫הפיכת המספר מ‪ integer-‬ל‪ ,string-‬ומדידת אורך המחרוזת באמצעות )(‪.len‬‬
‫צרפו לקובץ ה ‪ pdf‬את התשובה‪ ,‬וכן שתי שורות קוד בודדות – אחת לכל אופן פתרון ‪-‬‬
‫שמבצעות את החישוב‪.‬‬
‫הדרכה‪ :‬מומלץ להשתמש בפונקציה )‪ log(x,base‬של המודול ‪ ,math‬אשר מחשבת את‬
‫הלוגריתם של ‪ x‬בבסיס ‪.base‬‬
‫ב‪ .‬ממשו את הפונקציה )‪ ,add_hex(A, B‬אשר מקבלת שתי מחרוזות המייצגות מספרים בייצוג‬
‫הקסדצימלי )כלומר בבסיס ‪ ,(16‬ומחזירה את המחרוזת שמייצגת את תוצאת החיבור שלהם‪,‬‬
‫גם היא בייצוג הקסדצימלי‪.‬‬
‫ניתן להניח כי מחרוזות הקלט מייצגות מספרים חוקיים בבסיס ‪ ,16‬ולפיכך כוללות רק‬
‫ספרות ואת האותיות ‪) a,b,c,d,e,f‬שימו לב‪ :‬האותיות ניתנות ב ‪.(lower case‬‬
‫דוגמת הרצה‪:‬‬
‫)"‪>>> add("a5", "17‬‬
‫'‪'bc‬‬
‫להלן המחשה של אלגוריתם החיבור ‪ A+B‬על מספרים בבסיס ‪) 16‬בדומה לחיבור מספרים‬
‫עשרוניים עם נשא )‪:((carry‬‬
‫)‪(carried digits‬‬
‫‪1‬‬
‫)‪1 f 5 (A‬‬
‫‪+‬‬
‫)‪5 a (B‬‬
‫‪------------‬‬‫=‬
‫‪2 4 f‬‬
‫הנחיה‪:‬‬
‫‪ .1‬הטיפול בספרות ההקס דצימליות )חלקן ספרות "רגילות" וחלקן אותיות( לא יתבצע‬
‫באמצעות סדרה של משפטי תנאי‪ ,‬אלא באמצעות המרה מיידית‪ ,‬בדומה למה שראיתם‬
‫בתרגול ‪.3‬‬
‫‪ .2‬אין להמיר את המספרים ‪ A‬או ‪ B‬מבסיס לבסיס‪ .‬בפרט‪ ,‬אין להשתמש כלל בפונקציה ‪int‬‬
‫של פייתון‪ ,‬בפונקציה ‪ convert_base‬שראינו בתרגול וכו'‪ .‬יש לממש את האלגוריתם בהתאם‬
‫להמחשה‪ :‬ישירות באמצעות לולאות‪.‬‬
‫עמ' ‪ 6‬מתוך ‪7‬‬
‫‪CC BY-NC-SA 3.0‬‬
‫אוניברסיטת תל אביב ‪ -‬בית הספר למדעי המחשב‬
‫מבוא מורחב למדעי המחשב‪ ,‬אביב ‪2014‬‬
‫ג‪ .‬נתבונן שוב בקוד אשר הובא בהרצאה להעלאה בחזקה באמצעות ‪:iterated squaring‬‬
‫‪def power(a,b):‬‬
‫"""‪"""computes a**b using iterated squaring‬‬
‫‪result = 1‬‬
‫‪while b>0:‬‬
‫‪if b%2 == 1: # b is odd‬‬
‫‪result = result*a‬‬
‫‪a = a*a # squares power of a‬‬
‫‪b = b//2 # removes least significant bit of b‬‬
‫‪return result‬‬
‫נרצה להבין את הקשר בין מספר הפעולות שמבצע האלגוריתם לבין המספרים ‪ a‬ו ‪.b‬‬
‫לשם כך‪ ,‬הוסיפו בתוך הפונקציה )אך מבלי לשנות את הקוד הקיים( שורות אשר‬
‫תספורנה‬
‫‪ (1‬כמה פעמים בוצעה לולאת ה ‪) while‬נסמן ב ‪(n1‬‬
‫‪ (2‬כמה פעמים התקיים התנאי ב ‪) if‬נסמן ב ‪(n2‬‬
‫‪ (3‬כמה פעולות כפל ביצעה הפונקציה )נסמן ב ‪(n3‬‬
‫הריצו את הפונקציה עבור הקלטים‬
‫‪a=3, b=2**10‬‬
‫‪a=3, b=2**10-1‬‬
‫‪a=30, b=2**10‬‬
‫‪a=30, b=2**10-1‬‬
‫ורשמו בקובץ ה ‪ pdf‬את ‪ n1,n2,n3‬עבור כל אחת מההרצות‪.‬‬
‫בנוסף‪ ,‬רשמו ביטוי מתמטי מפורש עבור ‪ n1, n2, n3‬כפונקציה של‬
‫‪=k‬מספר הביטים בייצוג הבינארי של ‪b‬‬
‫ו ‪=m‬מספר ה‪ 1-‬בייצוג הבינארי של ‪.b‬‬
‫כדאי כמובן לבדוק את הביטויים שלכם על הדוגמאות שלעיל‪.‬‬
‫הנחיות הגשה‪:‬‬
‫ בקובץ ה ‪ pdf‬הגישו‪:‬‬‫• את התשובה שחישבתם בסעיף א'‪ ,‬ואת שורות הקוד ששימשו אתכם בחישוב‬
‫• את תשובתכם לסעיף ג'‬
‫ בקובץ ה ‪ py‬הגישו‪:‬‬‫• את הפונקציה שמימשתם בסעיף ב'‬
‫סוף‪.‬‬
‫עמ' ‪ 7‬מתוך ‪7‬‬
‫‪CC BY-NC-SA 3.0‬‬