ตัวดำเนินการระดับบิตคืออะไร?


130

ฉันเป็นคนที่เขียนโค้ดเพื่อความสนุกสนานและไม่ได้เจาะลึกลงไปในสภาพแวดล้อมทางวิชาการหรือวิชาชีพดังนั้นสิ่งต่างๆเช่นตัวดำเนินการระดับบิตเหล่านี้จึงหนีฉันไป

ฉันกำลังอ่านบทความเกี่ยวกับ JavaScript ซึ่งเห็นได้ชัดว่ารองรับการทำงานแบบบิต ฉันมักจะเห็นการดำเนินการนี้กล่าวถึงในสถานที่ต่างๆและฉันพยายามอ่านเพื่อหาว่ามันคืออะไรกันแน่ แต่ดูเหมือนจะไม่เข้าใจเลย แล้วพวกเขาคืออะไร? ตัวอย่างชัดเจนจะดีมาก! : D

คำถามเพิ่มเติมอีกสองสามข้อ - การใช้งานบิตไวซ์มีอะไรบ้าง คุณจะใช้เมื่อใด


2
สำหรับคำถามเพิ่มเติมคุณอาจต้องการเพิ่มคำถาม SO ใหม่และอ้างอิงคำถามนี้ คุณอาจจะได้รับคำตอบที่ดีกว่านี้
Greg Hewgill

คำตอบ:


187

เนื่องจากไม่มีใครเจาะประเด็นว่าเหตุใดสิ่งเหล่านี้จึงมีประโยชน์:

ฉันใช้การดำเนินการระดับบิตมากเมื่อทำงานกับแฟล็ก ตัวอย่างเช่นหากคุณต้องการส่งต่อชุดของแฟล็กไปยังการดำเนินการ (เช่นFile.Open()เปิดใช้งานโหมดอ่านและโหมดเขียนทั้งคู่) คุณสามารถส่งผ่านค่าเหล่านี้เป็นค่าเดียวได้ สิ่งนี้ทำได้โดยการกำหนดแฟล็กที่เป็นไปได้แต่ละรายการซึ่งเป็นบิตของตัวเองในบิตเซ็ต (ไบต์สั้น int หรือยาว) ตัวอย่างเช่น:

 Read: 00000001
Write: 00000010

ดังนั้นหากคุณต้องการผ่านการอ่านและเขียนคุณจะต้องผ่าน (อ่าน | เขียน) ซึ่งจะรวมทั้งสองเข้าด้วยกัน

00000011

ซึ่งสามารถถอดรหัสได้ในอีกด้านหนึ่งเช่น:

