Pertanyaan yang sangat menarik, dan trik cerdik.
Mari kita lihat contoh sederhana untuk memanipulasi byte tunggal. Menggunakan unsigned 8 bit untuk kesederhanaan. Bayangkan nomor Andaxxaxxbxx
Anda dan yang Anda inginkan ab000000
.
Solusinya terdiri dari dua langkah: sedikit masking, diikuti oleh perkalian. Topeng bit adalah operasi DAN sederhana yang mengubah bit tidak menarik menjadi nol. Dalam kasus di atas, topeng Anda akan menjadi00100100
dan hasilnya 00a00b00
.
Sekarang bagian yang sulit: mengubahnya menjadi ab......
.
Perkalian adalah sekelompok operasi shift-and-add. Kuncinya adalah membiarkan overflow untuk "mengalihkan" bit yang tidak kita butuhkan dan meletakkan bit yang kita inginkan di tempat yang tepat.
Perkalian dengan 4 ( 00000100
) akan menggeser semua yang tersisa 2 dan membuat Anda melakukannya a00b0000
. Untuk mendapatkan b
naik, kita perlu mengalikan dengan 1 (untuk menjaga a di tempat yang tepat) + 4 (untuk memindahkan b ke atas). Jumlah ini adalah 5, dan dikombinasikan dengan 4 sebelumnya kita mendapatkan angka ajaib 20, atau 00010100
. Yang asli 00a00b00
setelah topeng; perkalian memberikan:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
Dari pendekatan ini Anda dapat memperluas ke jumlah yang lebih besar dan lebih banyak bit.
Salah satu pertanyaan yang Anda ajukan adalah "dapatkah ini dilakukan dengan sejumlah bit?" Saya pikir jawabannya adalah "tidak", kecuali jika Anda mengizinkan beberapa operasi masking, atau beberapa perkalian. Masalahnya adalah masalah "tabrakan" - misalnya, "nyasar b" dalam masalah di atas. Bayangkan kita perlu melakukan ini ke nomor seperti xaxxbxxcx
. Mengikuti pendekatan sebelumnya, Anda akan berpikir kita perlu {x 2, x {1 + 4 + 16}} = x 42 (oooh - jawaban untuk semuanya!). Hasil:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
Seperti yang Anda lihat, itu masih berfungsi, tetapi "hanya". Kuncinya di sini adalah bahwa ada "ruang yang cukup" antara bit yang kita inginkan sehingga kita bisa menekan semuanya. Saya tidak bisa menambahkan bit keempat d tepat setelah c, karena saya akan mendapatkan contoh di mana saya mendapatkan c + d, bit mungkin membawa ...
Jadi tanpa bukti formal, saya akan menjawab bagian yang lebih menarik dari pertanyaan Anda sebagai berikut: "Tidak, ini tidak akan bekerja untuk sejumlah bit. Untuk mengekstrak N bit, Anda perlu (N-1) spasi antara bit yang ingin Anda mengekstrak, atau memiliki langkah-langkah mask-multiply tambahan. "
Satu-satunya pengecualian yang dapat saya pikirkan untuk aturan "harus memiliki (N-1) nol di antara bit" adalah ini: jika Anda ingin mengekstrak dua bit yang berdekatan satu sama lain di aslinya, DAN Anda ingin menyimpannya di urutan yang sama, maka Anda masih bisa melakukannya. Dan untuk tujuan aturan (N-1) mereka menghitung sebagai dua bit.
Ada wawasan lain - terinspirasi oleh jawaban @Ternary di bawah ini (lihat komentar saya di sana). Untuk setiap bit yang menarik, Anda hanya perlu sebanyak nol di sebelah kanan karena Anda membutuhkan ruang untuk bit yang perlu pergi ke sana. Tetapi juga, dibutuhkan sebanyak bit ke kiri karena memiliki bit hasil ke kiri. Jadi, jika sedikit b berakhir di posisi m dari n, maka perlu memiliki m-1 nol di sebelah kirinya, dan nm nol di sebelah kanan. Terutama ketika bit tidak dalam urutan yang sama dengan nomor aslinya seperti yang akan setelah pemesanan ulang, ini merupakan peningkatan penting untuk kriteria asli. Ini berarti, misalnya, kata yang 16 bit
a...e.b...d..c..
Dapat digeser menjadi
abcde...........
meskipun hanya ada satu ruang antara e dan b, dua antara d dan c, tiga antara yang lain. Apa yang terjadi dengan N-1 ?? Dalam hal ini, a...e
menjadi "satu blok" - mereka dikalikan dengan 1 untuk berakhir di tempat yang tepat, jadi "kami mendapat e gratis". Hal yang sama berlaku untuk b dan d (b membutuhkan tiga ruang ke kanan, d membutuhkan tiga yang sama ke kiri). Jadi ketika kami menghitung angka ajaib, kami menemukan ada duplikat:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
Jelas, jika Anda menginginkan angka-angka ini dalam urutan yang berbeda, Anda harus menempatkannya lebih jauh. Kita dapat merumuskan kembali (N-1)
aturan: "Itu akan selalu bekerja jika ada setidaknya (N-1) ruang antara bit; atau, jika urutan bit dalam hasil akhir diketahui, maka jika bit b berakhir di posisi m dari n, harus memiliki m-1 nol di sebelah kiri, dan nm nol di sebelah kanan. "
@Ternary menunjukkan bahwa aturan ini tidak berfungsi, karena mungkin ada carry dari bit yang menambahkan "tepat di sebelah kanan area target" - yaitu, ketika bit yang kita cari adalah semuanya. Melanjutkan contoh yang saya berikan di atas dengan lima bit yang dikemas dalam kata 16 bit: jika kita mulai dengan
a...e.b...d..c..
Untuk kesederhanaan, saya akan menyebutkan posisi bit ABCDEFGHIJKLMNOP
Matematika yang akan kami lakukan adalah
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
Sampai sekarang, kami pikir apa pun di bawah ini abcde
(posisi ABCDE
) tidak masalah, tetapi pada kenyataannya, seperti yang ditunjukkan @Ternary, jika b=1, c=1, d=1
kemudian (b+c)
dalam posisi G
akan menyebabkan sedikit untuk dibawa ke posisi F
, yang berarti bahwa (d+1)
dalam posisi F
akan membawa sedikit ke dalam E
- dan kami hasilnya rusak. Perhatikan bahwa ruang di sebelah kanan sedikit kepentingan paling signifikan (c
dalam contoh ini) tidak masalah, karena penggandaan akan menyebabkan padding dengan nol dari sebelumnya bit paling tidak signifikan.
Jadi kita perlu memodifikasi aturan (m-1) / (nm) kita. Jika ada lebih dari satu bit yang memiliki "persis (nm) bit yang tidak digunakan ke kanan (tidak termasuk bit terakhir dalam pola -" c "pada contoh di atas), maka kita perlu memperkuat aturan - dan kita harus lakukan secara iteratif!
Kita harus melihat tidak hanya pada jumlah bit yang memenuhi kriteria (nm), tetapi juga yang ada pada (n-m + 1), dll. Mari kita sebut nomor mereka Q0 (tepat n-m
untuk bit berikutnya), Q1 ( n-m + 1), hingga Q (N-1) (n-1). Maka kita berisiko membawa jika
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
Jika Anda melihat ini, Anda dapat melihat bahwa jika Anda menulis ekspresi matematika sederhana
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
dan hasilnya adalah W > 2 * N
, maka Anda perlu meningkatkan kriteria RHS sedikit demi sedikit (n-m+1)
. Pada titik ini, operasi aman selama W < 4
; jika itu tidak berhasil, tambah satu kriteria lagi, dll.
Saya pikir mengikuti hal di atas akan membuat Anda jauh ke jawaban Anda ...