JavaRush /จาวาบล็อก /Random-TH /การดำเนินการ Bitwise ใน Java

การดำเนินการ Bitwise ใน Java

เผยแพร่ในกลุ่ม
คุณคงจะคุ้นเคยกับคำว่า "ตี" ถ้าไม่มาทำความรู้จักกันดีกว่า :) บิตคือหน่วยวัดข้อมูลขั้นต่ำในคอมพิวเตอร์ ชื่อของมันมาจากภาษาอังกฤษ " เลขฐานสอง " - "เลขฐานสอง" บิตสามารถแสดงเป็นหนึ่งในตัวเลขสองตัว: 1 หรือ 0 มีระบบตัวเลขพิเศษที่ยึดตามหน่วยและศูนย์ - ไบนารี่ เราจะไม่เจาะลึกเข้าไปในป่าแห่งคณิตศาสตร์ และเพียงสังเกตว่าตัวเลขใดๆ ใน Java สามารถแปลงเป็นรูปแบบไบนารีได้ ในการทำเช่นนี้คุณต้องใช้คลาส wrapper การดำเนินการระดับบิต - 1ตัวอย่างเช่น ต่อไปนี้เป็นวิธีดำเนินการกับตัวเลขint:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
เอาต์พุตคอนโซล:

101010110
1010 10110 (ฉันเพิ่มช่องว่างเพื่อให้อ่านง่าย) คือหมายเลข 342 ในรูปแบบไบนารี จริงๆ แล้วเราได้แบ่งตัวเลขนี้ออกเป็นแต่ละบิต - ศูนย์และบิต มันขึ้นอยู่กับพวกเขาว่าเราสามารถดำเนินการที่เรียกว่าระดับบิตได้
  • ~— ตัวดำเนินการระดับบิต “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” ( &&) &&ตามที่คุณจำได้ตัวดำเนินการ จะส่งกลับ 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
  • |- บิต "หรือ" หลักการทำงานเหมือนกัน - เราเปรียบเทียบตัวเลขสองตัวทีละนิด ตอนนี้ถ้าอย่างน้อยหนึ่งบิตเท่ากับ 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)
เราไม่เคยพบผู้ดำเนินการดังกล่าวมาก่อน แต่ไม่มีอะไรซับซ้อนเกี่ยวกับเรื่องนี้ ดูเหมือนว่าปกติ “หรือ” ความแตกต่างคือหนึ่ง: ธรรมดา “หรือ” จะส่งกลับ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 ค่า ศูนย์สุดขั้วสองตัวของตัวเลขของเราจึงอยู่นอกช่วงและถูกลบทิ้ง เราได้ตัวเลข 10,000 ซึ่งในระบบทศนิยมสอดคล้องกับหมายเลข 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 การดำเนินการทั้งหมดจึงถูกแยกออกเป็นตารางพิเศษ:

ลำดับความสำคัญของตัวดำเนินการ

ผู้ประกอบการ ลำดับความสำคัญ
โพสต์ฟิกซ์ expr++ expr--
เอกนารี ++expr --expr +expr ~ !
การคูณ * / %
สารเติมแต่ง + -
กะ << >> >>>
เชิงสัมพันธ์ < > <= >=อินสแตนซ์ของ
ความเท่าเทียมกัน == !=
ระดับบิตและ &
ระดับบิตพิเศษหรือ ^
รวมระดับบิตหรือ |
ตรรกะและ &&
ตรรกะหรือ ||
ประกอบไปด้วย ? :
งานที่มอบหมาย = += -= *= /= %= &= ^= |= <<= >>= >>>=
การดำเนินการทั้งหมดจะดำเนินการจากซ้ายไปขวา แต่คำนึงถึงลำดับความสำคัญด้วย ตัวอย่างเช่น ถ้าเราเขียน: 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