กรณีการใช้งานจริงของผู้ประกอบการระดับบิต [ปิด]


224

กรณีการใช้งานจริงของผู้ประกอบการระดับบิตต่อไปนี้มีอะไรบ้าง

  • และ
  • แฮคเกอร์
  • ไม่
  • หรือ
  • เลื่อนไปทางซ้าย / ขวา

1
ฉันจำได้ว่าเมื่อฉันเรียนรู้เกี่ยวกับพวกเขาครั้งแรกดูเหมือนว่าพวกเขาจะใช้เฉพาะในระดับต่ำ c ... แต่ตั้งแต่นั้นพวกเขาได้เข้ามาโดยกล่องเครื่องมือและฉันใช้พวกเขาบ่อยครั้งรวมถึงเมื่อทำการเขียนโปรแกรม "ระดับสูง" พวกเขาเหมือน + และ * สำหรับฉันตอนนี้
โอ๊ก

2
@Anon: ในใจของฉันโลกแห่งความจริงควรจะหมายถึงอะไร แต่การเขียนโปรแกรมระดับต่ำซึ่งเป็นการใช้งานที่ชัดเจนที่สุดของตัวดำเนินการระดับบิต
Olivier Lalonde



ยังสามารถใช้ไบนารี XOR เพื่อหาตัวเลขที่ขาดหายไปในการเรียงสับเปลี่ยน: martinkysel.com/codility-permmissingelem-solution
Janac Meena

คำตอบ:


216
  • บิตฟิลด์ (ธง)
    พวกเขาเป็นวิธีที่มีประสิทธิภาพมากที่สุดในการแสดงบางสิ่งบางอย่างที่รัฐถูกกำหนดโดยคุณสมบัติ "ใช่หรือไม่" หลายอย่าง ACLs เป็นตัวอย่างที่ดี ถ้าคุณสมมติว่ามีการให้สิทธิ์แบบไม่ต่อเนื่อง 4 ครั้ง (อ่านเขียนดำเนินการเปลี่ยนนโยบาย) จะดีกว่าถ้าเก็บไว้ใน 1 ไบต์แทนที่จะเสีย 4 ซึ่งสามารถแมปกับประเภทการแจงนับในหลายภาษาเพื่อความสะดวกที่เพิ่มขึ้น

  • การสื่อสารผ่านพอร์ต / ซ็อกเก็ต
    เกี่ยวข้องกับ checksums, parity, บิตหยุด, อัลกอริทึมการควบคุมการไหลและอื่น ๆ ซึ่งโดยทั่วไปจะขึ้นอยู่กับค่าตรรกะของแต่ละไบต์เมื่อเทียบกับค่าตัวเลขเนื่องจากสื่ออาจส่งสัญญาณได้เพียงบิตเดียว เวลา.

  • การบีบอัดการเข้ารหัส
    ทั้งสองอย่างนี้ขึ้นอยู่กับอัลกอริทึมแบบบิตบิตเป็นอย่างมาก ดูอัลกอริธึมแบบยุบสำหรับตัวอย่าง - ทุกอย่างเป็นบิตไม่ใช่ไบต์

  • เครื่องจักรสถานะ จำกัด
    ฉันกำลังพูดถึงฮาร์ดแวร์ที่ฝังอยู่ในฮาร์ดแวร์บางชิ้นเป็นหลักถึงแม้ว่าพวกเขาจะสามารถพบได้ในซอฟต์แวร์เช่นกัน เหล่านี้จะรวมกันในธรรมชาติ - พวกเขาจะได้รับอย่างแท้จริง "รวบรวม" ลงไปที่พวงของประตูตรรกะดังนั้นพวกเขาจะต้องมีการแสดงเป็นAND, OR, NOTฯลฯ

  • กราฟิก มีพื้นที่ไม่เพียงพอที่นี่เพื่อเข้าสู่ทุกพื้นที่ที่ตัวดำเนินการเหล่านี้ใช้ในการเขียนโปรแกรมกราฟิก XOR(หรือ^) น่าสนใจเป็นพิเศษที่นี่เพราะการใช้อินพุตเดียวกันครั้งที่สองจะเป็นการยกเลิกครั้งแรก GUI ที่เก่ากว่านั้นใช้เพื่อเน้นการเลือกและการซ้อนทับอื่น ๆ เพื่อขจัดความจำเป็นในการวาดใหม่ที่มีราคาแพง พวกมันยังมีประโยชน์ในโปรโตคอลกราฟิกช้า (เช่นเดสก์ท็อประยะไกล)

นี่เป็นเพียงตัวอย่างแรก ๆ ที่ฉันพบ - นี่เป็นรายการที่ไม่ครบถ้วน


สวัสดี @Aaraught คุณได้แบ่งปันความรู้ที่ดีกับเราเป็นอย่างมาก ฉันสนใจที่จะเรียนรู้เพิ่มเติมเกี่ยวกับกรณีในโลกแห่งความเป็นจริงของ Bitwise Operator คุณช่วยแบ่งปันการอ้างอิงของคุณกับเราได้ไหม?
Heena Hussain

การดำเนินการระดับบิตมีประโยชน์สำหรับการคำนวณแบบเวกเตอร์หรือไม่?
Aaron Franke

47

มันแปลกหรือเปล่า

(value & 0x1) > 0

มันหารด้วยสอง (คู่) หรือไม่?

(value & 0x1) == 0

3
ขึ้นอยู่กับค่าภาษาของคุณ & 0x1> 0 อาจถูกแยกวิเคราะห์เป็นค่า & (0x1> 0)
leeeroy

3
@leeeroy - จริงเพียงพอ เพิ่ม parens บางส่วน
เซท

เครื่องมือเพิ่มประสิทธิภาพที่ทันสมัยจะแปลงนิพจน์เช่น (ค่า% 2)! = 0 ให้เป็นนิพจน์ด้านบนโดยอัตโนมัติ godbolt.org/z/mYEBH4
Ferrarezi

26

นี่คือสำนวนทั่วไปที่ใช้จัดการกับค่าสถานะที่จัดเก็บเป็นบิตส่วนบุคคล

enum CDRIndicators {
  Local = 1 << 0,
  External = 1 << 1,
  CallerIDMissing = 1 << 2,
  Chargeable = 1 << 3
};

unsigned int flags = 0;

ตั้งค่าสถานะ Chargeable:

flags |= Chargeable;

ล้างธงของ CallerIDMissing:

flags &= ~CallerIDMissing;

ทดสอบว่าตั้งค่า CallerIDMissing และ Chargeable:

if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {

}

25

ฉันใช้การดำเนินการระดับบิตในการนำโมเดลความปลอดภัยมาใช้กับ CMS มีหน้าซึ่งผู้ใช้สามารถเข้าถึงได้หากอยู่ในกลุ่มที่เหมาะสม ผู้ใช้อาจอยู่ในหลายกลุ่มดังนั้นเราจำเป็นต้องตรวจสอบว่ามีจุดตัดระหว่างกลุ่มผู้ใช้กับกลุ่มเพจหรือไม่ ดังนั้นเราจึงกำหนดตัวระบุ power-of-2 ที่ไม่ซ้ำกันในแต่ละกลุ่มเช่น:

Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100

เราหรือค่าเหล่านี้ร่วมกันและเก็บค่า (เป็น int เดียว) กับหน้า เช่นหากกลุ่ม A & B สามารถเข้าถึงหน้าได้เราจะเก็บค่า 3 (ซึ่งเป็นเลขฐานสองคือ 00000011) เป็นตัวควบคุมการเข้าถึงหน้า ในทำนองเดียวกันเราเก็บค่าตัวระบุกลุ่ม ORed ไว้กับผู้ใช้เพื่อแสดงกลุ่มที่อยู่

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


24

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

volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t          value;
uint32_t          set_bit   = 0x00010000;
uint32_t          clear_bit = 0x00001000;

value = *register;            // get current value from the register
value = value & ~clear_bit;   // clear a bit
value = value | set_bit;      // set a bit
*register = value;            // write it back to the register

นอกจากนี้htonl()และhtons()จะดำเนินการโดยใช้&และ|ผู้ประกอบการ (บนเครื่องที่มีendianness (สั่งไบต์) ไม่ตรงกับคำสั่งซื้อระบบเครือข่าย):

#define htons(a) ((((a) & 0xff00) >> 8) | \
                  (((a) & 0x00ff) << 8))

#define htonl(a) ((((a) & 0xff000000) >> 24) | \
                  (((a) & 0x00ff0000) >>  8) | \
                  (((a) & 0x0000ff00) <<  8) | \
                  (((a) & 0x000000ff) << 24))

7
ไม่ใช่ทุกคนที่พูดด้วยเครื่อง ตัวอย่างที่สองของคุณทำอะไรอยู่
ChaosPandion

7
htons()และhtonl()เป็นฟังก์ชั่น POSIX เพื่อสลับ a shortหรือ a longจากโฮสต์ ( h) endianness ไปยังเครือข่าย ( n) ลำดับไบต์
Carl Norum

คุณสามารถใช้วิธีที่คล้ายกันเพื่อทำการกลับรายการบิตในการดำเนินการ O (logN)
Mike DeSimone

ฮ่า ๆ ตอนที่ฉันเห็นครั้งแรกฉันคิดว่ามันเป็นการชุมนุม!
0x499602D2

ไม่ใช่htonl()สำหรับค่า 32 บิตintใช่ไหม longหมายถึง 64- บิตในหลายภาษา
Aaron Franke

21

ฉันใช้พวกมันเพื่อรับค่า RGB (A) จากค่าสีที่บรรจุไว้


และมันทำได้เร็วจริงๆ!
Callum Rogers

ใน C # เป็นหนึ่งในกรณีที่เป็นทางออกที่ดีที่สุดสำหรับการอ่านและความเร็ว
CaptainCasey

4
บนเครื่องของฉัน(a & b) >> cเร็วกว่า 5 เท่าa % d / e(ทั้งสองวิธีในการแยกค่าสีเดียวจาก int ที่เป็นตัวแทน ARGB) ตามลำดับ 6.7 และ 35.2 สำหรับการวนซ้ำ 1 พันล้านครั้ง
Benji XVI

@BenjiXVI C # มีการเพิ่มประสิทธิภาพคอมไพเลอร์สำหรับสิ่งนี้ เหตุผลที่คุณสังเกตเห็นความแตกต่างความเร็วเป็นเพราะใน C # %ไม่ใช่โมดูลัสของผู้ประกอบการมันเป็นผู้ประกอบการที่เหลือ พวกมันเทียบเท่ากับค่าบวก แต่ต่างกับค่าลบ ถ้าคุณให้ข้อ จำกัด ที่เหมาะสม (ผ่านuintแทนintตัวอย่างเช่น) จากนั้นทั้งสองตัวอย่างที่ควรจะเป็นความเร็วเท่ากัน
Aaron Franke

ขอโทษฉันรู้ว่ามันนานแล้ว โปรดแสดงตัวอย่างวิธีใช้เพื่อรับค่า RGB ทุกค่า
Jinx

14

เมื่อฉันมีธงบูลีนจำนวนมากฉันชอบเก็บไว้ใน int

ฉันเอามันออกมาโดยใช้ bitwise-AND ตัวอย่างเช่น:

int flags;
if (flags & 0x10) {
  // Turn this feature on.
}

if (flags & 0x08) {
  // Turn a second feature on.
}

เป็นต้น


23
หวังว่าเหล่านั้นเป็นจริงคงที่ในรหัสของคุณจริงและตัวเลขไม่มายากล :)
Earlz

1
ตัวอย่างหนึ่งของการใช้ค่าสถานะบูลีนในโลกที่ไม่ใช่ระดับต่ำคือการทำสิ่งต่างๆด้วยแพลตฟอร์ม GUI ต่างๆ ตัวอย่างเช่นคุณอาจใช้ my_button.Style | = STYLE_DISABLED เพื่อปิด
MauriceL

1
ฉันรู้ว่าเรื่องนี้เป็นภาษาไม่เชื่อเรื่องพระเจ้า แต่ C ให้เป็นวิธีที่ง่ายต่อการทำเช่นนี้กับบิตเขตif (flags.feature_one_is_one) { // turn on feature }เพื่อให้คุณสามารถใช้สิ่งที่ต้องการ มันอยู่ในมาตรฐาน ANSI C ดังนั้นความสะดวกในการพกพาจึงไม่เป็นปัญหา
polandeer

มันคงจะดีถ้าได้รับคำอธิบายว่าโค้ดนี้ทำอะไรทำไมธงไม่เริ่มต้นคุณหมายถึงอะไรโดย "เก็บพวกมันทั้งหมดใน int" สัญกรณ์ที่ใช้ ...
Angelo Oparah

12

& = AND:
ปิดบังบิตเฉพาะ
คุณกำลังกำหนดบิตเฉพาะที่ควรแสดงหรือไม่แสดง 0x0 & x จะล้างบิตทั้งหมดในไบต์ในขณะที่ 0xFF จะไม่เปลี่ยน x 0x0F จะแสดงบิตในแทะล่าง

การแปลง:
เพื่อตัวแปรให้สั้นลงไปเป็นอีกตัวที่มีบิตเอกลักษณ์จำเป็นต้องปรับบิตเนื่องจาก -1 ใน int คือ 0xFFFFFFFF ในขณะที่ -1 ในความยาวคือ 0xFFFFFFFFFFFFFFFF เพื่อรักษาเอกลักษณ์ที่คุณใช้หน้ากากหลังจากการแปลง

| = หรือ
ตั้งค่าบิต บิตจะถูกตั้งค่าแบบอิสระหากมีการตั้งค่าไว้แล้ว โครงสร้างข้อมูลจำนวนมาก (บิตฟิลด์) มีค่าสถานะเช่น IS_HSET = 0, IS_VSET = 1 ซึ่งสามารถตั้งค่าแบบอิสระได้ ในการตั้งค่าสถานะคุณใช้ IS_HSET | IS_VSET (ใน C และแอสเซมบลีสะดวกมากในการอ่าน)

^ = XOR
ค้นหาบิตที่เหมือนหรือต่างกัน

~ = ไม่
พลิกบิต

มันสามารถแสดงให้เห็นว่าการดำเนินการบิตโลคัลที่เป็นไปได้ทั้งหมดสามารถนำไปใช้โดยการดำเนินการเหล่านี้ ดังนั้นถ้าคุณชอบคุณสามารถใช้คำสั่ง ADD เพียงอย่างเดียวโดยการใช้งานบิต

แฮ็กที่ยอดเยี่ยมบางอย่าง:

http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html


ต่อไปนี้คือการเชื่อมโยงที่ให้ตัวอย่างที่ดีของการใช้ประกอบการระดับบิตใน AS3 สำหรับดำเนินการทางคณิตศาสตร์ที่เร็วสุด ( แต่มันอาจจะมีแนวโน้มที่จะนำไปใช้กับภาษามากที่สุด) A: lab.polygonal.de/2007/05/10/bitwise-gems-fast- เลขจำนวนเต็ม
เน้นหนักเมื่อ

ฉันคิดว่า "ไม่" ควร= ~ไม่ใช่ไม่ใช่|=ซึ่งก็คือ
Mike DeSimone

สำหรับ& = AND- เหตุใดฉันจึงต้องการล้างบิตทั้งหมดทำไมฉันจึงต้องการรับรุ่นที่ไม่มีการแก้ไขของไบต์และฉันต้องทำอย่างไรกับตอดต่ำ
สับสน

1
@ สับสน00ถูกต้องวิธีที่เร็ว / ง่ายกว่าในการทำให้ผลลัพธ์เป็นโมฆะนั้นก็คือxorด้วยตนเอง ฉันสามารถคิดถึงเหตุผลบางอย่างที่คุณอาจต้องการแยกแทะเล็มที่ต่ำกว่า โดยเฉพาะอย่างยิ่งถ้าตอดต่ำนั้นเป็นส่วนหนึ่งของโครงสร้างข้อมูลและคุณต้องการใช้มันเป็นมาสก์หรือORใช้กับโครงสร้างอื่น
James M. Lay

11

การเข้ารหัสเป็นการดำเนินการระดับบิตทั้งหมด


4
จริงๆ? การประยุกต์ใช้การเข้ารหัสมีแนวโน้มที่จะใช้ ops ระดับบิต แต่อัลกอริทึมการเข้ารหัสมักจะอธิบายในแง่ของตัวเลขและไม่ได้อยู่ในแง่ของการเป็นตัวแทนบิต
Constantin

1
ดังนั้นคุณจะทำอย่างไรกับอัลกอริธึมที่นอกเหนือจากการใช้มัน? ฉันอยากรู้.
เรียกซ้ำ

2
@Constantin: ดูตัวอย่างคำอธิบายวิธีการนำ DES มาใช้: ( en.wikipedia.org/wiki/…
Wayne Conrad

1
@ recursive หากคุณถามฉันเป็นการส่วนตัว - ฉันไม่ได้ออกแบบอัลกอริธึมเข้ารหัสหรือใช้มัน แต่ผู้คนทำหลายสิ่งหลายอย่างเช่นวิเคราะห์พวกเขาเพื่อจุดอ่อนทางทฤษฎี
Constantin

@Constantin: ลองดูนี่เป็นเพียงตัวอย่างหนึ่งในหลาย ๆ เรื่องเกี่ยวกับวิธี (ส่วนหนึ่งของ) อัลกอริทึมการเข้ารหัสโดยทั่วไป: en.wikipedia.org/wiki/Substitution_box
SyntaxT3rr0r

9

คุณสามารถใช้มันเป็นวิธีที่รวดเร็วและสกปรกในการแฮชข้อมูล

int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;

8

ฉันเพิ่งใช้ bitwise-XOR ( ^) ประมาณสามนาทีที่ผ่านมาเพื่อคำนวณ checksum สำหรับการสื่อสารแบบอนุกรมกับ PLC ...


7

Bitwise & ใช้เพื่อปกปิด / แยกส่วนหนึ่งของไบต์

1 ตัวแปรไบต์

 01110010
&00001111 Bitmask of 0x0F to find out the lower nibble
 --------
 00000010

ตัวดำเนินการกะ (<< >>) พิเศษมักใช้สำหรับการคำนวณ


6

นี่คือตัวอย่างการอ่านสีจากภาพบิตแมปในรูปแบบไบต์

byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */

//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */

//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF;  /* This now returns a red colour between 0x00 and 0xFF.

ฉันหวังว่าตัวอย่างเล็ก ๆ นี้จะช่วย ....


5

ในโลกที่เป็นนามธรรมของภาษาสมัยใหม่ทุกวันนี้มีไม่มากนัก File IO เป็นสิ่งที่ง่ายต่อการนึกถึงแม้ว่าจะใช้การดำเนินการระดับบิตในสิ่งที่นำไปใช้แล้วและไม่ได้ใช้สิ่งที่ใช้การดำเนินการระดับบิต ยังเป็นตัวอย่างง่ายๆรหัสนี้แสดงให้เห็นถึงการลบคุณลักษณะอ่านอย่างเดียวในไฟล์ (เพื่อให้สามารถใช้กับ FileStream ใหม่ระบุ FileMode.Create) ใน c #:

//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
    FileAttributes attributes = File.GetAttributes(targetName);

    if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
        File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));

    File.Delete(targetName);
}

นี่คือตัวอย่างล่าสุด: ฉันสร้าง "ศูนย์ข้อความ" เพื่อส่งข้อความที่ปลอดภัยจากการติดตั้งแอปพลิเคชันแบบกระจายของเราไปยังอีกแอปหนึ่ง โดยพื้นฐานแล้วมันคล้ายกับอีเมลพร้อม Inbox, Outbox, Sent, ฯลฯ แต่ยังรับประกันการจัดส่งด้วยใบรับการอ่านดังนั้นจึงมีโฟลเดอร์ย่อยเพิ่มเติมนอกเหนือจาก "inbox" และ "ส่ง" สิ่งนี้มีความต้องการสำหรับฉันในการกำหนดโดยทั่วไปสิ่งที่ "ในกล่องจดหมาย" หรือ "ในโฟลเดอร์ที่ส่ง" ในโฟลเดอร์ที่ส่งฉันต้องรู้ว่ามีอะไรอ่านบ้างและยังไม่ได้อ่าน ในสิ่งที่ยังไม่ได้อ่านฉันจำเป็นต้องรู้ว่าได้รับอะไรและไม่ได้รับอะไร ฉันใช้ข้อมูลนี้เพื่อสร้างไดนามิกโดยที่ส่วนคำสั่งใดกรองแหล่งข้อมูลท้องถิ่นและแสดงข้อมูลที่เหมาะสม

นี่คือวิธีการรวมกันของ enum:

    public enum MemoView :int
    {
        InboundMemos = 1,                   //     0000 0001
        InboundMemosForMyOrders = 3,        //     0000 0011
        SentMemosAll = 16,                  //     0001 0000
        SentMemosNotReceived = 48,          //     0011
        SentMemosReceivedNotRead = 80,      //     0101
        SentMemosRead = 144,                //     1001
        Outbox = 272,                       //0001 0001 0000
        OutBoxErrors = 784                  //0011 0001 0000
    }

คุณเห็นสิ่งนี้ทำอะไร? โดย anding (&) ด้วยค่า enum "Inbox" InboundMemos ฉันรู้ว่า InboundMemosForMyOrders อยู่ในกล่องจดหมาย

ต่อไปนี้เป็นวิธีการสร้างและส่งคืนตัวกรองที่กำหนดมุมมองสำหรับโฟลเดอร์ที่เลือกในปัจจุบัน:

    private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
    {
        string filter = string.Empty;
        if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
        {
            filter = "<inbox filter conditions>";

            if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
            {
                filter += "<my memo filter conditions>";
            }
        }
        else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
        {
            //all sent items have originating system = to local
            filter = "<memos leaving current system>";

            if((view & MemoView.Outbox) == MemoView.Outbox)
            {
                ...
            }
            else
            {
                //sent sub folders
                filter += "<all sent items>";

                if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
                {
                    if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
                    {
                        filter += "<not received and not read conditions>";
                    }
                    else
                        filter += "<received and not read conditions>";
                }
            }
        }

        return filter;
    }

เรียบง่ายมาก แต่การใช้งานอย่างเป็นระเบียบที่ระดับนามธรรมซึ่งไม่จำเป็นต้องใช้การดำเนินการระดับบิต


4

การเข้ารหัส Base64 เป็นตัวอย่าง การเข้ารหัส Base64 ใช้เพื่อแสดงข้อมูลไบนารีเป็นอักขระที่พิมพ์ได้สำหรับการส่งผ่านระบบอีเมล (และวัตถุประสงค์อื่น ๆ ) การเข้ารหัส Base64 แปลงชุดข้อมูล 8 บิตเป็นดัชนีการค้นหาอักขระ 6 บิต การดำเนินการบิตการขยับและการ 'ไม่' มีประโยชน์อย่างมากสำหรับการใช้การดำเนินการบิตที่จำเป็นสำหรับการเข้ารหัสและถอดรหัส Base64

แน่นอนว่านี่เป็นเพียงหนึ่งในตัวอย่างที่นับไม่ถ้วน



4

โดยทั่วไปแล้วการดำเนินการในระดับบิตจะเร็วกว่าการทำทวีคูณ / หาร ดังนั้นหากคุณต้องการคูณตัวแปร x ด้วยการบอกว่า 9 คุณจะต้องทำx<<3 + xเร็วกว่าx*9ซึ่งจะเป็นไม่กี่รอบได้เร็วกว่าหากรหัสนี้อยู่ใน ISR คุณจะประหยัดเวลาตอบสนอง

ในทำนองเดียวกันถ้าคุณต้องการที่จะใช้อาร์เรย์เป็นคิวแบบวงกลมมันจะเร็วกว่า (และสวยงามกว่า) เพื่อจัดการกับการตรวจสอบรอบตัวด้วยการใช้บิตที่ชาญฉลาด (ขนาดอาร์เรย์ของคุณควรเป็นกำลัง 2) เช่นคุณสามารถใช้tail = ((tail & MASK) + 1)แทนtail = ((tail +1) < size) ? tail+1 : 0หากคุณต้องการแทรก / ลบ

นอกจากนี้หากคุณต้องการให้แฟล็กข้อผิดพลาดเก็บรหัสข้อผิดพลาดหลายรหัสพร้อมกันแต่ละบิตสามารถเก็บค่าแยกกันได้ คุณสามารถและมันด้วยรหัสข้อผิดพลาดของแต่ละบุคคลเป็นการตรวจสอบ นี้ใช้ในรหัสข้อผิดพลาด Unix

บิตแมป n-bit สามารถเป็นโครงสร้างข้อมูลที่ยอดเยี่ยมและกะทัดรัด หากคุณต้องการจัดสรรพูลทรัพยากรขนาด n เราสามารถใช้ n-bits เพื่อแสดงสถานะปัจจุบัน



3

เลขxกำลังของ 2 คืออะไร? (มีประโยชน์สำหรับตัวอย่างในอัลกอริธึมที่เพิ่มจำนวนตัวนับและการดำเนินการจะต้องดำเนินการเฉพาะจำนวนลอการิทึมเท่านั้น)

(x & (x - 1)) == 0

เลขxใดเป็นจำนวนเต็มสูงสุด (ตัวอย่างนี้สามารถใช้เพื่อค้นหาพลังงานขั้นต่ำ 2 ที่มากกว่าx)

x |= (x >>  1);
x |= (x >>  2);
x |= (x >>  4);
x |= (x >>  8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift

1จำนวนเต็มต่ำสุดxใด? (ช่วยค้นหาจำนวนครั้งที่หารด้วย 2)

x & -x

การเลื่อนขวาที่ไม่ได้ลงนามจะทำใน C โดยการหล่อ LHS เป็นประเภทที่ไม่ได้ลงนาม สูตรสุดท้ายของคุณไม่พบต่ำสุด [ชุด] บิตก็ตรวจสอบว่า X เป็นอำนาจของ 2. x & -xเพื่อหาสิ่งที่บิตชุดต่ำสุดที่ทำ
Potatoswatter

อืมคุณพูดถูกแล้วฉันแทนที่ x & -x ด้วยตัวอย่างแรกขอบคุณสำหรับการแก้ไข
Dimitris Andreou

3

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

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    if (i >= arr.length) 
        i = 0;
}

นี่เป็นวิธีการที่ง่ายที่สุดหากคุณต้องการหลีกเลี่ยงหากคำสั่งคุณสามารถใช้วิธีการโมดูลัสเช่น:

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    i = i % arr.length;
}

ข้อเสียของสองวิธีนี้คือตัวดำเนินการโมดูลัสนั้นมีราคาแพงเนื่องจากจะมองหาส่วนที่เหลือหลังจากการหารจำนวนเต็ม และวิธีแรกจะรันคำสั่งifในการวนซ้ำแต่ละครั้ง กับผู้ประกอบการระดับบิต แต่ถ้าความยาวของอาร์เรย์ของคุณเป็นอำนาจของ 2 คุณสามารถสร้างลำดับเช่น0 .. length - 1โดยการใช้&(และบิต) i & lengthผู้ประกอบการเช่นดังนั้น ดังนั้นเมื่อรู้สิ่งนี้รหัสจากด้านบนจึงกลายเป็น

int[] arr = new int[8];
int i = 0;
while (true){
    print(arr[i]);
    i = i + 1;
    i = i & (arr.length - 1);
}

นี่คือวิธีการทำงาน ในรูปแบบไบนารี่ทุกหมายเลขที่มีกำลังของ 2 ลบด้วย 1 จะแสดงเฉพาะกับตัวเลข ตัวอย่างเช่น 3 ในเลขฐานสองคือ117 คือ11115 คือ1111อะไรคุณจะได้รับแนวคิด ทีนี้เกิดอะไรขึ้นถ้าคุณ&มีจำนวนต่อเลขประกอบอยู่ในเลขฐานสอง? สมมติว่าเราทำสิ่งนี้:

num & 7;

หากnumมีขนาดเล็กหรือเท่ากับ 7 ผลลัพธ์จะเป็นnumเพราะแต่ละบิตบิต&กับ 1 เป็นตัวของมันเอง หากnumมีขนาดใหญ่กว่า 7 ในระหว่างการใช้&งานคอมพิวเตอร์จะพิจารณาค่าศูนย์นำหน้าของ 7 ซึ่งแน่นอนว่าจะเป็นศูนย์หลังจาก&การทำงานเฉพาะส่วนที่ต่อท้ายจะยังคงอยู่ เช่นเดียวกับในกรณีของ9 & 7ไบนารีมันจะดูเหมือน

1001 & 0111

ผลลัพธ์จะเป็น 0001 ซึ่งเป็น 1 ในทศนิยมและระบุองค์ประกอบที่สองในอาร์เรย์


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

@JanDoggen คุณพูดถูกฉันจะใส่มันในประโยคแรก สำหรับอาเรย์เป็นพลังของสองในประสบการณ์ของฉันมีมากกว่าสองสามครั้งเมื่อทำงาน อาจเป็นเพราะมันเกี่ยวข้องกับเครือข่ายและกราฟิก
user3552161

1
จุดของโพสต์นี้คือการแสดงให้เห็นว่าผู้ประกอบการระดับบิตมีประโยชน์สำหรับการสร้างลำดับของตัวเลข, 0, 1, 2, 3, 0, 1, 2 ... ลำดับเป็นเพียงคนแรกที่มาถึงใจ
user3552161

2

ฉันใช้มันสำหรับตัวเลือกแบบหลายตัวเลือกฉันเก็บค่าเดียวแทนที่จะเป็น 10 หรือมากกว่านี้


2

มันยังมีประโยชน์ในรูปแบบสัมพันธ์ sql สมมติว่าคุณมีตารางต่อไปนี้: BlogEntry, BlogCategory

ตามธรรมเนียมคุณสามารถสร้างความสัมพันธ์ nn ระหว่างพวกเขาโดยใช้ตาราง BlogEntryCategory หรือเมื่อไม่มีระเบียน BlogCategory มากคุณสามารถใช้ค่าหนึ่งใน BlogEntry เพื่อเชื่อมโยงไปยังหลาย ๆ BlogCategory เช่นเดียวกับที่คุณทำกับ enums ที่ถูกตั้งค่าสถานะใน RDBMS ส่วนใหญ่ ผู้ประกอบการที่รวดเร็วมากในการเลือกคอลัมน์ 'ตั้งค่าสถานะ' ...


2

เมื่อคุณต้องการเปลี่ยนบิตของเอาต์พุตไมโครคอนโทรลเลอร์บางส่วนเท่านั้น แต่การลงทะเบียนเพื่อเขียนเป็นไบต์คุณทำสิ่งนี้ (pseudocode):

char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs

แน่นอนว่าไมโครคอนโทรลเลอร์หลายตัวช่วยให้คุณสามารถเปลี่ยนแต่ละบิตได้ ...


นี่ควรเป็นภาษาอะไร
Carson Myers

@Carson: ไม่มีภาษานี่คือ pseudocode เมื่อฉันทำจริงไม่กี่ปีที่ผ่านมามันเป็นสภา แต่ฉันคิดว่ามันเป็นเรื่องง่ายที่จะทำใน C. ขอบคุณสำหรับหัวขึ้นฉันจะอัปเดตเพื่อให้ชัดเจน
Emilio M Bumachar

ฉันแก้ไขคำตอบเพื่อเปลี่ยนความคิดเห็นเพื่อให้การไฮไลต์ไม่ได้ฟัด และฉันรู้ว่าฉันคิดว่ามันอาจจะเป็น C แต่คุณใช้ 0b ... สัญกรณ์ที่ฉันต้องการมีให้ใน C.
Carson Myers

2

ถ้าคุณเคยต้องการที่จะคำนวณ mod หมายเลขของคุณ (%) อำนาจบางอย่างของ 2, คุณสามารถใช้ซึ่งในกรณีนี้เป็นเช่นเดียวกับyourNumber & 2^N-1yourNumber % 2^N

number % 16 = number & 15;
number % 128 = number & 127;

นี่อาจเป็นประโยชน์เพียงอย่างเดียวในการเป็นทางเลือกในการดำเนินการกับโมดูลัสด้วยการจ่ายเงินปันผลที่ยิ่งใหญ่นั่นคือ 2 ^ N ... แต่ถึงกระนั้นความเร็วที่เพิ่มขึ้นจากการดำเนินการของโมดูลัสนั้นก็ไม่สำคัญ ฉันสงสัยว่าคอมไพเลอร์สมัยใหม่จะทำการปรับให้เหมาะสมแล้ว ใครรู้เพิ่มเติมเกี่ยวกับเรื่องนี้?


คอมไพเลอร์จะใช้การเพิ่มประสิทธิภาพนี้ ... แต่ถ้าคุณไม่ทราบเกี่ยวกับการเพิ่มประสิทธิภาพของคุณอาจล้มเหลวที่จะเลือกตัวหารที่เป็นพลังที่แท้จริงของ 2.
เบนยต์

มันขึ้นอยู่กับสถานการณ์ ใน C # นี้จะให้ผลลัพธ์ที่แตกต่างกันเช่นเดียว%กับการดำเนินการส่วนที่เหลือพวกเขาปฏิบัติต่อเชิงลบแตกต่างกัน อย่างไรก็ตามถ้าคุณผ่านuintไป%แล้วคอมไพเลอร์ C # จะสร้างรหัสเครื่องโดยใช้ bitwise และเมื่ออาร์กิวเมนต์ที่สองเป็นพลังงานที่รู้จักกันล่วงหน้าของทั้งสอง
Aaron Franke


1

มีคำถามจริงที่ใช้ในโลกของฉันที่นี่ -
ตอบกลับการแจ้งเตือน WM_KEYDOWN แรกเท่านั้น

เมื่อบริโภคข้อความ WM_KEYDOWN ใน windows C api bit 30 ระบุสถานะคีย์ก่อนหน้า ค่าเป็น 1 ถ้าคีย์ไม่ทำงานก่อนที่ข้อความจะถูกส่งหรือเป็นศูนย์ถ้าคีย์ขึ้น


1

ส่วนใหญ่จะใช้สำหรับการดำเนินการระดับบิต (ประหลาดใจ) ต่อไปนี้เป็นตัวอย่างโลกแห่งความจริงที่พบใน PHP codebase

การเข้ารหัสอักขระ:

if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {

โครงสร้างข้อมูล:

ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;

ไดรเวอร์ฐานข้อมูล:

dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);

การใช้งานคอมไพเลอร์:

opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;

1

เมื่อใดก็ตามที่ฉันเริ่มเขียนโปรแกรม C ครั้งแรกฉันเข้าใจตารางความจริงและสิ่งต่าง ๆ ทั้งหมด แต่มันก็ไม่ได้คลิกด้วยวิธีการใช้งานจริงจนกว่าฉันจะอ่านบทความนี้http://www.gamedev.net/reference/articles/article1563.asp (ซึ่งให้ตัวอย่างชีวิตจริง)


1
ไม่มันไม่เหมือนกัน ใน C ถ้าx == 1และy == 2จากนั้นx || yประเมินเป็น 1 และx | yประเมินเป็น 0 และฉันไม่เห็นว่าทำไมจึงx^trueเหนือกว่า!xในทุก ๆ ทาง มันพิมพ์ได้มากกว่าสำนวนน้อยกว่าและหากxไม่เป็นboolก็ไม่น่าเชื่อถือ
David Thornley

โอ้รอ .. ใช่แล้วมันเป็นใบ้ในส่วนของฉัน .. ฉันไม่สามารถคิดได้ในวันนี้
Earlz

x | y ประเมินเป็น 3 (แก้ไข: nvm ฉันเห็นว่าคุณกำลังพูดถึงสิ่งที่แก้ไขแล้ว!)
พ็อด

1
@DavidThornley: กรณีหนึ่งที่x^trueเหนือกว่า!xคือsome->complicated().member->lookup ^= true; ไม่มีโอเปอเรเตอร์เวอร์ชัน unary-assignment ของผู้ประกอบการเอก
Ben Voigt

1

ฉันไม่คิดว่าสิ่งนี้นับว่าเป็น bitwise แต่ Array ของ ruby ​​ได้กำหนดการปฏิบัติการผ่านตัวดำเนินการ bitwise จำนวนเต็มปกติ [1,2,4] & [1,2,3] # => [1,2]ดังนั้น ในทำนองเดียวกันสำหรับและa ^ b #=> set differencea | b #=> union


1

การแก้ปัญหาเชิงเส้นของ Tower Of Hanoi ใช้การดำเนินงานระดับบิตเพื่อแก้ปัญหา

public static void linear(char start, char temp, char end, int discs)
{
    int from,to;
    for (int i = 1; i < (1 << discs); i++) {
        from = (i & i-1) % 3;
        to = ((i | i-1) + 1) % 3;
        System.out.println(from+" => "+to);
    }
}

คำอธิบายสำหรับการแก้ปัญหานี้อยู่ที่นี่

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