CodeGym /בלוג Java /Random-HE /אופרטורים של Java Bitwise
John Squirrels
רָמָה
San Francisco

אופרטורים של Java Bitwise

פורסם בקבוצה
בשיעור של היום נערוך היכרות עם Java Bitwise Operators ונשקול דוגמאות כיצד לעבוד איתם. אתה בטח מכיר את המילה "קצת". אם לא, נזכיר מה זה אומר :) קצת היא יחידת המידע הקטנה ביותר במחשב. שמו בא מספרה בינארית . ניתן לבטא ביט באחד משני מספרים: 1 או 0. קיימת מערכת מספרים בינארית מיוחדת המבוססת על אחדים ואפסים. לא נתעמק כאן בג'ונגל מתמטי. נציין רק שניתן להמיר כל מספר ב-Java לצורה בינארית. כדי לעשות זאת, עליך להשתמש בשיעורי העטיפה.
אופרטורים ביטוויזיים - 1
לדוגמה, כך תוכל לעשות זאת עבור int :
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
פלט מסוף: 101010110 1010 10110 (הוספתי את הרווח כדי להקל על הקריאה) הוא המספר 342 במערכת העשרונית. למעשה פירקנו את המספר הזה לביטים בודדים: אפסים ואחדים. פעולות המבוצעות על ביטים נקראות bitwise .
  • ~ - לא מבחינה סיבית.
האופרטור הזה פשוט מאוד: הוא עובר על כל סיביות במספר שלנו, ומעיף את הסיביות: אפסים הופכים לאחת, ואחדים הופכים לאפסים. אם נחיל אותו על המספר 342 שלנו, זה מה שקורה: 101010110 הוא 342 מיוצג כמספר בינארי 010101001 הוא הערך של הביטוי ~342 בוא ננסה ליישם את זה בפועל:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(~x);
   }
}
פלט מסוף: 169 169 הוא התוצאה שלנו ( 010101001 ) במערכת העשרונית המוכרת :)
  • & - AND
כפי שאתה יכול לראות, זה נראה די דומה ל-AND הלוגי ( && ). אתה זוכר, האופרטור && מחזיר אמת רק אם שני האופרנדים נכונים . Bitwise & עובד בצורה דומה: הוא משווה שני מספרים ביט אחר סיביות. ההשוואה מייצרת מספר שלישי. לדוגמה, ניקח את המספרים 277 ו-432: 110110000 הוא 277 מיוצג כמספר בינארי 1000101011 הוא 432 מיוצג כמספר בינארי לאחר מכן, האופרטור & משווה את הסיבית הראשונה של המספר העליון לסיבית הראשונה של המספר התחתון. מכיוון שזהו אופרטור AND, התוצאה תהיה 1 רק אם שני הביטים הם 1. בכל מקרה אחר, התוצאה היא 0. 100010101 & 110110000 _______________ 10001000 - תוצאה של האופרטור & ראשית, נשווה את הביטים הראשונים מבין השניים מספרים, ואז הסיביות השניות, ואז השלישיות וכן הלאה. כפי שאתה יכול לראות, רק בשני מקרים שניהם סיביות מתאימות במספרים שווים ל-1 (הסיביות הראשונה והחמישית). כל שאר ההשוואות יצרו 0s. אז בסופו של דבר קיבלנו את המספר 10001000. בשיטה העשרונית הוא מתאים למספר 272. בוא נבדוק:
public class Main {

   public static void main(String[] args) {
       System.out.println(277&432);
   }
}
פלט קונסולה: 272
  • | - OR.
אופרטור זה פועל באותו אופן: השוואה בין שני מספרים ביט אחר סיביות. רק עכשיו אם לפחות אחת מהסיביות היא 1, אז התוצאה היא 1. בואו נסתכל על אותם המספרים (277 ו-432): 100010101 | 110110000 _______________ 110110101 - תוצאת ה | אופרטור הנה, אנו מקבלים תוצאה שונה: הביטים היחידים שנותרו אפסים הם אותם ביטים שהיו אפסים בשני המספרים. התוצאה היא המספר 110110101. בשיטה העשרונית הוא מתאים למספר 437 בואו נבדוק:
public class Main {

   public static void main(String[] args) {
       System.out.println(277|432);
   }
}
פלט קונסולה: 437 חישבנו הכל נכון! :)
  • ^ - XOR בשיטת סיביות (בלעדי OR)
עדיין לא נתקלנו במפעיל הזה. אבל אין בזה שום דבר מסובך. זה דומה לאופרטור ה-OR הרגיל. יש הבדל אחד: ה-OR הרגיל מחזיר אמת אם לפחות אופרנד אחד נכון. אבל זה לא חייב להיות אחד: אם שני האופרנדים נכונים, התוצאה נכונה. אבל בלעדי OR מחזיר אמת רק אם בדיוק אחד מהאופרנדים נכון. אם שני האופרנדים נכונים, ה-OR הרגיל מחזיר true ("לפחות אמת אחד"), אבל XOR מחזיר false. לכן זה נקרא בלעדי OR. לדעת איך פועלים האופרטורים הקודמים בשיטת הסיביות, אתה כנראה יכול בקלות לחשב 277 ^ 432. אבל בואו נחפור בזה ביחד עוד פעם אחת :) 100010101 ^ 110110000 _______________ 010100101 - תוצאה של האופרטור ^ זו התוצאה שלנו. אותם סיביות שהיו זהים בשני המספרים מייצרים 0 (כלומר המבחן "היחיד" נכשל). אבל הביטים שיצרו צמד של 0-1 או 1-0 הפכו לאחת. התוצאה שלנו היא המספר 010100101. בשיטה העשרונית הוא מתאים למספר 165. בואו נראה אם ​​החישובים שלנו נכונים:
public class Main {

   public static void main(String[] args) {
       System.out.println(277^432);
   }
}
תפוקת קונסולה: 165 סופר! הכל בדיוק כמו שחשבנו :) עכשיו הגיע הזמן להכיר מפעילי ביט משמרות. השם מדבר בעד עצמו. אנחנו לוקחים מספר כלשהו, ​​ומזיזים את החלקים שלו שמאלה או ימינה :) בואו נראה איך הוא נראה:

העבר שמאלה

תזוזה של ביטים שמאלה מסומנת על ידי << הנה דוגמה:
public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 3;// Shift distance

       int z = (x << y);
       System.out.println(Integer.toBinaryString(x));
       System.out.println(Integer.toBinaryString(z));
   }
}
בדוגמה זו, המספר x = 64 נקרא הערך. את חלקי הערך נעביר. נעביר את הביטים שמאלה (יכולת לנחש זאת לפי כיוון האופרטור << ) במערכת הבינארית, המספר 64 = 1000000 המספר y = 3 נקרא מרחק shift. מרחק ההסטה מציין כמה ביטים ימינה/שמאלה אתה רוצה להעביר את הביטים של המספר x בדוגמה שלנו, נעביר אותם 3 ביטים שמאלה. כדי לראות את תהליך המעבר בצורה ברורה יותר, התבונן בתמונה. בדוגמה זו, אנו משתמשים ב-int s. Ints תופסים 32 סיביות בזיכרון המחשב. כך נראה המספר המקורי שלנו 64:
אופרטורים ביטוויזיים - 2
ועכשיו אנחנו לוקחים כל קטע שלנו ומזיזים אותם ממש שמאלה ב-3 מקומות:
אופרטורים ביטוויזיים - 3
תסתכל על מה קיבלנו. כפי שאתה יכול לראות, כל הביטים שלנו זזו, ועוד 3 אפסים נוספו מקצה הטווח. שלוש, כי הזזנו ב-3. אם היינו זזים ב-10, היו מתווספים 10 אפסים. לפיכך, הביטוי x << y פירושו "הזז את הסיביות של המספר x שמאלה ב-y מקומות". התוצאה של הביטוי שלנו היא המספר של 1000000000, שהוא 512 בשיטה העשרונית. בוא נבדוק:
public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 3;// Shift distance

       int z = (x << y);
       System.out.println(z);
   }
}
פלט קונסולה: 512 נקודתית! תיאורטית, ניתן להזיז את הביטים בלי סוף, אבל מכיוון שהמספר שלנו הוא int , יש לנו רק 32 ספרות בינאריות זמינות. מתוכם 7 כבר תפוסים על ידי 64 (1000000). לכן, אם נעביר 27 מקומות שמאלה, היחיד שלנו יעבור מעבר לטווח של סוג הנתונים וילך לאיבוד. רק אפסים יישארו!
public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 26;// Shift distance

       int z = (x << y);
       System.out.println(z);
   }
}
פלט קונסולה: 0 כצפוי, זו עברה מעבר ל-32 הביטים הזמינים ונעלמה. סיימנו עם מספר של 32 סיביות המורכב מאפסים בלבד.
אופרטורים ביטוויזיים - 4
באופן טבעי, זה מתאים ל-0 בשיטה העשרונית. הנה כלל פשוט לזכור תזוזות שמאלה: עבור כל תזוזה שמאלה, המספר מוכפל ב-2. ננסה לחשב את הביטוי הבא ללא תמונות של ביטים 111111111 << 3 עלינו להכפיל את המספר 111111111 ב -2 . כתוצאה מכך, נקבל 888888888. בוא נכתוב קצת קוד ונבדוק:
public class Main {

