Çok ilginç bir soru ve zekice.
Tek bir baytın manipüle edilmesinin basit bir örneğine bakalım. Basitlik için imzasız 8 bit kullanma. Numaranızın olduğunu xxaxxbxx
ve istediğinizi düşünün ab000000
.
Çözüm iki adımdan oluşuyordu: biraz maskeleme, ardından çarpma. Bit maskesi, ilginç bitleri sıfırlara dönüştüren basit bir AND işlemidir. Yukarıdaki durumda, maskeniz 00100100
ve sonuç olacaktır 00a00b00
.
Şimdi zor kısmı: bunu dönüştürmek ab......
.
Çarpma, bir grup kaydırma ve ekleme işlemidir. Anahtar, taşmanın, ihtiyacımız olmayan bitleri "kaydırması" na izin vermek ve istediklerimizi doğru yere koymaktır.
4 ( 00000100
) ile çarpma, 2 ile kalan her şeyi değiştirir ve sizi alır a00b0000
. Almak için b
yukarı taşımak için biz + 4 (b yukarı taşımak için) (doğru yerde a tutmak için) 1 ile çarpmak gerekir. Bu toplam 5'tir ve önceki 4'le birleştiğinde sihirli bir sayı olan 20 veya alırız 00010100
. Orijinal 00a00b00
maskelemeden sonraydı; çarpma şunu verir:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
Bu yaklaşımdan daha büyük sayılara ve daha fazla bite genişletebilirsiniz.
Sorduğunuz sorulardan biri "bu, herhangi bir sayıda bitle yapılabilir mi?" Birkaç maskeleme işlemine veya çarpma işlemine izin vermedikçe, cevabın "hayır" olduğunu düşünüyorum. Sorun "çarpışmalar" meselesidir - örneğin, yukarıdaki problemdeki "başıboş b". Bunu benzer bir sayıya yapmamız gerektiğini düşünün xaxxbxxcx
. Önceki yaklaşımın ardından {x 2, x {1 + 4 + 16}} = x 42'ye (oooh - her şeyin cevabına!) İhtiyacımız olduğunu düşünürdünüz. Sonuç:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
Gördüğünüz gibi, hala çalışıyor, ama "sadece". Burada kilit nokta, istediğimiz bitler arasında her şeyi sıkıştırabilmemiz için "yeterli boşluk" olmasıdır. C'den hemen sonra dördüncü bit d ekleyemedim, çünkü c + d'yi aldığım örnekler alırdım, bitler taşıyabilir, ...
Resmi bir kanıt olmadan, sorunuzun daha ilginç kısımlarını şu şekilde cevaplarım: "Hayır, bu herhangi bir sayıda bit için işe yaramayacak. N bitlerini çıkarmak için, istediğiniz bitler arasında (N-1) boşluklara ihtiyacınız var ayıklamak veya ek maske-çarpma adımları var. "
"Bitler arasında (N-1) sıfırlar olmalıdır" kuralı için düşünebildiğim tek istisna şudur: orijinalde birbirine bitişik iki bit ayıklamak istiyorsanız, VE aynı sipariş, o zaman hala yapabilirsiniz. Ve (N-1) kuralının amacı için iki bit olarak sayılırlar.
Başka bir fikir daha var - aşağıdaki @Ternary'nin cevabından esinlenmiştir (oradaki yorumuma bakın). Her ilginç bit için, oraya gitmesi gereken bitler için alana ihtiyacınız olduğu için sağında sadece çok sayıda sıfır gerekir. Ama aynı zamanda, solda sonuç bitlerine sahip olduğu için solda çok sayıda bite ihtiyaç duyar. Eğer bir bit b n'nin m pozisyonunda biterse, solunda m-1 sıfır ve sağında nm sıfır olması gerekir. Özellikle bitler, yeniden sipariş verdikten sonraki orijinal sayı ile aynı sırada olmadığında, bu orijinal kriterlerde önemli bir gelişmedir. Bu, örneğin, 16 bitlik bir kelimenin
a...e.b...d..c..
İçine kaydırılabilir
abcde...........
e ve b arasında sadece bir, d ile c arasında iki, diğerlerinde üç boşluk olmasına rağmen. N-1'e ne oldu ?? Bu durumda, a...e
"bir blok" haline gelir - doğru yerde sonuçlandırmak için 1 ile çarpılırlar ve böylece "biz ücretsiz e aldık". Aynı durum b ve d için de geçerlidir (b sağda üç boşluğa, d solunda aynı üçe ihtiyaç duyar). Yani sihirli sayıyı hesapladığımızda, kopyalar olduğunu görüyoruz:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
Açıkçası, bu sayıları farklı bir sırayla istiyorsanız, daha fazla boşluk bırakmanız gerekir. (N-1)
Kuralı yeniden formüle edebiliriz : "Her zaman bitler arasında en az (N-1) boşluk varsa veya nihai sonuçtaki bitlerin sırası biliniyorsa, m bitinde m biti biterse her zaman işe yarayacaktır. n, solunda m-1 sıfır ve sağında nm sıfır olması gerekir. "
@Ternary, bu kuralın işe yaramadığına dikkat çekti, çünkü "sadece hedef alanın sağına" ekleyen bitlerden bir taşıma olabilir - yani, aradığımız bitlerin hepsi bu olduğunda. Yukarıda verdiğim örneğe 16 bitlik bir kelimeyle sıkıca paketlenmiş beş bitle devam ettim:
a...e.b...d..c..
Basitlik için, bit konumlarını adlandıracağım ABCDEFGHIJKLMNOP
Yapacağımız matematik
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
Şimdiye kadar, aşağıda abcde
(pozisyonlar ABCDE
) hiçbir şeyin önemli olmayacağını düşündük , ama aslında, @Ternary'nin işaret ettiği gibi, eğer b=1, c=1, d=1
o zaman (b+c)
pozisyon G
biraz pozisyona taşınacaksa F
, yani (d+1)
pozisyon F
biraz içine taşınacak E
- ve bizim sonuç şımarık. En az anlamlı ilgi bitinin sağındaki alanın ( c
bu örnekte) önemli olmadığına dikkat edin, çünkü çarpma beyondan sıfırlarla en az önemli bitin dolmasına neden olacaktır.
Bu yüzden (m-1) / (nm) kuralımızı değiştirmemiz gerekiyor. Eğer sağda "tam olarak (nm) kullanılmayan bitleri olan birden fazla bit varsa (desendeki son biti saymazsak - yukarıdaki örnekte" c "), o zaman kuralı güçlendirmeliyiz - ve tekrar tekrar yapın!
Biz (nm) kriterini karşılayan bit numarasından sadece bakmak zorunda değil, aynı zamanda (nm + 1), vb edelim çağrısı (tam sayıları Q0 altındadır olanlar n-m
bir sonraki bit), Q1 ( n-m + 1), Q (N-1) (n-1) 'e kadar. Sonra biz taşıma riski varsa
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
Buna bakarsanız, basit bir matematiksel ifade yazarsanız,
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
ve sonuç W > 2 * N
, o zaman RHS ölçütünü bir kat artırmanız gerekir (n-m+1)
. Bu noktada operasyon W < 4
; bu işe yaramazsa kriteri bir kez daha artırın vb.
Yukarıdakileri takip etmenin cevabınıza uzun bir yol alacağını düşünüyorum ...