if ((flag & Read) != 0) { //...

ซึ่งตรวจสอบ

00000011 &
00000001

ซึ่งส่งคืน

00000001

ซึ่งไม่ใช่ 0 ดังนั้นแฟล็กจึงระบุ READ

คุณสามารถใช้ XOR เพื่อสลับบิตต่างๆ ฉันเคยใช้สิ่งนี้เมื่อใช้แฟล็กเพื่อระบุอินพุตทิศทาง (ขึ้นลงซ้ายขวา) ตัวอย่างเช่นหากสไปรต์เคลื่อนที่ในแนวนอนและฉันต้องการให้สไปรท์หมุนไปรอบ ๆ :

     Up: 00000001
   Down: 00000010
   Left: 00000100
  Right: 00001000
Current: 00000100

ฉันเพียงแค่ XOR ค่าปัจจุบันด้วย (LEFT | RIGHT) ซึ่งจะปิด LEFT และเปิดขวาในกรณีนี้

Bit Shifting มีประโยชน์ในหลายกรณี

x << y

เหมือนกับ

x * 2 ปี

หากคุณต้องการคูณด้วยกำลังสองอย่างรวดเร็ว แต่ระวังการเปลี่ยน 1 บิตเป็นบิตด้านบนซึ่งจะทำให้จำนวนเป็นลบเว้นแต่จะไม่ได้ลงนาม นอกจากนี้ยังมีประโยชน์เมื่อจัดการกับข้อมูลขนาดต่างๆ ตัวอย่างเช่นการอ่านจำนวนเต็มจากสี่ไบต์:

int val = (A << 24) | (B << 16) | (C << 8) | D;

สมมติว่า A เป็นไบต์ที่สำคัญที่สุดและ D น้อยที่สุด มันจะจบลงด้วย:

A = 01000000
B = 00000101
C = 00101011
D = 11100011
val = 01000000 00000101 00101011 11100011

สีมักจะถูกจัดเก็บด้วยวิธีนี้ (โดยไบต์ที่สำคัญที่สุดจะถูกละเว้นหรือใช้เป็นอัลฟ่า):

A = 255 = 11111111
R = 21 = 00010101
G = 255 = 11111111
B = 0 = 00000000
Color = 11111111 00010101 11111111 00000000

หากต้องการค้นหาค่าอีกครั้งเพียงแค่เลื่อนบิตไปทางขวาจนกว่าจะอยู่ด้านล่างสุดจากนั้นปิดบังบิตลำดับที่สูงกว่าที่เหลือ:

Int Alpha = Color >> 24
Int Red = Color >> 16 & 0xFF
Int Green = Color >> 8 & 0xFF
Int Blue = Color & 0xFF

0xFFเหมือนกับ11111111. โดยพื้นฐานแล้วสำหรับ Red คุณจะทำสิ่งนี้:

Color >> 16 = (filled in 00000000 00000000)11111111 00010101  (removed 11111111 00000000)
00000000 00000000 11111111 00010101 &
00000000 00000000 00000000 11111111 =
00000000 00000000 00000000 00010101 (The original value)

x << n ดังนั้น n ต้องอยู่ในรูปของค่า 2 ^?
Ahmed C

28

เป็นที่น่าสังเกตว่าตารางความจริงบิตเดียวที่แสดงเป็นคำตอบอื่น ๆ ทำงานกับบิตอินพุตครั้งละหนึ่งหรือสองบิตเท่านั้น จะเกิดอะไรขึ้นเมื่อคุณใช้จำนวนเต็มเช่น:

int x = 5 & 6;

คำตอบอยู่ที่การขยายไบนารีของแต่ละอินพุต:

  5 = 0 0 0 0 0 1 0 1
& 6 = 0 0 0 0 0 1 1 0
---------------------
      0 0 0 0 0 1 0 0

แต่ละคู่ของบิตในแต่ละคอลัมน์จะทำงานผ่านฟังก์ชัน "AND" เพื่อให้บิตเอาต์พุตที่สอดคล้องกันในบรรทัดล่างสุด ดังนั้นคำตอบของนิพจน์ข้างต้นคือ 4 CPU ได้ทำ (ในตัวอย่างนี้) การดำเนินการ "AND" ที่แยกจากกัน 8 รายการสำหรับแต่ละคอลัมน์

ฉันพูดถึงเรื่องนี้เพราะฉันยังจำได้ว่ามี "AHA!" ช่วงเวลาที่ฉันได้เรียนรู้เกี่ยวกับเรื่องนี้เมื่อหลายปีก่อน


ว้าวนั่นเข้าท่ากว่าตอนนี้ ฟังดูซับซ้อนกว่าที่เห็นได้ชัด ขอบคุณ ฉันไม่แน่ใจว่าจะเลือกคำตอบไหนดีเพราะมีคำตอบดีๆมากมายและฉันไม่สามารถโหวตได้ .. ขอบคุณ
คลิก

27

ตัวดำเนินการ Bitwise คือตัวดำเนินการที่ทำงานทีละบิต

และเป็น 1 ก็ต่อเมื่ออินพุตทั้งสองเป็น 1

หรือคือ 1 หากอินพุตหนึ่งหรือมากกว่าเป็น 1

XOR คือ 1 ก็ต่อเมื่ออินพุตตัวใดตัวหนึ่งเป็น 1 เท่านั้น

ไม่เป็น 1 ก็ต่อเมื่ออินพุตเป็น 0

สิ่งเหล่านี้สามารถอธิบายได้ดีที่สุดว่าเป็นตารางความจริง ความเป็นไปได้ของอินพุตอยู่ที่ด้านบนและด้านซ้ายบิตผลลัพธ์คือหนึ่งในสี่ (สองในกรณีที่ไม่ใช่เนื่องจากมีเพียงอินพุตเดียว) ที่แสดงที่จุดตัดของอินพุตทั้งสอง

AND|0 1      OR|0 1
---+----    ---+----
  0|0 0       0|0 1
  1|0 1       1|1 1

XOR|0 1     NOT|0 1
---+----    ---+---
  0|0 1        |1 0
  1|1 0

ตัวอย่างหนึ่งคือถ้าคุณต้องการเพียง 4 บิตล่างของจำนวนเต็มคุณและมันด้วย 15 (ไบนารี 1111) ดังนั้น:

    203: 1100 1011
AND  15: 0000 1111
------------------
 IS  11: 0000 1011

16

เหล่านี้คือตัวดำเนินการระดับบิตทั้งหมดที่รองรับใน JavaScript:

  • op1 & op2- ตัวANDดำเนินการเปรียบเทียบสองบิตและสร้างผลลัพธ์ของ 1 ถ้าทั้งสองบิตเป็น 1; มิฉะนั้นจะคืนค่า 0

  • op1 | op2- ตัวORดำเนินการเปรียบเทียบสองบิตและสร้างผลลัพธ์เป็น 1 หากบิตเสริมกัน มิฉะนั้นจะคืนค่า 0

  • op1 ^ op2- ตัวEXCLUSIVE-ORดำเนินการเปรียบเทียบสองบิตและส่งคืน 1 หากบิตใดบิตหนึ่งเป็น 1 และให้ 0 หากบิตทั้งสองเป็น 0 หรือ 1

  • ~op1- ตัวCOMPLEMENTดำเนินการใช้เพื่อสลับบิตทั้งหมดของตัวถูกดำเนินการ

  • op1 << op2- ตัวSHIFT LEFTดำเนินการย้ายบิตไปทางซ้ายทิ้งบิตทางซ้ายสุดและกำหนดบิตทางขวาสุดเป็น 0 การย้ายไปทางซ้ายแต่ละครั้งจะคูณ op1 ด้วย 2 อย่างมีประสิทธิภาพ

  • op1 >> op2- ตัวSHIFT RIGHTดำเนินการจะย้ายบิตไปทางขวาทิ้งบิตทางขวาสุดและกำหนดบิตทางซ้ายสุดเป็น 0 การย้ายไปทางขวาแต่ละครั้งจะแบ่ง op1 ออกเป็นครึ่งหนึ่งอย่างมีประสิทธิภาพ บิตเครื่องหมายซ้ายสุดจะถูกเก็บรักษาไว้

  • op1 >>> op2- ตัวดำเนินการSHIFT RIGHT- ZERO FILLย้ายบิตไปทางขวาทิ้งบิตทางขวาสุดและกำหนดบิตทางซ้ายสุดเป็น 0 การย้ายไปทางขวาแต่ละครั้งจะแบ่ง op1 ออกเป็นครึ่งหนึ่งอย่างมีประสิทธิภาพ บิตเครื่องหมายซ้ายสุดจะถูกทิ้ง


"if the bits are complementary" - บาท?
Andrey Tyukin

@AndreyTyukin สองบิตเสริมกันถ้าหนึ่งในนั้นคือ 1 และอีกอันคือ 0
Jeff Hillman

@JeffHillman ตามคำอธิบายของคุณในความคิดเห็น 1 และ 1 ไม่ใช่ "เสริม" แล้วมันก็ไม่ชัดเจนสำหรับฉันว่าทำไม1 | 1ให้1และไม่0และ|ควรจะแตกต่างจาก^อย่างไร ฉันต้องใช้คำถาม / คำตอบนี้เป็นเป้าหมายที่ซ้ำกันเมื่อไม่กี่วันที่ผ่านมาและฉันหวังว่าหลังจาก 10 ปีจะมีการทำสำเนาตามรูปแบบบัญญัติที่ชัดเจนขึ้นสำหรับคำถามประเภทนี้
Andrey Tyukin

4

หากต้องการแยกย่อยอีกเล็กน้อยมันมีส่วนเกี่ยวข้องกับการแทนค่าไบนารีของค่าที่เป็นปัญหา

ตัวอย่างเช่น (เป็นทศนิยม):
x = 8
y = 1

จะออกมาเป็น (ในไบนารี):
x = 1,000
y = 0001

จากนั้นคุณสามารถทำการคำนวณเช่น 'และ' หรือ 'หรือ'; ในกรณีนี้:
x | y =
1000 
0001 |
------
1001

หรือ ... 9 ในทศนิยม

หวังว่านี่จะช่วยได้


|เป็นการดำเนินการหรือ?
Si8

ด้วยเหตุผลบางอย่างสิ่งนี้เหมาะสมกับฉันมากที่สุด ยังไม่แน่ใจเกี่ยวกับ x | y = 1000 0001 |ส่วนนี้
samayo

4

เมื่อมีการกล่าวถึงคำว่า "bitwise" บางครั้งก็มีการชี้แจงว่าไม่ใช่ตัวดำเนินการ "ตรรกะ"

ยกตัวอย่างเช่นใน JavaScript, ผู้ประกอบการระดับบิตรักษาตัวถูกดำเนินการของพวกเขาเป็นลำดับของ 32 บิต (ศูนย์และคนบริการ) ; ในขณะเดียวกันตัวดำเนินการเชิงตรรกะมักใช้กับค่าบูลีน (ตรรกะ)แต่สามารถทำงานกับชนิดที่ไม่ใช่บูลีนได้

ยกตัวอย่าง expr1 && expr2

ส่งคืน expr1 หากสามารถแปลงเป็นเท็จ มิฉะนั้นจะคืนค่า expr2 ดังนั้นเมื่อใช้กับค่าบูลีน && จะคืนค่าจริงหากตัวถูกดำเนินการทั้งสองเป็นจริง มิฉะนั้นจะส่งกลับเท็จ

a = "Cat" && "Dog"     // t && t returns Dog
a = 2 && 4     // t && t returns 4

ตามที่คนอื่น ๆ สังเกต 2 & 4 เป็นบิตและดังนั้นมันจะส่งกลับ 0

คุณสามารถคัดลอกสิ่งต่อไปนี้ไปยัง test.html หรือบางสิ่งและทดสอบ:

<html>
<body>
<script>
    alert("\"Cat\" && \"Dog\" = " + ("Cat" && "Dog") + "\n"
        + "2 && 4 = " + (2 && 4) + "\n"
        + "2 & 4 = " + (2 & 4));
</script>

3

ในการเขียนโปรแกรมคอมพิวเตอร์ดิจิทัลการทำงานแบบบิตจะดำเนินการบนรูปแบบบิตหรือตัวเลขไบนารีตั้งแต่หนึ่งบิตขึ้นไปที่ระดับของแต่ละบิต เป็นการดำเนินการที่รวดเร็วและเป็นแบบดั้งเดิมที่ได้รับการสนับสนุนโดยตรงจากโปรเซสเซอร์และใช้เพื่อจัดการกับค่าสำหรับการเปรียบเทียบและการคำนวณ

การดำเนินงาน :

  • บิตและ

  • บิตหรือ

  • บิตไม่

  • XOR แบบบิต

  • ฯลฯ

รายการ

    AND|0 1        OR|0 1 
    ---+----      ---+---- 
      0|0 0         0|0 1 
      1|0 1         1|1 1 

   XOR|0 1        NOT|0 1 
   ---+----       ---+--- 
     0|0 1           |1 0 
     1|1 0

เช่น.

    203: 1100 1011
AND  15: 0000 1111
------------------
  =  11: 0000 1011

การใช้ตัวดำเนินการระดับบิต

  • ตัวดำเนินการกะซ้ายและกะขวาเทียบเท่ากับการคูณและการหารด้วย x * 2 yตามลำดับ

เช่น.

int main()
{
     int x = 19;
     printf ("x << 1 = %d\n" , x <<1);
     printf ("x >> 1 = %d\n", x >>1);
     return 0;
}
// Output: 38 9
  • & สามารถใช้ตัวดำเนินการเพื่อตรวจสอบได้อย่างรวดเร็วว่าตัวเลขเป็นเลขคี่หรือคู่

เช่น.

int main()
{
    int x = 19;
    (x & 1)? printf("Odd"): printf("Even");
    return 0;
 }
// Output: Odd
  • ค้นหาขั้นต่ำของ x และ y อย่างรวดเร็วโดยไม่มีif elseคำสั่ง

เช่น.

int min(int x, int y)
{
    return y ^ ((x ^ y) & - (x < y))
}
  • การแปลงทศนิยมเป็นไบนารี

เช่น.

#include <stdio.h>
int main ()
{
    int n , c , k ;
    printf("Enter an integer in decimal number system\n " ) ;
    scanf( "%d" , & n );
    printf("%d in binary number
    system is: \n " , n ) ;
    for ( c = 31; c >= 0 ; c -- )
    {
         k = n >> c ;
         if ( k & 1 )
              printf("1" ) ;
         else
              printf("0" ) ;
      }
      printf(" \n " );
      return 0 ;
}
  • การเข้ารหัสประตู XOR เป็นเทคนิคที่ได้รับความนิยมเนื่องจากมีความสอดคล้องและถูกใช้โดยโปรแกรมเมอร์
  • ตัวดำเนินการ XOR แบบ bitwise เป็นตัวดำเนินการที่มีประโยชน์ที่สุดจากมุมมองการสัมภาษณ์ทางเทคนิค

การเปลี่ยนเกียร์แบบบิตใช้งานได้กับหมายเลข + ve เท่านั้น

นอกจากนี้ยังมีการใช้ตรรกะระดับบิตที่หลากหลาย


"Complixblity และ reare ... "?
Jonathan Cross

The left-shift and right-shift operators are equivalent to multiplication and division by x * 2y respectively.ถูกตัอง! muyiy.cn/question/program/102.html
xgqfrms

โซลูชันของฉันrepl.it/@xgqfrms/…
xgqfrms

1

มันอาจช่วยให้คิดอย่างนี้ นี่คือวิธีการทำงานของ AND (&):

โดยพื้นฐานแล้วบอกว่าเป็นตัวเลขทั้งสองนี้ดังนั้นหากคุณมีเลข 5 และ 3 สองตัวพวกมันจะถูกแปลงเป็นเลขฐานสองและคอมพิวเตอร์จะคิดว่า

         5: 00000101
         3: 00000011

มีทั้งหนึ่ง: 00000001 0 เป็นเท็จ 1 เป็นจริง

ดังนั้น AND ของ 5 และ 3 จึงเป็นหนึ่ง ตัวดำเนินการ OR (|) ทำสิ่งเดียวกันยกเว้นเพียงหนึ่งในตัวเลขที่ต้องเป็นหนึ่งในเอาต์พุต 1 ไม่ใช่ทั้งสอง


-5

ฉันได้ยินมาตลอดว่าตัวดำเนินการ JavaScript bitwise ช้าแค่ไหน ฉันได้ทำการทดสอบบางอย่างสำหรับบล็อกโพสต์ล่าสุดของฉันและพบว่าเร็วกว่าทางเลือกเลขคณิต 40% ถึง 80% ในการทดสอบหลายครั้ง บางทีพวกเขาอาจจะช้า ในเบราว์เซอร์สมัยใหม่ฉันชอบพวกเขา

ฉันมีกรณีหนึ่งในรหัสของฉันที่จะอ่านได้เร็วและง่ายขึ้นด้วยเหตุนี้ ฉันจะเปิดตาให้มากขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.