   public static void main(String[] args) {
       System.out.println(111111111 << 3);
   }
}
פלט מסוף: 888888888

העבר ימינה

פעולה זו מסומנת על ידי >> . זה עושה את אותו הדבר, אבל בכיוון השני! :) לא נמציא את הגלגל מחדש. בוא ננסה את זה עם אותו int 64.
public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 2;// Shift distance

       int z = (x >> y);
       System.out.println(z);
   }
}
אופרטורים ביטוויזיים - 5
אופרטורים ביטוויזיים - 6
כתוצאה מהזזה ימינה ב-2, שני האפסים הקיצוניים במספר שלנו יוצאים מתחום ואובדים. נקבל 10000, המתאים למספר 16 בפלט מסוף המערכת העשרונית: 16 הנה כלל פשוט לזכירת תזוזות ימינה: כל תזוזה ימינה מתחלקת בשניים, ומבטלת כל שארית. לדוגמה, 35 >> 2 אומר שעלינו לחלק את 35 ב-2 פעמיים, לזרוק את השאריות 35/2 = 17 (לזרוק את השארית 1) 17/2 = 8 (לזרוק את השארית 1) בסופו של דבר, 35 >> 2 צריך להיות שווה ל-8. בוא נבדוק:
public class Main {

   public static void main(String[] args) {
       System.out.println(35 >> 2);
   }
}
פלט קונסולה: 8

עדיפות מפעיל ב-Java

בזמן כתיבה וקריאת קוד, תמצא לעתים קרובות ביטויים המשלבים מספר פעולות. חשוב מאוד להבין באיזה סדר הם יבוצעו (אחרת, אתה עשוי להיות מופתע מהתוצאה) מכיוון של-Java יש המון פעולות, לכל אחת מהן הוקצה מקום בטבלה מיוחדת:

עדיפות מפעיל

מפעילים עֲדִיפוּת
postfix expr++ expr--
אונארי ++expr --expr +expr ~ !
כפל * / %
תוסף + -
מִשׁמֶרֶת << >> >>>
יחסי < > <= >= מופע של
שוויון == !=
AND &
OR בלעדי מבחינה סיבית ^
כולל OR |
AND הגיוני &&
OR הגיוני ||
מְשּוּלָשׁ ? :
מְשִׁימָה = += -= *= /= %= &= ^= |= <<= >>= >>>=
כל הפעולות מתבצעות משמאל לימין, תוך התחשבות בעדיפותן. למשל, אם נכתוב
int x  = 6 - 4/2;
לאחר מכן תבוצע תחילה פעולת החלוקה ( 4/2 ). למרות שהוא מגיע למקום השני, יש לו עדיפות גבוהה יותר. סוגריים וסוגריים מציינים עדיפות מרבית. אתה בטח זוכר את זה מבית הספר. לדוגמה, אם תוסיף אותם לביטוי
int x  = (6 - 4)/2;
אז החיסור מבוצע תחילה, מכיוון שהוא מוקף בסוגריים. קדימות האופרטור הלוגי && היא נמוכה למדי (ראה טבלה), כך שהיא לרוב תהיה האחרונה. לדוגמה:
boolean x = 6 - 4/2 > 3 && 12*12 <= 119;
ביטוי זה יבוצע באופן הבא:
  • 4/2 = 2
boolean x = 6 - 2 > 3 && 12*12 <= 119;
  • 12*12 = 144
boolean x = 6 - 2 > 3 && 144 <= 119;
  • 6-2 = 4
boolean x = 4 > 3 && 144 <= 119;
לאחר מכן, אופרטורי ההשוואה מבוצעים:
  • 4 > 3 = נכון
boolean x = true && 144 <= 119;
  • 144 <= 119 = שקר
boolean x = true && false;
ולבסוף, האופרטור AND ( && ) יתבצע אחרון.
boolean x = true && false;
boolean x = false;
לדוגמה, לאופרטור התוספת( + ) יש קדימות גבוהה יותר מאופרטור ההשוואה != (לא שווה); לכן, בביטוי
boolean x = 7 != 6+1;
תחילה תבוצע פעולת 6+1, לאחר מכן הבדיקה 7 != 7 (אשר מוערכת כ-false), ולבסוף הקצאת התוצאה (false) למשתנה x (הקצאה היא בדרך כלל בעלת העדיפות הנמוכה ביותר מבין כל האופרטורים; ראה השולחן). פיו! זה היה שיעור ענק, אבל עשית את זה! אם לא הבנת עד הסוף חלק משיעורים אלה או קודמים, אל תדאג. אנו ניגע בנושאים אלו יותר מפעם אחת בעתיד. כמה שיעורי CodeGym על פעולות לוגיות ומספריות. לא נגיע אליהם בקרוב, אבל לא מזיק שתקרא אותם עכשיו.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION