คำถามที่น่าสนใจมากและเคล็ดลับที่ชาญฉลาด
ลองดูตัวอย่างง่ายๆในการจัดการไบต์เดียว การใช้ 8 บิตที่ไม่ได้ลงนามเพื่อความเรียบง่าย ลองจินตนาการถึงหมายเลขของคุณและคุณต้องการxxaxxbxx
ab000000
การแก้ปัญหาประกอบด้วยสองขั้นตอน: การปิดบังเล็กน้อยตามด้วยการคูณ bit mask เป็นการทำงานแบบ AND อย่างง่ายที่เปลี่ยนบิตที่ไม่สนใจเป็นศูนย์ ในกรณีดังกล่าวข้างต้นหน้ากากของคุณจะเป็นและผลที่ได้00100100
00a00b00
ab......
ตอนนี้ส่วนที่ยากกลายเป็นว่า
การคูณคือการดำเนินการ shift-and-add กุญแจสำคัญคือการอนุญาตให้มีการไหลล้นเพื่อ "เลื่อนออกไป" บิตที่เราไม่ต้องการและใส่สิ่งที่เราต้องการในสถานที่ที่เหมาะสม
คูณ 4 ( 00000100
) จะเปลี่ยนทุกอย่างด้านซ้ายโดยที่ 2 a00b0000
และได้รับคุณไป ในการที่b
จะเลื่อนขึ้นเราจำเป็นต้องคูณด้วย 1 (เพื่อให้ a อยู่ในตำแหน่งที่ถูกต้อง) + 4 (เพื่อเลื่อน b ขึ้น) จำนวนนี้คือ 5 และรวมกับก่อนหน้านี้ 4 เราได้รับจำนวนมายากล 20 00010100
หรือ ต้นฉบับคือ00a00b00
หลังจากกำบัง; การคูณให้:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
จากวิธีการนี้คุณสามารถขยายจำนวนมากขึ้นและบิตเพิ่มเติม
หนึ่งในคำถามที่คุณถามคือ "สามารถทำได้ด้วยบิตจำนวนเท่าใด?" ฉันคิดว่าคำตอบคือ "ไม่" ยกเว้นว่าคุณอนุญาตการดำเนินการปิดบังหลายรายการหรือหลายทวีคูณ ปัญหาคือปัญหาของ "การชน" - ตัวอย่างเช่น "หลงทางข" ในปัญหาข้างต้น xaxxbxxcx
ลองนึกภาพเราจำเป็นต้องทำเช่นนี้ไปยังหมายเลขเหมือน ทำตามวิธีก่อนหน้านี้คุณจะคิดว่าเราต้องการ {x 2, x {1 + 4 + 16}} = x 42 (oooh - คำตอบทุกอย่าง!) ผลลัพธ์:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
อย่างที่คุณเห็นมันยังใช้งานได้ แต่ "เพียงแค่" พวกเขาสำคัญที่นี่คือมี "ช่องว่างเพียงพอ" ระหว่างบิตที่เราต้องการให้เราสามารถบีบทุกอย่างขึ้น ฉันไม่สามารถเพิ่มบิตที่สี่ d หลังจาก c เพราะฉันจะได้รับอินสแตนซ์ที่ฉันได้รับ c + d บิตอาจมีบิต ...
ดังนั้นถ้าไม่มีการพิสูจน์อย่างเป็นทางการฉันจะตอบคำถามที่น่าสนใจของคุณดังนี้: "ไม่นี่จะใช้ไม่ได้กับจำนวนบิตใด ๆ หากต้องการแยกบิต N บิตคุณต้องใช้ช่องว่าง (N-1) ระหว่างบิตที่คุณต้องการ ดึงข้อมูลหรือมีขั้นตอนเพิ่มมาสก์ทวีคูณ "
ข้อยกเว้นเดียวที่ฉันนึกได้สำหรับกฎ "ต้องมี (N-1) ระหว่างบิต" คือ: ถ้าคุณต้องการแยกสองบิตที่อยู่ติดกันในต้นฉบับและคุณต้องการเก็บไว้ใน คำสั่งเดียวกันจากนั้นคุณยังสามารถทำมันได้ และสำหรับจุดประสงค์ของกฎ (N-1) พวกเขานับเป็นสองบิต
มีข้อมูลเชิงลึกอื่น ๆ - ได้แรงบันดาลใจจากคำตอบของ @Ternary ด้านล่าง (ดูความคิดเห็นของฉันที่นั่น) สำหรับแต่ละบิตที่น่าสนใจคุณจะต้องมีศูนย์จำนวนมากทางด้านขวาของมันตามที่คุณต้องการพื้นที่สำหรับบิตที่ต้องไปที่นั่น แต่ยังต้องการบิตทางซ้ายมากเนื่องจากมีบิตผลลัพธ์ไปทางซ้าย ดังนั้นหากบิต b สิ้นสุดในตำแหน่ง m ของ n ดังนั้นมันต้องมีศูนย์ m-1 ทางด้านซ้ายและศูนย์ nm ทางด้านขวา โดยเฉพาะอย่างยิ่งเมื่อบิตไม่ได้อยู่ในลำดับเดียวกันในหมายเลขเดิมเหมือนเดิมหลังจากเรียงลำดับใหม่นี่เป็นการปรับปรุงที่สำคัญสำหรับเกณฑ์ดั้งเดิม ซึ่งหมายความว่าตัวอย่างเช่นนั่นคือคำ 16 บิต
a...e.b...d..c..
สามารถเลื่อนเป็น
abcde...........
แม้ว่าจะมีช่องว่างเดียวระหว่าง e และ b สองช่องว่างระหว่าง d และ c สามช่องว่างระหว่างพื้นที่อื่น เกิดอะไรขึ้นกับ N-1 ?? ในกรณีนี้a...e
จะกลายเป็น "หนึ่งบล็อก" - พวกเขาจะถูกคูณด้วย 1 เพื่อสิ้นสุดในสถานที่ที่เหมาะสมและดังนั้น "เราได้รับ e ฟรี" สิ่งนี้เป็นจริงสำหรับ b และ d (b ต้องการช่องว่างสามช่องทางด้านขวาและ d ต้องการสามช่องทางด้านซ้ายเหมือนกัน) ดังนั้นเมื่อเราคำนวณจำนวนเวทย์มนตร์เราจะพบว่ามีการซ้ำซ้อน:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
เห็นได้ชัดว่าถ้าคุณต้องการตัวเลขเหล่านี้ในลำดับที่แตกต่างกันคุณจะต้องเว้นวรรคพวกเขาต่อไป เราสามารถจัด(N-1)
ระเบียบกฎใหม่: "มันจะทำงานเสมอหากมีช่องว่างอย่างน้อย (N-1) ระหว่างบิตหรือถ้ารู้ลำดับของบิตในผลลัพธ์สุดท้ายแล้วถ้าบิต b สิ้นสุดในตำแหน่ง m ของ n, มันต้องมีศูนย์ m-1 ทางซ้าย, และศูนย์ nm อยู่ทางขวา "
@ เทอร์นารีชี้ให้เห็นว่ากฎนี้ใช้งานไม่ได้เนื่องจากอาจมีการเพิ่มบิตจาก "ทางด้านขวาของพื้นที่เป้าหมาย" - กล่าวคือเมื่อบิตที่เรากำลังค้นหาอยู่นั้นเป็นบิตทั้งหมด ดำเนินการต่อตัวอย่างที่ฉันให้ไว้ข้างต้นด้วยห้าบิตที่อัดแน่นในคำ 16 บิต: ถ้าเราเริ่มต้นด้วย
a...e.b...d..c..
เพื่อความง่ายฉันจะตั้งชื่อตำแหน่งบิต ABCDEFGHIJKLMNOP
คณิตศาสตร์ที่เรากำลังจะทำคือ
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
จนถึงขณะนี้เราคิดอะไรด้านล่างabcde
(ตำแหน่งABCDE
) จะไม่เป็นเรื่อง แต่ในความเป็นจริงเป็น @Ternary ชี้ให้เห็นว่าถ้าb=1, c=1, d=1
แล้ว(b+c)
อยู่ในตำแหน่งที่G
จะทำให้บิตที่จะดำเนินการไปยังตำแหน่งF
ซึ่งหมายความว่า(d+1)
อยู่ในตำแหน่งที่F
จะดำเนินการบิตเข้าE
- และของเรา ผลที่ได้คือเสีย โปรดทราบว่าพื้นที่ทางด้านขวาของบิตที่มีความสำคัญน้อยที่สุด ( c
ในตัวอย่างนี้) ไม่สำคัญเนื่องจากการคูณจะทำให้เกิดช่องว่างภายในด้วยศูนย์จาก beyone บิตที่สำคัญน้อยที่สุด
ดังนั้นเราจำเป็นต้องแก้ไขกฎ (m-1) / (nm) ของเรา หากมีมากกว่าหนึ่งบิตที่มี "แน่นอน (nm) บิตที่ไม่ได้ใช้ไปทางขวา (ไม่นับบิตสุดท้ายในรูปแบบ -" c "ในตัวอย่างด้านบน) จากนั้นเราต้องเสริมความแข็งแกร่งของกฎ - และเราต้อง ทำซ้ำ!
เราต้องดูไม่เพียง แต่จำนวนบิตที่เป็นไปตามเกณฑ์ (nm) เท่านั้น แต่ต้องดูที่ (n-m + 1) และอื่น ๆ ด้วยเราจะเรียกหมายเลข Q0 (ตรงn-m
กับบิตถัดไป), Q1 ( n-m + 1), สูงสุด Q (N-1) (n-1) ถ้าอย่างนั้นเราก็เสี่ยงที่จะพกพา
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
ถ้าคุณดูตรงนี้คุณจะเห็นว่าถ้าคุณเขียนนิพจน์ทางคณิตศาสตร์อย่างง่าย
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
และผลที่ได้คือW > 2 * N
แล้วคุณต้องเพิ่มเกณฑ์ RHS (n-m+1)
โดยหนึ่งบิต ณ จุดนี้การดำเนินการมีความปลอดภัยตราบใดที่W < 4
; หากวิธีนี้ใช้ไม่ได้ผลให้เพิ่มเกณฑ์อีกครั้งหนึ่งเป็นต้น
ฉันคิดว่าการทำตามข้างต้นจะทำให้คุณได้คำตอบที่ตรงไกลยิ่งขึ้น ...