מבחן בקורס מבוא מורחב למדעי המחשב, CS1001.py ביה"ס למדעי המחשב, אונ' תל אביב סמסטר א' 2019, מועד א', 27/01/2019 מרצים: פרופ' דניאל דויטש, ד"ר אמיר רובינשטיין מתרגלים: מיכל קליינבורט, בן בוגין, נעם פרזנצ'בסקי משך הבחינה: 3 שעות. חומר עזר מותר: 2 דפי עזר )דו צדדיים( בגודל A4 כל אחד. במבחן 16 עמודים מודפסים בידקו שכולם בידיכן. בנוסף, בסוף הבחינה ישנו דף נוסף, ריק, לשימוש ב"מקרה חירום" בלבד. יש לכתוב את כל התשובות בטופס הבחינה. המחברת תשמש כטיוטה בלבד ולא תיבדק. יש לענות על כל השאלות. בכל השאלות, אלא אם נכתב במפורש אחרת: - אם עליכן לכתוב פונקציה, אין צורך לבדוק את תקינות הקלט שלה. - מותר להסתמך על סעיפים קודמים, גם אם לא עניתן עליהם. - ניתן לצטט טענות שנטענו בהרצאה או בשיעורי התרגול בסמסטר זה. במקרה זה יש לכתוב "בהרצאה/תרגול ראינו כי...". ציטוטים ממקורות אחרים יש להוכיח. - אם נדרשתן לתת חסם על סיבוכיות במונחי ( )O, יש לתת חסם עליון נמוך ביותר האפשרי, למשל אם הסיבוכיות היא 7n התשובה הנדרשת היא,O(n) ולא ) 2.O(n אנו ממליצים לא "להיתקע" על אף שאלה, אלא להמשיך לשאלות אחרות ולחזור לשאלה אח"כ. בכל סעיף ניתן לכתוב "איני יודע/ת" ולא לכתוב שום טקסט נוסף. במקרה זה יינתן 20% מציון הסעיף )מעוגל כלפי מטה(. יש לכתוב את כל התשובות במקום המוקצב ובכתב קריא. תשובות ובהן חריגות משמעותיות מהמקום המוקצב, או תשובות הכתובות בכתב קטן מדי, לא ייקראו ולא יקבלו ניקוד, או שיקבלו ניקוד חלקי בלבד. תשובות שדורשות מאמצים רבים להבנתן גם כן עלולות לגרור הורדת ציון. טבלת ציונים: )לשימוש הבודקים( ניקוד ערך שאלה 20 1 25 2 20 3 בהצלחה! * הפניה במסמך זה היא בלשון נקבה ולשון זכר לסירוגין, מטעמי נוחות בלבד. כל הדרישות מיועדות לשני המגדרים באופן זהה. 20 4 15 5 100 סה"כ 1
שאלה )20 1 נק'( בקורס ראינו את מבנה הנתונים רשימה מקושרת. לנוחיותכם, הקוד של המחלקה Linked_list שראינו בכיתה מופיע בסוף השאלה. נציג כעת הרחבה למבנה זה: רשימה מקושרת דו-כיוונית. צומת ברשימה מקושרת דו-כיוונית )כמו ברשימה מקושרת, למחלקה זו נקרא )Node מכיל ערך )value( ומצביע לצומת הבא ברשימה.)next( נוסף על כך מכיל הצומת גם מצביע לאיבר הקודם ברשימה.)prev( הרשימה עצמה DLList( מלשון Doubly )linked list מכילה מצביע לצומת הראשון ברשימה,)head( מצביע לצומת האחרון ברשימה )tail( ואת אורך הרשימה )כאמור, מספר הצמתים בה, גם כאן נקרא למשתנה זה.)len להלן מתודות האתחול של שתי המחלקות שהצגנו והמתודה len של המחלקה :DLList class Node(): def init (self, val): self.value = val self.next = None self.prev = None class DLList(): def init (self, lst=none): self.head = None self.tail = None self.len = 0 if lst!= None: for item in lst: self.insert(item) def len (self): return self.len שימו לב מתודת האתחול של DLList משתמשת במתודה insert אותה נממש כעת. )המשך השאלה בעמוד הבא( 2
השלימו את המתודה insert של המחלקה.DLList המתודה מקבלת אובייקט מטיפוס DLList )הפרמטר,)self ערך )val( ופרמטר בוליאני אופציונלי,first( שהינו False באופן דיפולטי(. ופועלת באופן הבא: אם first == False המתודה מוסיפה את הערך val כצומת חדש בסוף הרשימה אם first == True המתודה מוסיפה את הערך val כצומת חדש בתחילת הרשימה הנחיה: על המתודה לפעול בזמן (1)O ובזכרון (1)O.1 def insert(self, val, first=false): השלימו את המתודה rotate של המחלקה.DLList המתודה מקבלת אובייקט מטיפוס DLList )הפרמטר )self ומספר שלם אי-שלילי )k(, ומשנה את self באופן הבא: עבור רשימה עם n איברים, אם נמספר את איברי הרשימה מ- 0 עד 1-n, אזי האיבר ה- i יהיה לאחר הפעלת המתודה האיבר ה- i). + k)%n לדוגמא:.2 ופרמטר 2=k נקבל את הרשימה הבא: 3
הנחיות: על המתודה לפעול בזמן O(m) כאשר {k m = min {k, n ובזכרון (1)O כאשר n הוא מספר האיברים ברשימה על המתודה לשנות את הרשימה עליה היא נקראת )כלומר לא ליצור רשימה חדשה( ניתן להניח כי k < n def rotate(self, k): השלימו את המתודה delete_node של המחלקה.DLList המתודה מקבלת אובייקט מטיפוס ואובייקט מטיפוס צומת )node( אשר נמצא ברשימה. המתודה מוחקת את הצומת מהרשימה. )self )הפרמטר DLList.3 הנחיות: ניתן להניח כי הצומת node נמצא ברשימה ובפרט כי הרשימה לא ריקה על המתודה לפעול בזמן ובזכרון (1)O def delete_node(self, node): 4
לפניכם 4 פונקציות לאתחול רשימות, f1 ו- f3 מאתחלות רשימות מקושרות דו-כיווניות ואילו f2 ו- f4 מאתחלות רשימות מקושרות חד-כיווניות )כפי שראינו בשיעור(. רשמו ליד כל אחת מהפונקציות את זמן הריצה שלה כתלות בקלט במונחים אסימפטוטיים הדוקים ככל הניתן..4 def f1(n): lst = DLList() for i in range(n): lst.insert(i, first=true) def f2(n): lst = Linked_list() for i in range(n): lst.add_at_start(i) def f3(n): lst = DLList() for i in range(n): lst.insert(i) def f4(n): lst = Linked_list() for i in range(n): lst.insert(i, len(lst)) זמן ריצה )f1(: זמן ריצה )f2(: זמן ריצה )f3(: זמן ריצה )f4(: תזכורת: הקוד למחלקות Node ו- Linked List שראינו בכיתה class Node(): def init (self, val): self.value = val self.next = None def repr (self): return "[" + str(self.value) + "," + str(id(self.next))+ "]" #This shows pointers as well for educational purposes 5
class Linked_list(): def init (self, seq=none): self.next = None self.len = 0 if seq!= None: for x in seq[::-1]: self.add_at_start(x) def repr (self): out = "" p = self.next while p!= None: out += str(p) + " " #str envokes repr of class Node p = p.next return out def len (self): ''' called when using Python's len() ''' return self.len def add_at_start(self, val): ''' add node with value val at the list head ''' p = self tmp = p.next p.next = Node(val) p.next.next = tmp self.len += 1 def find(self, val): ''' find (first) node with value val in list ''' p = self.next # loc = 0 # in case we want to return the location while p!= None: if p.value == val: return p else: p = p.next #loc=loc+1 # in case we want to return the location return None def getitem (self, loc): ''' called when using L[i] for reading return node at location 0<=loc<len ''' assert 0 <= loc < len(self) p = self.next for i in range(0, loc): p = p.next return p 6
def setitem (self, loc, val): ''' called when using L[loc]=val for writing assigns val to node at location 0<=loc<len ''' assert 0 <= loc < len(self) p = self.next for i in range(0, loc): p = p.next p.value = val return None def insert(self, loc, val): ''' add node with value val after location 0<=loc<len of the list ''' assert 0 <= loc <= len(self) p = self for i in range(0, loc): p = p.next tmp = p.next p.next = Node(val) p.next.next = tmp self.len += 1 def delete(self, loc): ''' delete element at location 0<=loc<len ''' assert 0 <= loc < len(self) p = self for i in range(0, loc): p = p.next # p is the element BEFORE loc p.next = p.next.next self.len -= 1 שאלה )25 2 נק'( עומר ואדם רוצים לשלוח ביניהם הודעות טקסט שמכילות אך ורק של כל תו בהודעות שישלחו יהיה מספר שלם בין תווים מתוך 16 תווי ה ascii הראשונים. כלומר, קוד ה ascii "0" ולאחריו r ביטים 0 ל 15 כולל. הם יצרו גירסה חדשה של אלגוריתם הדחיסה "למפל-זיו". בגירסה החדשה תו בודד יקודד ע"י הביט שמייצגים את קוד ה ascii של התו )כלומר, בסה"כ + 1 r ביטים(. חזרה תקודד )כמו באלגוריתם המקורי( ע"י הביט "1" ולאחריו 12 ביטים להיסט אחורה )offset( ולאחריהם 5 ביטים לאורך החזרה )כלומר, בסה"כ = 1+12+5 18 ביטים(. מהו הערך הקטן ביותר האפשרי ל r )מספר הביטים לייצוג כל קוד ascii של תו שיכול להופיע בהודעה(? r =.1 7
מהי כמות התווים המינימלית s כמות הביטים(? = s, כך שחזרות באורך s ומעלה משתלם לייצג כחזרה ולא כרצף תווים בודדים )מבחינת נימוק קצר לתשובתכם:.2 שימו לב: בהמשך השאלה נניח כי משתמשים בגירסה החדשה של למפל-זיו שמוגבלת ל- 16 תווים ושאכן לא מקודדים חזרות באורך קטן מזה שציינתם )כלומר באורך קטן מ (. s נניח שהתווים a,b,c,d,e הינם בעלי קוד ascii בין 0 ל- 15 כולל ולכן יכולים להופיע בהודעות בין עומר לאדם. תזכורת: ייצוג הביניים לפי אלגוריתם למפל-זיו הינו רשימה שאיבריה הם תווים בודדים או רשימות באורך 2 שמייצגות חזרה )זוג שהאיבר הראשון בו הינו ה offset והשני הינו אורך החזרה(. עבור כל מחרוזת ציינו כיצד יראה ייצוג הביניים של מחרוזת זו בשיטת הדחיסה של עומר ואדם:.3 ייצוג הביניים: ייצוג הביניים: ייצוג הביניים: "abababab" "abcabcdabc" "abcdabcdeabcde" עומר הפעיל את האלגוריתם על מחרוזת text חוקית וקיבל מחרוזת של ביטים, נסמנה. binary אדם הציע שכעת נתייחס למחרוזת זו כאל מחרוזת בינארית של "0" ו- "1", ונפעיל עליה אלגוריתם האפמן, כאשר הקורפוס )=המחרוזת ממנה לומדים את תדירויות התווים( הינו 25*"01" )כלומר הקורפוס הינו שיכפול של המחרוזת "01" עשרים וחמש פעמים בדיוק(. לדעתו של אדם התוצאה תהיה מחרוזת קצרה יותר מהמחרוזת.binary עומר טוען שהפעלת האפמן עם הקורפוס הזה מיותרת ותייצר מחרוזת באותו אורך כמו המחרוזת.binary בתיה הצטרפה לויכוח, וטענה ששניהם טועים המחרוזת לאחר דחיסת האמפן תהיה אפילו ארוכה יותר מהמחרוזת.binary מי מהם צודק? הסבירו..4 הקיפו בעיגול את בחירתכם: עומר צודק / אדם צודק / בתיה צודקת נימוק: 8
נתון קורפוס שמכיל את התווים.a,b,c,d,e שכיחויות התווים בקורפוס הינן:,w a, w b, w c, w d, w e בהתאמה. כל השכיחויות שלמות וגדולות ממש מ- 0. על סמך השכיחויות הללו, בונים עץ האפמן ע"י האלגוריתם שלמדנו. בכל תת-סעיף נתון מבנה של עץ ועליכם לסמן את התנאים על ערכי השכיחויות שבהכרח יגרמו לבניית עץ בעל מבנה כזה ע"י אלגוריתם האפמן )עד כדי הבדלים של שמאל ימין(, או לסמן שאין תנאי כזה מבין האפשרויות. במקרה כזה )ורק במקרה כזה( עליכם גם להסביר, ולכלול בהסבר אחד משניים: ציון תנאים אחרים עבורם בהכרח מתקבל עץ כזה, או נימוק מדוע זה לא ייתכן. שימו לב שיתכנו מספר תשובות נכונות עבור כל עץ ועליכם לסמן את כולן..5 w a > w b > w c > w d > w e w a = 1 w 2 b = 1 w 4 c = 1 w 8 d = 1 w 16 e w a = w b = w c, w d > 3w a, w e > 2w d w a = 1 w 2 b = 1 w 3 c = 1 w 4 d = 1 w 5 e.a. b.c. d א. e. אף אחד מהנ"ל לא מתאים עבור עץ זה נימוק, אם סימנתם את תשובה e: w a = 1 2 w b = 1 4 w c, w d = 1 16 w e ב. a. w a > w b > 2w c > 4w d > 8w e w a = w b = w c, w d = w e > 10w a w a = w b = w c, w d = w e > 3w a אף אחד מהנ"ל לא מתאים עבור עץ זה נימוק, אם סימנתם את תשובה e:.b. c. d. e w a = 1 2 w b < 1 4 w c = 1 4 w d = 1 5 w e w a = 1 10 w b = 1 20 w c = 1 25 w d = 1 30 w e.a.b ג. w a > w b > w c, w d < w e w a = w b = w c < w d = w e אף אחד מהנ"ל לא מתאים עבור עץ זה נימוק, אם סימנתם את תשובה e:.c. d. e 9
שאלה )20 3 נק'(.L[j]>L[i] בהינתן רשימה L של מספרים כלשהם, נגדיר היפוך )inversion( כזוג אינדקסים ברשימה (i,j) המקיימים i<j וגם לשם פשטות, בשאלה זו נניח כי כל המספרים ברשימה שונים זה מזה. בשאלה זו נעסוק בספירת מספר ההיפוכים ברשימה. למשל ברשימה ]1,2,3,4[ יש 0 היפוכים, ואילו ברשימה ]1,3,4,2[ יש 2 היפוכים, בזוגות האינדקסים הבאים: )1,3(, )2,3(. מה מספר ההיפוכים המקסימלי ברשימה בגודל n? )אין צורך להסביר( להלן פונקציה שאמורה להחזיר את מספר ההיפוכים ברשימה נתונה, אך היא לא מחזירה תשובה נכונה. ציינו מה תחזיר הפונקציה עבור הרשימה ]1,3,4,2[, והציעו תיקון לפונקציה. לשם כך, מספרנו את השורות. ציינו אילו שורות ברצונכם לשנות ומהן הפקודות לאחר השינוי..1.2 ערך ההחזרה של :inversions([1,3,4,2]) 1. def inversions(l): 2. inv = 0 3. for i in range(len(l)): 4. for j in range(len(l)): 5. if L[i]>L[j]: 6. inv+=1 7. return inv הצעה לתיקון: מה סיבוכיות הזמן של הפונקציה המתוקנת במקרה הגרוע כתלות באורך הרשימה n, במונחים אסימפטוטיים? הניחו שפעולות אריתמטיות מתבצעות ב- (1)O..3 ניתן לחשב את מספר ההיפוכים ברשימה נתונה באמצעות שימוש באלגוריתם mergesort שראינו בכיתה. להלן חלק מהקוד שלמדנו של הפונקציות mergesort ו-,merge עם כמה שינויים )מודגשים בקו(: הפונקציה merge החדשה מאתחלת בתחילתה משתנה בשם inv ל- 0. משתנה זה הוא מספר שלם המייצג מספר היפוכים. בסופה, הפונקציה מחזירה אותו יחד עם הרשימה הממוזגת )כלומר היא מחזירה.)tuple הפונקציה merge תעדכן משתנה זה במהלך ריצתה. בנוסף לשינוי זה, גם הפונקציה mergesort מחזירה כעת שני ערכים - הראשון הוא רשימה ממויינת )כמו קודם(, והשני הוא מספר היפוכים. למשל, עבור רשימה lst באורך 1 או פחות, היא תחזיר את הזוג.lst,0.4 10
עליכם להוסיף לקוד את הפקודות הדרושות, כך שבסוף ריצת mergesort על רשימה נתונה יוחזר זוג: הרשימה הממויינת, ומספר ההיפוכים ברשימה הנתונה. לשם כך, מספרנו את השורות בפונקציה.merge ציינו אחרי אילו שורות ברצונכם להוסיף פקודות ומהן פקודות אלו. כמו כן השלימו את סופה של הפונקציה mergesort בתוך בלוק ה- else )אין לבצע בה שינוים פרט לתוספת זו(. 1. def merge(a, B): 2. inv = 0 3. n = len(a) 4. m = len(b) 5. C = [0 for i in range(n+m)] 6. 7. a=0; b=0; c=0 8. while a<n and b<m: 9. if A[a] < B[b]: 10. C[c] = A[a] 11. a+=1 12. else: 13. C[c] = B[b] 14. b+=1 15. c+=1 16. 17. C[c:] = A[a:] + B[b:] 18. return C, inv תוספות לפונקציה merge )ציינו מספרי שורות אחריהן תרצו להוסיף פקודות(: 1. def mergesort(lst): 2. n = len(lst) 3. if n<=1: 4. return lst,0 5. else: #two recursive calls 6. L1, inv1 = mergesort2(lst[0:n//2]) 7. L2, inv2 = mergesort2(lst[n//2:n]) 8. 9. 11
מהי סיבוכיות הזמן של ריצת mergesort על רשימה בגודל n, לאחר השינוי שלכם? תנו תשובה במונחים אסימפטוטיים. הניחו שפעולות אריתמטיות מתבצעות ב-. O(1).5 להלן אלגוריתם מיון נוסף, שלא ראינו בכיתה: מיון הכנסה. 1. def insertion_sort(l): 2. for i in range(1,len(l)): 3. current = L[i] 4. j = i 5. while j>0 and L[j-1]>current: 6. L[j] = L[j-1] 7. j = j-1 8. L[j] = current 9. return None.6 נניח שמריצים את האלגוריתם על רשימה באורך n, ובה בדיוק m היפוכים. מה סיבוכיות הזמן של הפונקציה במקרה כזה? תנו תשובה אסימפטוטית במונחי n ו/או m. שאלה )20 4 נק'( בשאלה זו נעסוק בגרסה שונה של בעיית "n המלכות" שלמדנו בתרגול. נזכיר כי בבעיה זו, אנחנו רוצים לקבוע מהו מספר ההצבות החוקיות להציב n מלכות בלוח שחמט בגודל n על n. בגרסה שלמדנו, הצבה חוקית היא כזו בה אף מלכה לא מאיימת על מלכה אחרת, כלומר: אין שתי מלכות המוצבות באותה שורה או באותה עמודה אין שתי מלכות המוצבות באותו האלכסון )שימו לב כי יש להתייחס לאלכסונים משני הכיוונים: למטה-ימינה ולמעלה-ימינה( בלוח השחמט החדש "מלכות ודרקונים" נתון לנו לוח מיוחד, בו בחלק מהמשבצות ממוקמים דרקונים. לדרקון תכונה מיוחדת: מלכות לא יכולות לאיים על מלכה אחרת, אם ביניהן ניצב דרקון. כלומר, כעת שתי מלכות יוכלו להיות באותה שורה, עמודה או אלכסון, אם בין שתיהן )על אותה השורה, עמודה או אלכסון( ניצב דרקון )ייתכן שיש יותר מדרקון אחד בין שתי מלכות(. כמו כן, מלכה ודרקון לא יכולים להיות מוצבים באותו תא. לוח board מיוצג על ידי רשימה של n תווים המייצגים כל אחד תא בשורה זו. התו ' ' )רווח( מייצג תא ריק, התו )בעמוד הבא( דוגמה להצבה חוקית, והייצוג שלה: תתי-רשימות, כאשר כל תת-רשימה ב- board מייצגת שורה, ובתוך כל תת-רשימה כזו n 'Q' מייצג מלכה, והתו 'D' מייצג דרקון. למשל, להלן 12
>>> board = [ ['Q', ' ', 'D', ' ', 'Q'] [' ', ' ', ' ', ' ', ' '] [' ', 'Q ', 'D', 'Q', ' '] [' ', ' ', ' ', ' ', ' '] [' ', ' ', 'Q', ' ', ' ']] Q Q D D Q Q Q כעת נרצה לספור את מספר ההצבות החוקיות בלוח מסוג זה. צחי הבחין שניתן לפתור בעיה זו באמצעות מעבר בצורה רקורסיבית על כל התאים בלוח: מתחילים בתא )0,0(, כלומר הפינה השמאלית העליונה, ובכל קריאה רקורסיבית עוברים לתא שבאותה העמודה, בשורה שמתחת. כשמגיעים לשורה האחרונה בעמודה, ואם קיימת עמודה נוספת, עוברים לשורה הראשונה בעמודה הבאה, עד לסיום העמודות. נכתוב כעת את הקוד שמממש אלגוריתם זה. ראשית, נגדיר את הפונקציה col) legal(board, row, שמקבלת את הלוח board )בגודל n על n( שבו מוצבים מספר כלשהו של דרקונים, ובנוסף מוצבות עליו בצורה חוקית מלכות בחלק מהתאים ה"קודמים" )לפי סדר המעבר שצחי הגדיר(. כלומר, כבר הוצבו בין 0 ל 1-n )כולל( מלכות שלא מאיימות אחת על השנייה בעמודות 0 עד col-1 )כולל( ובעמודה col בשורה 0 עד row-1 )כולל(. הפונקציה מחזירה True אם עבור הלוח הנתון ניתן להציב מלכה בתא col( )row, כך שלא תאיים על אף מלכה אחרת שכבר מוצבת בלוח..1 def legal(board, row, col): if board[row][col]!= ' ': return False v = legal_up(board, row, col) h = legal_left(board, row, col) d1 = legal_diag_left_up(board, row, col) d2 = legal_diag_left_down(board, row, col) return h and v and d1 and d2 השלימו את המימוש של הפונקציה col) legal_left(board, row, שמחזירה True אם עבור הלוח הנתון board ניתן להציב מלכה בתא col( )row, כך שלא תאיים על מלכה אחרת המוצבת משמאל למלכה זו, כלומר: הצבה של מלכה בתא זה לא תאיים על מלכה אחרת בשורה,row בעמודה הקטנה מ- col. >>> legal_left(board, 0, 1) False >>> legal_left(board, 0, 3) True דוגמת הרצה )על הלוח מהדוגמה לעיל(: def legal_left(board, row, col): left = [ if ] return len(left) == 0 or left[ ]!= 'Q' 13
בסעיף זה עליכם להשלים את הפונקציה board).queens_rec(remaining_queens, row, col, לפונקציה זו קוראים מפונקציית המעטפת הבאה:.2 def queens(n, board): return queens_rec(n, 0, 0, board) פונקציית המעטפת מקבלת את n שהוא מספר המלכות שיש להציב, ואת board לוח שמוצבים בו אך ורק דרקונים במספר לא ידוע )שאר התאים הינם ריקים(, ועליה להחזיר את מספר ההצבות החוקיות של המלכות. השלימו את המימוש )ניתן כמובן להשתמש בפונקציות שלעיל(: def queens_rec(remaining_queens, row, col, board): n = len(board) if : return 1 if col >= n: else: result = 0 if legal(board, row, col): if row < n-1: _ else: if row < n - 1: else: return result מהו עומק עץ הרקורסיה של הפונקציה?queens_rec נמקו בקצרה..3 14
האם ממואיזציה עשויה לשפר את סיבוכיות הזמן של?queens_rec נמקו בקצרה..4 שאלה 15) 5 נק'( להלן קודים שונים לתיקון שגיאות. לכל אחד מהם, הסבירו כמה שגיאות ניתן בוודאות לזהות וכמה לתקן )ביחס להגדרות שראינו בכיתה(. הסבירו בקצרה. בהינתן הודעה בת 6 ביטים, שכפל 3 פעמים כל רצף של שני ביטים. למשל )ההדגשות רק לצורך ההסבר(:.1 101010111111010101 >= 101101 010101000000101010 >= 010010 מס' שגיאות הניתנות לזיהוי: מס' שגיאות הניתנות לתיקון: הסבר קצר: בהינתן הודעה בת 4 ביטים, הוסף 3 ביטים בסוף ההודעה כך ש: הביט הראשון שנוסף, ערכו 0 אם מס' ה- 1 ים מבין הביטים הראשון, השני והרביעי של ההודעה המקורית הוא זוגי. אחרת ערכו 1. הביט השני שנוסף, ערכו 0 אם מס' ה- 1 ים מבין הביטים הראשון, השלישי והרביעי של ההודעה המקורית הוא זוגי. אחרת ערכו 1. הביט השני השלישי שנוסף, ערכו 0 אם מס' ה- 1 ים מבין הביטים השני, השלישי והרביעי של ההודעה המקורית הוא זוגי. אחרת ערכו 1. למשל:.2 0110110 >= 0110 1110000 >= 1110 מס' שגיאות הניתנות לזיהוי: מס' שגיאות הניתנות לתיקון: 15
הסבר קצר: בהינתן הודעה בת 5 ביטים: הוסף ביט שערכו 0 אם מס' ה- 1 ים בהודעה המקורית הוא זוגי. אחרת ערכו 1. כעת, שכפל כל ביט בהודעה )כולל הביט שנוסף בסעיף )1(( פעמיים. למשל )הדוגמא מראה את שני השלבים, התוצאה הסופית היא בצד שמאל(.3 111111110000 >= 111100 >= 11110 מס' שגיאות הניתנות לזיהוי: מס' שגיאות הניתנות לתיקון: הסבר קצר: בהצלחה! 16
דף נוסף, מיועד ל "מקרה חירום" 17