JavaRush /בלוג Java /Random-HE /פעולות Bitwise ב-Java

פעולות Bitwise ב-Java

פורסם בקבוצה
אתם בוודאי מכירים את המילה "ביט". אם לא, בואו נכיר את זה :) קצת היא יחידת המדידה המינימלית של מידע במחשב. שמו בא מהאנגלית " ספרה בינארית " - "מספר בינארי". ניתן לבטא ביט כאחד משני מספרים: 1 או 0. יש מערכת מספרים מיוחדת המבוססת על אחדים ואפסים - בינארית. לא נעמיק בג'ונגל של המתמטיקה ורק נציין שניתן להמיר כל מספר בג'אווה לצורתו הבינארית. כדי לעשות זאת אתה צריך להשתמש בשיעורי עטיפה. פעולות ביטוויזיות - 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.
  • ~- אופרטור "NOT" באופן סיביות.

זה עובד פשוט מאוד: הוא עובר על כל סיביות במספר שלנו ומשנה את ערכו להיפך: אפס לאחת, אחד לאפס. אם נחיל אותו על המספר שלנו 342, זה מה שנקבל: 101010110 - המספר 342 בבינארי 010101001 - התוצאה של הביטוי ~342 אבל מכיוון שמשתנה int לוקח 4 בתים, כלומר. 32 סיביות, למעשה, המספר במשתנה מאוחסן כך: 00000000 00000000 00000001 01010110- המספר 342 במשתנה מסוג int ב-java 11111111 11111111 11111110 10101001- התוצאה של הביטוי ~342 ב-java בואו ננסה לעשות זאת בפועל:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(~x));
   }
}
פלט מסוף:
11111111111111111111111010101001
  • &- אופרטור סיביות "AND"

כפי שאתה יכול לראות, הוא כתוב די דומה ל"AND" ( &&). האופרטור &&, כזכור, מחזיר trueרק אם שני האופרנדים נכונים. Bitwise &עובד בצורה דומה: היא משווה שני מספרים טיפין טיפין. התוצאה של השוואה זו היא המספר השלישי. לדוגמה, ניקח את המספרים 277 ו-432: 100010101 - המספר 277 בצורה בינארית 110110000 - המספר 432 בצורה בינארית לאחר מכן, האופרטור &משווה את הסיביות הראשונה של המספר העליון עם הסיביות הראשונה של התחתון. מכיוון שזהו אופרטור "AND", התוצאה תהיה שווה ל-1 רק אם שני הסיביות שוות ל-1. בכל שאר המקרים התוצאה תהיה 0. 100010101 & 110110000 _______________ 100010000 - תוצאת העבודה & תחילה נשווה את הביטים הראשונים של שני מספרים אחד עם השני, ואז סיביות שניות, שלישיות וכו'. כפי שאתה יכול לראות, רק בשני מקרים היו שתי הסיביות במספרים שוות ל-1 (הסיביות הראשונה והחמישית). התוצאה של כל ההשוואות האחרות הייתה 0. לכן, בסופו של דבר קיבלנו את המספר 100010000. בשיטה העשרונית הוא מתאים למספר 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
ספרנו הכל נכון! :)
  • ^- OR בלעדי בשיטת סיביות (ידוע גם בשם XOR)
עוד לא נתקלנו במפעיל כזה. אבל אין בזה שום דבר מסובך. זה נראה כמו "או" רגיל. ההבדל הוא אחד: "או" רגיל מחזיר trueאם לפחות אופרנד אחד נכון. אבל לא בהכרח אחד - אם שניהם קיימים true- אז התוצאה true. אבל ה"או" הבלעדי חוזר trueרק אם אחד מהאופרנדים נכון. אם שני האופרנדים נכונים, "או" רגיל יחזור true("לפחות אחד נכון"), אבל או בלעדי יחזור false. לכן זה נקרא אקסקלוסיבי. הכרת העיקרון של פעולות סיביות קודמות, אתה כנראה יכול בקלות לבצע את פעולת 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;//meaning
       int y = 3;//quantity

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

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
פלט מסוף:

512
זה נכון! בתיאוריה, ניתן להזיז ביטים ללא הגבלת זמן. אבל מכיוון שיש לנו את המספר int, יש רק 32 תאים זמינים. מתוכם, 7 כבר תפוסים על ידי המספר 64 (1,000,000). לכן, אם נעשה, למשל, 27 תזוזות שמאלה, היחידה היחידה שלנו תצא מהטווח ו"תחליף". רק אפסים יישארו!
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 26;//quantity

       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;//meaning
       int y = 2;//quantity

       int z = (x >> y);
       System.out.println(z);
   }
}
פעולות ביטוויזיות - 5פעולות ביטוויזיות - 6כתוצאה מההזזה ב-2 ימינה, שני האפסים הקיצוניים של המספר שלנו יצאו מחוץ לטווח ונמחקו. קיבלנו את המספר 10000, שבמערכת העשרונית מתאים למספר 16. פלט לקונסולה:

16
כלל פשוט לזכירת תזוזות ימינה: כל תזוזה ימינה מתחלקת בשניים, וזורקת כל שארית. לדוגמה, 35 >> 2 זה אומר שעלינו לחלק 35 ב-2 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 = true

    boolean x = true && 144 <= 119;
  • 144 <= 119 = false

    boolean x = true && false;
  • ולבסוף, המפעיל האחרון יבוצע &&.

    boolean x = true && false;

    boolean x = false;

    לאופרטור החיבור ( +), למשל, יש עדיפות גבוהה יותר מאופרטור ההשוואה !=("לא שווה");

    לכן בביטוי:

    boolean x = 7 != 6+1;

    תחילה תתבצע הפעולה 6+1, לאחר מכן הסימון 7!=7 (false), ובסוף התוצאה תוקצה falseלמשתנה x. להקצאה יש בדרך כלל את העדיפות הנמוכה ביותר מכל הפעולות - תסתכל בטבלה.

פיו! ההרצאה שלנו הייתה ארוכה, אבל עשית את זה! אם אינכם מבינים עד תום חלקים מסוימים של זה ושל ההרצאות הקודמות, אל דאגה, אנו ניגע בנושאים אלו יותר מפעם אחת בעתיד. הנה כמה קישורים שימושיים עבורך:
  • אופרטורים לוגיים - הרצאה של JavaRush בנושא פעולות לוגיות. לא נגיע אליהם בקרוב, אבל אתה יכול לקרוא אותם עכשיו, לא יהיה שום נזק
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION