“สวัสดี อามีโก้!”
"ฉันยังต้องการพูดคุยเกี่ยวกับบิตมาสก์และ XOR"
"คุณรู้อยู่แล้วว่าตัวเลขประกอบด้วยบิต และคุณสามารถดำเนินการต่างๆ กับบิตเหล่านี้ได้ บิตมาสก์เป็นตัวแทนของค่าตรรกะที่แตกต่างกันหลายค่า (ค่าจริง/เท็จ) เป็นจำนวนเต็มเดียว ในกรณีนี้ ค่าบูลีนแต่ละค่าจะสอดคล้องกับ บิตเฉพาะ นี่คือวิธีที่จะทำ:"
"การแทนเลขฐานสองของเลขฐานสอง (1, 2, 4, 8, 16, 32, ...) เกี่ยวข้องกับการตั้งค่าหนึ่งบิตเท่านั้น:"
ตัวเลข | การเป็นตัวแทนไบนารี |
---|---|
1 | 0000 0001 |
2 | 0000 0010 |
4 | 0000 0100 |
8 | 0000 1000 |
16 | 0001 0000 |
19 (ไม่ใช่ยกกำลังสอง) | 0001 0011 |
31 (ไม่ใช่ยกกำลังสอง) | 0001 1111 |
"ดังนั้น จำนวนเต็มใดๆ สามารถถือเป็นอาร์เรย์ของบิตหรืออาร์เรย์ของค่าบูลีน"
"นี่คือวิธีที่คุณสามารถเก็บค่าบูลีนต่างๆ ไว้ในตัวเลขเดียว:"
boolean a = true;
boolean b = false;
boolean c = true;
boolean d = false;
int result = 0;
if (a) result += 1; // 1 == 20 — bit 0
if (b) result += 2; // 2 == 21 — bit 1
if (c) result += 4; // 4 == 22 — bit 2
if (d) result += 8; // 8 == 23 — bit 3
"ตอนนี้แต่ละบิตคือ 1 ถ้าตัวแปรบูลีนที่ตรงกันเป็นจริง"
ในกรณีของเรา ตัวแปร a และ c เป็นจริง ผลลัพธ์จึงเท่ากับ 1+4 == 5
0000 0101
0000 dcba
"ฉันคิดว่าฉันรู้ว่าเกิดอะไรขึ้น"
“ถ้าเข้าใจแล้ว ไปกันเถอะ”
"int มี 32 บิต หนึ่งในนั้นใช้สำหรับเครื่องหมายของตัวเลข และอีก 31 บิตสามารถใช้เก็บค่าของตัวแปรบูลีน 31 ตัว"
"Long มี 64 บิต ซึ่งเราสามารถจัดเก็บตัวแปรบูลีนได้ 63 ตัว"
"ใช่."
"ตัวแปรนับสิบอัดแน่นอยู่ในตัวเลขเดียว นั่นก็ไม่กี่ตัว"
"แต่สิ่งนี้นำไปใช้ที่ไหน"
"โดยหลักแล้วในสถานการณ์ที่คุณต้องการจัดเก็บข้อมูลจำนวนมากเกี่ยวกับวัตถุ เมื่อคุณจัดเก็บข้อมูลจำนวนมากเกี่ยวกับวัตถุหนึ่งๆ จะมีตัวแปรบูลีนสองสามตัวอยู่เสมอ "ด้วยวิธีนี้ พวกมันทั้งหมดจะถูกจัดเก็บไว้ในหมายเลขเดียวได้อย่างสะดวก "
"เน้นคำว่าเก็บไว้ เพราะจริงๆ แล้วการใช้เบอร์ไม่ค่อยสะดวกเท่าไหร่"
"อ้อ นั่นแหละคือสิ่งที่ฉันอยากถาม เราจะแยกค่าบูลีนออกจากตัวเลขได้อย่างไร"
"มันไม่ซับซ้อนเลย สมมติว่าคุณต้องกำหนดว่าบิต 6 ถูกตั้งค่าเป็น 1 หรือไม่ (2 ยกกำลัง 5 คือ 32) เราสามารถตรวจสอบได้ดังนี้:"
int a = 32; // 25 == 0010 0000
int b = 8; // 23 == 0000 1000
int c = 2; // 21 == 0000 0010
int result = a + b + c; // 32 + 8 + 2 == 42 == 0010 1010
int a = result & 32; // 0010 1010 & 0010 0000 = 0010 0000
int b = result & 8; // 0010 1010 & 0000 1000 = 0000 1000
int c = result & 2; // 0010 1010 & 0000 0010 = 0000 0010
"ดังนั้น การทำงานกับบิตมาสก์จึงเกี่ยวข้องกับการดำเนินการสามอย่าง:"
1) ตั้งค่าบิตเฉพาะเป็น 0
2) ตั้งค่าบิตเฉพาะเป็น 1
3) ตรวจสอบค่าของบิตเฉพาะ
"ยกตัวอย่างบิต 6"
"คุณตั้งค่าบิต 6 เป็น 1 ได้อย่างไร"
รหัส | คำอธิบาย |
---|---|
|
คุณตั้งค่าบิต 6 เป็น 1 ได้อย่างไร |
|
คุณตั้งค่าบิต 6 เป็น 0 ได้อย่างไร |
|
คุณจะได้รับค่าของบิต 6 ได้อย่างไร |
"นั่นเป็นเรื่องที่ผิดปกติอย่างมาก แต่ไม่ใช่เรื่องยาก ตอนนี้ฉันเป็นโปรแกรมเมอร์ที่ร้อนแรง"
"และอีกหนึ่งเคล็ดลับเล็ก ๆ น้อย ๆ เกี่ยวกับวิธีรับตัวเลขอย่างง่ายดายด้วยบิตเฉพาะที่ตั้งค่าเป็น 0 หรือ 1: 01000000 หรือ 10111111"
สำหรับสิ่งนี้ เรามี ตัวดำเนินการ>> และ <<
"1 คือ 2 ยกกำลังศูนย์ กล่าวคือ ตัวเลขที่มีบิต 0 ตั้งค่าเป็น 1 เราต้องการตัวเลขที่มีบิต 6 เซ็ต"
int c = 1 << 6; // 0000 0001 << 6 == 0100 0000 == 64
"เยี่ยมมาก! มีประโยชน์มากสำหรับกรณีเช่นนี้"
"แต่ถ้าฉันต้องการตัวเลขที่ทุกบิตตั้งค่าเป็น 1 ยกเว้นบิตหนึ่งที่กำหนดเป็น 0"
"นั่นก็ไม่ใช่เรื่องยากเช่นกัน:"
int d = ~(1 << 6); // ~0100 0000 == 10111111
"อีกนัยหนึ่ง ทุกอย่างง่ายมาก:"
รหัส | คำอธิบาย |
---|---|
|
คุณตั้งค่าบิต 6 เป็น 1 ได้อย่างไร |
|
คุณตั้งค่าบิต 6 เป็น 0 ได้อย่างไร |
|
คุณจะได้รับค่าของบิต 6 ได้อย่างไร |
“มันดูไม่ยากนัก แต่ฉันจะไม่จำมันในทันที”
"แต่ถ้าคุณพบนิพจน์ที่น่ากลัว เช่น "result &= ~(1 << 6)" ในโค้ดของคนอื่น คุณจะรู้ว่าคนนี้กำลังทำงานกับ bitmask"
"และถ้าคุณเจอมันบ่อยๆ มันจะจำมันได้เอง"
"จำไว้... ฟังดูดี ขอบคุณสำหรับบทเรียน"