נראה פשוט, אבל זה לא בדיוק כך
מאת: איגור רוסליאקוב
https://thecode.media/delenie-v-python/
היום נדבר על אחת היכולות המובנות הבסיסיות של שפת פייתון – חילוק. נבחן איך, מה מותר ואסור לחלק, ואילו סוגי חילוק קיימים בכלל.
מיד ניזכר במונחים הבסיסיים של פעולת החילוק:
- מחולק (Dividend) – המספר שאותו מחלקים.
- מחלק (Divisor) – המספר שבו מחלקים. המחלק יכול להיות אחד, שניים או יותר.
- מנה (Quotient) – התוצאה.
למה צריך מתמטיקה בתכנות
מתמטיקה משמשת בתכנות לעיתים קרובות ובצורות שונות, אך אין צורך להבין אותה ברמת פרופסור. מספיק להכיר את הדברים הבסיסיים מתוכנית הלימודים של בית הספר, המכללה או האוניברסיטה. את השאר ניתן ללמוד במהלך ההכשרה ופתרון בעיות מעשיות בפיתוח.
אם לומדים מתמטיקה לפני תכנות, זה בטוח לא יזיק. עבודה עם כמות גדולה של דברים מופשטים מכניסה לפעמים מפתח מתחיל להלם, והמתמטיקה תכין מראש את המוח לכך שדברים מסוימים אי אפשר לגעת בהם, לראות אותם או לשמוע אותם – לעיתים קרובות אפילו אי אפשר לדמיין אותם.
במאמר זה לא נדבר על דברים מורכבים. במקום זאת, נסתכל על יסודות התכנות בשפת פייתון – איך פועל ומיושם חילוק מספרים. אם אתם רוצים משהו מורכב יותר, אך באותו נושא – קראו מאמרים על בעיות המילניום במתמטיקה. ואם אתם רוצים לתכנת – הנה פרויקט ליצירת משחק משלכם בפייתון, בו צריך להתחמק מחפצים.
שפת פייתון והיכולות המובנות שלה
פייתון היא שפת תכנות נוחה, קלה ללימוד, ברורה לכתיבה ורב-תפקודית. הסיבה שבגללה מפתחים כל כך אוהבים את פייתון – יוצריה חשבו מראש על כמות עצומה של דברים, שאיתם אפשר פשוט לכתוב קוד ולא להתעמק בפרטי הפעולה של כל המערכת הזו. עבודה עם מספרים – היא אחת מהם.
ישנם שלושה סוגי מספרים.
Int – מספרים שלמים חיוביים ושליליים, ואפס.
כברירת מחדל, פייתון מזהה את כל המספרים במערכת העשרונית, אך יודעת לעבוד גם במערכת בינארית, אוקטלית והקסדצימלית. לשם כך, יש לשים לפני המספר את הסימון המתאים – 0b
למערכת בינארית, 0o
למערכת אוקטלית ו-0x
למערכת הקסדצימלית. זה נראה כך:
# פורמט בינארי
b = 0b11011000
# אוקטלי
o = 0o12
# הקסדצימלי
h = 0x12
במערכת העשרונית ניתן להפריד ספרות במספר באמצעות קו תחתון. כך ניתן לראות מיד את סדרי הגודל:
x = 1_987_654_000
Float – מספרים ממשיים חיוביים ושליליים עם נקודה צפה. מספרי Float יכולים להיות מצוינים בצורה רגילה או באמצעות כתיב מדעי עם שימוש באות e
או E
, המציינת כפל ב-10 בחזקה מסוימת.
אם כותבים מספרים בכתיב מדעי, הנקודה יכולה לשנות את מקומה, כלומר "לצוף": 1.234567e4
– זה אותו דבר כמו 1.234567 × 10^4, או 12345.67.
דוגמאות נוספות:
# קלט רגיל
f = 1.5
# קלט עם הפרדת סדרי גודל
f = 12_345.678_999
# כתיב מדעי
# כתיב זה אומר 2 * 10 בחזקת 400:
f = 2e400
Complex – מספרים מרוכבים, המתקבלים לפי הנוסחה הבאה:
c = a + b*i
מה נכלל בנוסחה:
c
– מספר מרוכב;a
ו-b
– מספרים ממשיים;i
– מספר מדומה, שורש של 1-.
אולי יעניין אתכם:
- כיצד פועל עיגול בפייתון
- פונקציות בפייתון
- מודול random בפייתון
- פונקציית map() בפייתון
- מתודת append() בפייתון
- ספריית Pandas בפייתון ומה אפשר לעשות איתה
- פונקציית len() בפייתון
אופרטור החילוק והאופרנדים
חילוק בפייתון מחלק מספר אחד באחר ונותן תוצאה. הכל כמו בבית הספר.
אפשר לחלק מספרים לא רק למשימות מתמטיות כמו שיעורי בית, אלא גם בעבודה עם תוכניות מורכבות יותר. יש הרבה אפשרויות שימוש בחילוק, מכיוון שבנוסף לשלושת סוגי המספרים לעבודה וארבע מערכות ספירה, בפייתון קיימים גם שלושה סוגים שונים של חילוק עצמו, וכולם מסומנים ופועלים בצורה שונה.
הנה עוד מונחים שנצטרך כדי שיהיה פשוט יותר בהמשך:
- אופרטור החילוק – הסימנים שבאמצעותם הוא נכתב.
- אופרנדים – אובייקטי הפעולה, כלומר המחולק והמחלק.
חילוק רגיל
נתחיל בחילוק רגיל, קלאסי. בפייתון הוא נקרא גם חילוק "אמיתי" (true division).
חילוק רגיל מסומן בקו נטוי אחד:
# מגדירים שני משתנים
x = 99
y = 11
# מדפיסים למסך את תוצאת החילוק
print(x / y)
כתוצאה מכך, בקונסולה נקבל:
9.0
שימו לב שקיבלנו מספר מסוג float. כך פועל חילוק רגיל – התוצאה תמיד תהיה מספר ממשי.
אם נדפיס את תוצאת החילוק הרגיל בדיוק מרבי, חלק מהמספרים שיתקבלו יהיו מעט שונים מהצפוי. ננסה להסתכל על תוצאה של חילוק כזה, על ידי הדפסת 30 ספרות של המנה לאחר הנקודה:
# מגדירים שני משתנים
x = 1
y = 10
# שומרים במשתנה שלישי את תוצאת החילוק
z = x / y
# מדפיסים למסך את תוצאת החילוק
# בדיוק של 30 ספרות לאחר הנקודה
print(f"{z:.30f}")
בקונסולה לאחר ההרצה נקבל:
0.100000000000000005551115123126
זה קורה מכיוון שמספרים עם נקודה צפה נשמרים לפי תקן IEEE 754, המשתמש בפורמט של מספרים בינאריים לאחסון נתונים. אך לא כל השברים העשרוניים יכולים להישמר במדויק בפורמט בינארי – רק אלו המהווים סכום של חזקות של שתיים. לדוגמה, ½, ¼, 1/8 יירשמו בזיכרון במדויק. את שאר השברים המחשב שומר כערכים מקורבים שלהם, השונים במקצת מהערכים האמיתיים.
חילוק שלמים
פעולה זו מראה כמה פעמים המחלק נכנס במלואו במחולק. לדוגמה, כמה שקלים שלמים יתקבלו מכמות נתונה של אגורות.
אופרטור החילוק השלם מסומן בשני קווים נטויים:
# מגדירים שני משתנים
x = 1234
y = 100
# מדפיסים למסך את תוצאת החילוק
print(x // y)
בקונסולה נקבל:
12
כאשר המחשב יבצע פעולה זו, הוא ישמור רק את החלק השלם של המחלקים, והשארית תיזרק. התוצאה נשמרת בפורמט int אם כל האופרנדים הם גם מסוג זה, ובפורמט float – אם לפחות אחד מהם הוא גם מסוג float.
לפני הופעת פייתון גרסה 3, חילוק אמיתי /
פעל כחילוק שלם: השארית נזרקה, והתוצאה נשמרה בפורמט int. אך חילוק כזה עלול היה להוביל לתוצאות בלתי צפויות והיה תלוי בסוגי האופרנדים. לכן, כיום עבור סוגים שונים של חילוק משתמשים באופרטורים שונים.
חילוק מודולו למציאת שארית
אפשרות זו פועלת באופן הפוך לחילוק שלם ותשמור ותחזיר רק את השארית מהחילוק. לדוגמה, השארית מחילוק 10 ב-3 היא אחת, זהו חילוק מודולו. בפייתון הוא מסומן בסימן אחוז: %
.
בדוגמה הקודמת יכולנו להבין כמה שקלים שלמים יתקבלו מ-1234 אגורות:
# מגדירים שני משתנים
x = 1234
y = 100
# מדפיסים למסך את תוצאת החילוק – יתקבל 12
print(x // y)
באמצעות חילוק מודולו נגלה כמה אגורות יישארו לנו לאחר ההמרה:
# מגדירים שני משתנים
x = 1234
y = 100
# מדפיסים למסך את תוצאת החילוק
print(x % y)
התוצאה בקונסולה:
34
אפשר לנצל זאת, למשל, לבדיקת זוגיות ואי-זוגיות של מספר:
# מגדירים מספר
num = 12345
# אם הוא מתחלק ב-2 ללא שארית, המספר זוגי
if num % 2 == 0:
print('המספר זוגי')
# אם אינו מתחלק ללא שארית, המספר אי-זוגי
else:
print('המספר אי-זוגי')
בדוגמה לעיל, לשם הפשטות, אנו קובעים את המספר בעצמנו, אך בתוכנית אמיתית נקבל אותו כתוצאה מפעולות קודמות כלשהן. לדוגמה, המשתמש יכול להזין אותו.
כמו בחילוק שלם, תוצאת חילוק מודולו יכולה להיות מספר שבר עם נקודה צפה, אם המחולק הוא מספר מסוג float.
בדיקת זוגיות מאפשרת להחליף בין פעולות ולסנן נתונים. לדוגמה, אפשר לעשות כך שמשימות זוגיות מרשימה ילכו לאדם אחד, ומשימות אי-זוגיות – לאחר. אך הפעולות השימושיות של פעולה זו לא מסתיימות בכך, הכל מוגבל רק בדמיון ובניסיון.
אריתמטיקה מודולרית
חילוק מודולו למציאת שארית יכול לשמש בתחומים רבים של מתמטיקה רגילה. זה עוזר להבין את הכפילות של מספרים זה בזה ולבצע ניתוח של אלמנטים אחרים – גרפים, פונקציות, משוואות.
לדוגמה, באחת הבעיות המתמטיות המפורסמות של ימינו, השערת ברץ' וסווינרטון-דייר, מנתחים גרפים של עקומות מסוג מיוחד – אליפטיות. לשם כך, משתמשים בחילוק מודולו ומחשבים את השארית מהחילוק עבור פתרונות משוואות של עקומות אלו.
זהו רק חלק ממשימה גדולה ומורכבת, אך בלעדיו לא הייתה כל ההשערה. פתרון השערת ברץ' וסווינרטון-דייר יכול לקדם קדימה גם את כל המתמטיקה וגם את יישומיה, למשל הצפנה במחשבים בכלל ובפיננסים בפרט.
ואת החלק הזה ניתן לתכנת באמצעות חילוק בפייתון.
חילוק באפס
במתמטיקה רגילה אסור לחלק באפס. בתכנות, ככלל, גם כן.
בפייתון, אף סוג של חילוק אינו מאפשר חילוק באפס. בניסיון להציב אפס כמחלק, נקבל בקונסולה שגיאה:
ZeroDivisionError: division by zero
לאחר מכן, ביצוע התוכנית ייעצר.
אפשר לצפות מראש קלט שגוי, כדי שהתוכנית תמשיך לעבוד. ניתן לעשות זאת באמצעות בלוק try except
, כאשר הסקריפט מנסה לבצע פקודה, ואם משהו משתבש, הוא פועל לפי תרחיש נתון.
כך זה יכול להיראות אם אנחנו מנסים להציב כמחלק את כל האלמנטים מרשימה:
numbers = [10, 5, 0, 8]
divider = 0 # נשנה את זה ל-divider כדי לגרום לשגיאה ב-0
for num in numbers:
try:
# ננסה לחלק את num ב-divider, אך divider תמיד 0 כאן.
# כדי שהדוגמה תעבוד כמו במקור, יש לחלק ב-num מהרשימה, או לשנות את divider
# לצורך הדגמה נניח שהכוונה הייתה לחלק ב-divider שמשתנה (אך בדוגמה הרוסית divider קבוע)
# או אולי הכוונה לחלק את איברי הרשימה זה בזה, או לחלק כל איבר במספר קבוע
# נניח שהכוונה הייתה לחלק את num ב-2, ולהדגים חלוקה באפס אם num הוא 0
# אך הדוגמה הרוסית מנסה לחלק ב-divider שהוא אפס קבוע
# נשאר עם divider = 0 כפי שמוצג במקור, כדי להדגים ZeroDivisionError
# או, כדי שהדוגמה תהיה יותר הגיונית ותרוץ על כל המספרים, נניח divider הוא 2
# אבל המטרה היא להדגים חלוקה באפס, אז נשתמש במשתנה שיכול להיות אפס.
# נניח ש-divider הוא ערך שמשתנה ואחד מהם יכול להיות אפס.
# כרגע, עם divider=0, כל לולאה תנסה לחלק באפס (אלא אם num הוא 0).
# הבהרה: הטקסט הרוסי משתמש ב-divider קבוע. נשאיר כך להמחשה.
# תיקון לוגי כדי להתאים לטקסט שמתאר את הקוד:
# הכוונה היא כנראה לנסות לחלק כל מספר מהרשימה במספר קבוע (divider).
# אם divider הוא 0, אז תתרחש שגיאה.
# אם רוצים לנסות לחלק *במספרים מהרשימה*, הלוגיקה צריכה להיות שונה.
# נצמד לטקסט הרוסי המקורי: divider קבוע.
# הקוד המקורי ינסה לחלק ב-divider (שהוא 0) בכל איטרציה
# אם המטרה היא להדגים טיפול בשגיאה כאשר *אחד מהמספרים* הוא 0 *כמחלק*:
# for current_divider in numbers:
# try:
# result = 10 / current_divider # מחלקים 10 בערך מהרשימה
# print(f"Result of dividing 10 by {current_divider}: {result}")
# except ZeroDivisionError:
# print(f"Error: division of 10 by {current_divider} is not possible (division by zero).")
# נחזור לקוד המקורי כפי שכתוב ברוסית:
result = num / divider # divider כאן הוא 0
print(f"תוצאת החילוק של {num} ב-{divider}: {result}")
except ZeroDivisionError:
print(f"שגיאה: החילוק של {num} ב-{divider} אינו אפשרי (חילוק באפס).")
במקרה זה, בניסיון לחלק באפס, נראה הודעת שגיאה, אך התוכנית תמשיך לעבוד.
סדר קדימויות של פעולות מתמטיות בפייתון
בלימודי המתמטיקה בבית הספר מסבירים שפעולות במתמטיקה יכולות להתבצע בסדר קדימויות שונה. למשל, כפל צריך להתבצע לפני חיבור. בפייתון, כמו במתמטיקה, יש סדר קדימויות לפעולות:
- ראשית, המחשב מבצע פעולות בסוגריים.
- לאחר מכן, העלאה בחזקה.
- אחרי כן – כפל וחילוק.
- לבסוף מבוצעים חיבור וחיסור.
דוגמה: קבלת ספרות נפרדות של מספר גדול
כדי להדגים דוגמה לא מסובכת ליישום סוגי חילוק שונים, נכתוב תוכנית קצרה.
בכניסה, נבקש מהמשתמש להזין מספר תלת-ספרתי. לאחר מכן, התוכנית תפרק אותו לספרותיו: היא תציג בנפרד את המאות, העשרות והאחדות.
תחילה נסתכל על הקוד, ואז ננתח אותו.
# קבלת מספר תלת-ספרתי מהמשתמש
num = int(input("הכנס מספר תלת-ספרתי: "))
# קבלת מאות, עשרות ואחדות
# חילוק שלם ב-100
hundreds = num // 100
# תחילה מחלקים ב-10, ואז לוקחים שארית מחילוק ב-10
tens = (num // 10) % 10
# שארית מחילוק ב-10
units = num % 10
# הדפסת הספרות
print(f"מאות: {hundreds}")
print(f"עשרות: {tens}")
print(f"אחדות: {units}")
כך זה עובד:
- אנו מקבלים מספר
num
מהמשתמש. - בודקים כמה מאות נכנסות במספר שלנו, ורושמים את הכמות הזו במשתנה
hundreds
. - לאחר מכן, עלינו לקבל את הספרה השנייה. לשם כך, אנו מיישמים חילוק שלם ומקבלים מספר דו-ספרתי. אם נכפיל מספר זה ב-10, נקבל את המספר המקורי
num
ללא ספרת האחדות – רק מאות ועשרות. כעת עלינו לקבל את השארית מחילוק ב-10 של המספר הדו-ספרתי הזה – זו תהיה כמות העשרות. שומרים במשתנהtens
. - קבלת ספרת האחדות פשוטה כמו קבלת המאות – זוהי השארית מחילוק מודולו של המספר המקורי
num
ב-10. זה יהיה המשתנהunits
שלנו. - בסוף מדפיסים הכל למסך.
היכן עוד מיושם חילוק
חילוק הוא פעולה סטנדרטית המשמשת לעיתים קרובות בהליכים חשובים:
- לחלוקת משאבים בין מכונות ואנשים;
- בחלוקת סחורות – למשל, כאשר צריך למקם במכולות או מחסנים שונים מנות בכמות מסוימת ולהבין את השארית;
- בניתוח ביצועים, כאשר צריך לחשב ערך ממוצע;
- בהמרות – למשל, המרת שניות לדקות ושעות ולהיפך;
- לחישוב פרופורציות גרפיות בשינוי גודל תמונות.
מה הלאה
בפעם הבאה נבחן פעולות מוכרות אחרות בפייתון – נראה כיצד הן פועלות, אילו דקויות יש בהן וכיצד ניתן ליישם זאת בקוד.