Aşağıdaki bitsel operatörlerin bazı gerçek dünya kullanım durumları nelerdir?
- VE
- XOR
- DEĞİL
- VEYA
- Sol / Sağ kaydırma
Aşağıdaki bitsel operatörlerin bazı gerçek dünya kullanım durumları nelerdir?
Yanıtlar:
Bit alanları (bayraklar) Durumu
birkaç "evet veya hayır" özelliği ile tanımlanan bir şeyi temsil etmenin en etkili yoludur. EKL iyi bir örnektir; diyelim ki 4 ayrı izin (okuma, yazma, yürütme, değişiklik politikası), atık 4 yerine 1 baytta saklamak daha iyidir. Daha fazla rahatlık için bunlar birçok dilde numaralandırma türleriyle eşleştirilebilir.
Bağlantı noktaları / soketler üzerinden iletişim
Her zaman sağlama sayıları, eşlik, durdurma bitleri, akış kontrol algoritmaları vb. bir zaman.
Sıkıştırma, Şifreleme
Bunların her ikisi de büyük ölçüde bitsel algoritmalara bağlıdır. Bak Sıkıştırılmalı bir örnek için algoritma - her şey bitler halinde, bayt değil.
Sonlu Durum Makinaları
Yazılımda da bulunabilmelerine rağmen, öncelikle bir parça donanıma gömülü türden bahsediyorum. Bunlar doğada kombinatoryal - onlar tam anlamıyla mantık kapıları bir grup aşağı "derlenmiş" alıyor olabilirler, onlar gibi ifade edilebilir zorunda AND
, OR
, NOT
vb
Grafikler
Burada, bu operatörlerin grafik programlamada kullanıldığı her alana girmek için yeterli alan yoktur. XOR
(veya ^
) burada özellikle ilginçtir, çünkü aynı girdiyi ikinci kez uygulamak birinciyi geri alır. Eski GUI'ler, maliyetli yeniden çizimlere olan ihtiyacı ortadan kaldırmak için seçim vurgulama ve diğer kaplamalar için buna güveniyordu. Yavaş grafik protokollerinde (yani uzak masaüstü) hala yararlıdırlar.
Bunlar benim ilk ortaya koyduğum birkaç örnekti - bu pek kapsamlı bir liste değil.
Tuhaf mı?
(value & 0x1) > 0
İki (çift) ile bölünebilir mi?
(value & 0x1) == 0
Bir CMS için bir güvenlik modeli uygulamada bitsel işlemler kullandım. Kullanıcıların uygun gruplarda olmaları halinde erişebilecekleri sayfalar vardı. Bir kullanıcı birden çok grupta olabilir, bu nedenle kullanıcı grupları ile sayfa grupları arasında bir kavşak olup olmadığını kontrol etmemiz gerekiyordu. Bu nedenle, her gruba benzersiz bir 2 güç gücü tanımlayıcısı atadık, örneğin:
Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100
Bu değerleri OR VEYA birlikte tutarız ve değeri sayfa ile (tek int olarak) depolarız. Bir sayfaya A ve B grupları tarafından erişilebiliyorsa, 3 değerini (ikili dosyada 00000011 olan) sayfalara erişim kontrolü olarak saklarız. Aynı şekilde, hangi gruplarda olduklarını göstermek için bir kullanıcıyla ORed grup tanımlayıcılarının bir değerini saklarız.
Bu nedenle, belirli bir kullanıcının belirli bir sayfaya erişip erişemediğini kontrol etmek için, değerleri birlikte AND yapmanız ve değerin sıfır olmadığından emin olmanız yeterlidir. Bu kontrol, tek bir komutla, döngü yok, veritabanı gidiş-dönüşleri olmadan uygulandığı için çok hızlıdır.
Bireysel bitler olarak saklanan bayraklarla ilgili bazı yaygın deyimler.
enum CDRIndicators {
Local = 1 << 0,
External = 1 << 1,
CallerIDMissing = 1 << 2,
Chargeable = 1 << 3
};
unsigned int flags = 0;
Ücretli bayrağını ayarlayın:
flags |= Chargeable;
CallerIDMissing bayrağını temizle:
flags &= ~CallerIDMissing;
CallerIDMissing ve Chargeable'ın ayarlanıp ayarlanmadığını test edin:
if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {
}
Düşük seviyeli programlama buna iyi bir örnektir. Örneğin, bir donanım parçasının istediğiniz şeyi yapmasını sağlamak için bellek eşlemeli bir kayıt defterine belirli bir bit yazmanız gerekebilir:
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
Ayrıca htonl()
ve ve operatörleri htons()
kullanılarak uygulanır ( endianitesi (Bayt sırası) ağ sırasıyla eşleşmeyen makinelerde ):&
|
#define htons(a) ((((a) & 0xff00) >> 8) | \
(((a) & 0x00ff) << 8))
#define htonl(a) ((((a) & 0xff000000) >> 24) | \
(((a) & 0x00ff0000) >> 8) | \
(((a) & 0x0000ff00) << 8) | \
(((a) & 0x000000ff) << 24))
htons()
ve htonl()
a short
veya a'yı long
ana bilgisayar ( h
) endianitesinden ağ ( n
) bayt sırasına değiştirmek için POSIX işlevleridir .
htonl()
32 bitlik bir int
değer için değil mi? long
birçok dilde 64 bit anlamına gelir.
Bunları örneğin paketlenmiş renk değerlerinden RGB (A) değerleri almak için kullanıyorum.
(a & b) >> c
5 kattan daha hızlı a % d / e
(ARGB'yi temsil eden bir int'ten tek bir renk değeri elde etmenin her iki yolu). Sırasıyla, 1 milyar yineleme için 6.7'ler ve 35.2'ler.
%
da Modül operatörü değil, Kalan operatörü olmasıdır. Pozitif değerler için eşdeğerdir, ancak negatif olanlarla farklılık gösterirler. Uygun kısıtlamaları sağlarsanız ( örneğin uint
yerine int
) geçerseniz , iki örnek aynı hızda olmalıdır.
Bir sürü boolean bayrakım olduğunda hepsini bir int'de saklamayı seviyorum.
Onları bitsel-AND kullanarak çıkarıyorum. Örneğin:
int flags;
if (flags & 0x10) {
// Turn this feature on.
}
if (flags & 0x08) {
// Turn a second feature on.
}
vb.
if (flags.feature_one_is_one) { // turn on feature }
. ANSI C standardında olduğundan taşınabilirlik sorun olmamalı.
& = VE:
Belirli bitleri maskeleyin.
Görüntülenmesi veya gösterilmemesi gereken belirli bitleri tanımlıyorsunuz. 0xFF ve x bir bayttaki tüm bitleri temizlerken, 0xFF x'i değiştirmez. 0x0F, alt uçtaki bitleri görüntüler.
Dönüştürme:
Bit kimliğine sahip daha kısa değişkenleri daha uzun değişkenlere dökmek için bitleri ayarlamak gerekir, çünkü int'deki -1 değeri 0xFFFFFFFF, uzunluğunda -1 ise 0xFFFFFFFFFFFFFFFF'dir. Kimliği korumak için dönüşümden sonra bir maske uygularsınız.
| = VEYA Bitleri
ayarla. Bitler, önceden ayarlanmışlarsa bağımsız olarak ayarlanır. Birçok veri yapısında (bit alanı) IS_HSET = 0, IS_VSET = 1 gibi bayraklar bulunur. Bayrakları ayarlamak için IS_HSET | IS_VSET (C ve montajda bu okumak çok uygundur)
^ = XOR
Aynı veya farklı bitleri bulun.
~ = DEĞİL
Uçları çevirin.
Tüm olası yerel bit işlemlerinin bu işlemler tarafından uygulanabileceği gösterilebilir . Eğer isterseniz sadece bir bit işlemi ile bir ADD talimatı uygulayabilirsiniz.
Bazı harika kesmek:
http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html
= ~
, değil |=
, VEYA.
& = AND
- Neden neden ben byte değiştirilmemiş bir sürümünü almak istiyorum isteyeyim, tüm bitleri temizlemek istiyorum, ve daha düşük kemirmek ilgisi neyim ki?
xor
kendisidir. Alt kırıntıyı çıkarmak isteyebileceğiniz birkaç nedeni düşünebilirim. Özellikle bu düşük kırıntı veri yapısının bir parçasıysa ve bunu maske olarak veya OR
başka bir yapı ile kullanmak istiyorsanız .
Şifreleme tüm bitsel işlemlerdir.
Verileri karma yapmak için hızlı ve kirli bir yol olarak kullanabilirsiniz.
int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;
Bu, bitmap görüntüsündeki renkleri bayt formatında okumak için bir örnektir
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.
Umarım bu küçük örnekler yardımcı olur ....
Günümüz modern dilinin soyutlanmış dünyasında, çok fazla değil. Dosya G / Ç, akla gelen kolay bir dosyadır, ancak bu zaten uygulanmış olan bir şey üzerinde bitsel işlemler uygular ve bitsel işlemler kullanan bir şey uygulamaz. Yine de, kolay bir örnek olarak, bu kod bir dosyadaki salt okunur özniteliğin kaldırılmasını gösterir (böylece c # 'da yeni bir FileStream belirterek FileMode.Create belirterek kullanılabilir):
//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);
}
Özel uygulamalara gelince, işte son bir örnek: Dağıtılmış uygulamamızın bir kurulumundan diğerine güvenli mesaj göndermek için bir "mesaj merkezi" oluşturdum. Temel olarak, Gelen Kutusu, Giden Kutusu, Gönderilmiş vb.Ile birlikte e-postaya benzer, ancak okundu bilgileriyle teslimat garantisi de vardır, bu nedenle "gelen kutusu" ve "gönderilen" öğelerinin ötesinde ek alt klasörler de vardır. Bunun ne anlama geldiği, "gelen kutusunda" veya "gönderilen klasörde" ne olduğunu genel olarak tanımlamam için bir gereklilikti. Gönderilen klasörde neyin okunduğunu ve neyin okunmadığını bilmem gerekiyor. Okunmamış olanlardan neyin alındığını ve nelerin alınmadığını bilmem gerekiyor. Bu bilgiyi, yerel bir veri kaynağını filtreleyen ve uygun bilgileri görüntüleyen dinamik bir nerede cümlesi oluşturmak için kullanıyorum.
Enum nasıl bir araya getirilir:
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
}
Bunun ne yaptığını görüyor musunuz? (&) "Inbox" numaralandırma değeri InboundMemos ile anding tarafından, InboundMemosForMyOrders gelen kutusunda olduğunu biliyorum.
Şu anda seçili olan klasör için bir görünüm tanımlayan filtreyi oluşturan ve döndüren yöntemin haşlanmış bir sürümü:
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;
}
Son derece basit, ancak tipik olarak bitsel işlemler gerektirmeyen bir soyutlama düzeyinde düzgün bir uygulama.
Base64 kodlaması buna bir örnektir. Base64 kodlaması, ikili verileri e-posta sistemleri (ve diğer amaçlar) üzerinden gönderilmek üzere yazdırılabilir bir karakter olarak göstermek için kullanılır. Base64 kodlaması, 8 bit baytlık bir diziyi 6 bit karakter arama dizinlerine dönüştürür. Bit işlemleri, kaydırma ve 'veya' değil ', Base64 kodlama ve kod çözme için gerekli bit işlemlerini uygulamak için çok yararlıdır.
Bu elbette sayısız örnekten sadece bir tanesidir.
Şaşırdım, kimse İnternet çağı için açık bir cevap seçmedi. Bir alt ağ için geçerli ağ adreslerini hesaplama.
Genellikle bitsel işlemler çarpma / bölme işleminden daha hızlıdır. Yani bir değişkeni x'i 9 ile çarpmanız gerekiyorsa, bunu x<<3 + x
birkaç döngüden daha hızlı yaparsınız x*9
. Bu kod bir ISR'nin içindeyse, yanıt süresinden tasarruf edersiniz.
Benzer şekilde, bir diziyi dairesel kuyruk olarak kullanmak istiyorsanız, biraz akıllıca işlemlerle kontrolleri sarmak daha hızlı (ve daha zarif) olacaktır. (dizi boyutunuz 2 güç olmalıdır). Örn:, eklemek / silmek istiyorsanız tail = ((tail & MASK) + 1)
yerine kullanabilirsiniz tail = ((tail +1) < size) ? tail+1 : 0
.
Ayrıca, bir hata işaretinin birden çok hata kodunu bir arada tutmasını istiyorsanız, her bit ayrı bir değer tutabilir. Her bir hata kodu ile VE olarak bir kontrol olarak yapabilirsiniz. Bu Unix hata kodlarında kullanılır.
Ayrıca bir n-bit bitmap gerçekten harika ve kompakt bir veri yapısı olabilir. Eğer n boyutunda bir kaynak havuzu tahsis etmek isterseniz, mevcut durumu temsil etmek için bir n-bit kullanabiliriz.
Hiç kimse sabit nokta matematikten bahsetmemiş gibi görünüyor.
(Evet, ben yaşlıyım, tamam mı?)
Sayı x
2'nin gücü mü? (Örneğin, bir sayacın artırıldığı algoritmalarda kullanışlıdır ve bir eylemin yalnızca logaritmik defa yapılması gerekir)
(x & (x - 1)) == 0
Tam sayının en yüksek biti x
hangisidir? (Bu, örneğin 2'den büyük minimum gücü bulmak için kullanılabilir 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
Tam sayının en düşük biti x
hangisidir? (2'ye bölünebilir sayısını bulmanıza yardımcı olur.)
x & -x
x & -x
.
Bitsel operatörler, uzunluğu 2 olan dizileri döngüye sokmak için kullanışlıdır. Bahsedildiği gibi, bitsel operatörler son derece kullanışlıdır ve Bayraklar , Grafikler , Ağ Oluşturma , Şifreleme'de kullanılır . Sadece bu da değil, aynı zamanda son derece hızlı. Benim kişisel favori kullanım için döngü bir dizi olmadan Koşullamalar . Sıfır dizin tabanlı bir diziniz olduğunu varsayalım (örneğin, ilk öğenin dizini 0) ve süresiz olarak döngü yapmanız gerektiğini varsayalım . Süresiz demek istediğim, ilk öğeden sonuncuya ve ilk öğeye geri dönmek demek. Bunu uygulamanın bir yolu:
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
if (i >= arr.length)
i = 0;
}
Eğer kaçınmak istiyorsanız bu en basit yaklaşımdır eğer açıklamada, kullanabilirsiniz modülü şöyle bir yaklaşım:
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
i = i % arr.length;
}
Bu iki yöntemin aşağı tarafı, modül operatörünün pahalı olmasıdır, çünkü tamsayı bölünmesinden sonra bir kalıntı arar. Ve ilk yöntem her yinelemede bir if ifadesi çalıştırır . Ancak bitsel operatör ile dizinizin uzunluğu 2 güç ise, (bitsel ve) operatörünü 0 .. length - 1
kullanarak kolayca bir dizi oluşturabilirsiniz . Bunu bilerek, yukarıdaki kod&
i & length
int[] arr = new int[8];
int i = 0;
while (true){
print(arr[i]);
i = i + 1;
i = i & (arr.length - 1);
}
İşte böyle çalışır. Olarak ikili biçimde 1 ile çıkarılır 2 gücü her sayı sadece olanlarla ifade edilir. Örneğin, ikili dosyada 3 11
, 7 111
, 15 1111
ve benzeri, fikri anlarsınız. Şimdi, &
sadece ikili olanlardan oluşan bir sayıya karşı herhangi bir sayı alırsanız ne olur ? Diyelim ki bunu yapıyoruz:
num & 7;
Eğer num
daha küçük veya 7'ye eşitse, sonuç 1 ile num
bit &
olan her bitin kendisinin olması olacaktır. Eğer num
7'den daha büyük, sırasında &
operasyon bilgisayarın tabii sonra sıfır olarak kalacak başta sıfırları 7 's ele alacağız &
sadece sondaki parçası olmaya devam edecektir operasyon. 9 & 7
İkili durumda olduğu gibi
1001 & 0111
sonuç, ondalık sayıda 1 olan ve dizideki ikinci öğeye yönelik olan 0001 olacaktır.
sql ilişkisel modelinde de kullanışlı olabilir, diyelim ki aşağıdaki tablolarınız var: BlogEntry, BlogCategory
traditonally, bir BlogEntryCategory tablosu kullanarak aralarında bir nn ilişkisi oluşturabilir veya BlogEntry'de bayraklı numaralarla yaptığınız gibi birden çok BlogCategory kaydına bağlanmak için bir değer kullanabileceğiniz BlogCategory kayıtları olmadığında, çoğu RDBMS'de de bu 'işaretli' sütunda seçim yapmak için çok hızlı bir operatör ...
Bir mikrodenetleyicinin Çıkışlarının bazı bitlerini değiştirmek istediğinizde, ancak yazılacak kayıt bir bayt olduğunda, bunun gibi bir şey yaparsınız (sözde kod):
char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs
Tabii ki, birçok mikrodenetleyici her biti ayrı ayrı değiştirmenize izin verir ...
Sayı modunuzu (%) belirli bir 2 gücü hesaplamak istiyorsanız yourNumber & 2^N-1
, bu durumda aynı olanı kullanabilirsiniz yourNumber % 2^N
.
number % 16 = number & 15;
number % 128 = number & 127;
Bu büyük olasılıkla sadece 2 ^ N çok büyük bir temettü ile modül operasyonu için bir alternatif olmak yararlıdır ... Ama o zaman bile bile modül 2.0 üzerinde hız artışı .NET 2.0 üzerinde benim test ihmal edilebilir. Modern derleyicilerin zaten böyle optimizasyonlar yaptığından şüpheleniyorum. Bunun hakkında daha fazla bilen biri var mı?
%
, Kalan işlemde olduğu gibi negatiflere farklı davranırlar. Ancak, eğer geçerseniz uint
için %
, C # derleyicisi aslında bitwise kullanarak makine kodu üretecek VE ikinci argüman ikisinin bir ön bilinen güç olduğunda.
Buradaki sorumda gerçek bir dünya kullanımı var -
Yalnızca ilk WM_KEYDOWN bildirimini mi yanıtladınız?
Windows'da bir WM_KEYDOWN mesajı tüketirken C api bit 30 önceki anahtar durumunu belirtir. Mesaj gönderilmeden önce tuş aşağıdaysa değer 1 veya tuş yukarıdaysa sıfır olur
Çoğunlukla bitsel operasyonlar için kullanılırlar (sürpriz). PHP kod tabanında bulunan birkaç gerçek dünya örneği.
Karakter kodlaması:
if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {
Veri yapıları:
ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
Veritabanı sürücüleri:
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
Derleyici uygulaması:
opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;
C programlamaya ilk başladığımda, doğruluk tablolarını ve bunların hepsini anladım, ancak bu makaleyi okuyana kadar aslında nasıl kullanılacağını tıklamadı http://www.gamedev.net/reference/articles/article1563.asp (gerçek hayattan örnekler verir)
x == 1
ve y == 2
sonra x || y
1 olarak x | y
değerlendirir ve 0 olarak değerlendirir. Ayrıca neden hiçbir şekilde x^true
üstündür !x
. Daha fazla yazım, daha az deyimsel ve eğer x
olmazsa bool
güvenilmez.
x^true
daha üstündür !x
olan some->complicated().member->lookup ^= true;
tekli operatörlerden hiçbir bileşik atama sürümü vardır.
Bunun bitsel olduğunu düşünmüyorum, ama Ruby'nin Array'ı normal tamsayı bitsel operatörleri aracılığıyla ayarlanmış işlemleri tanımlar. Yani [1,2,4] & [1,2,3] # => [1,2]
. Benzer şekilde a ^ b #=> set difference
ve için a | b #=> union
.
Tower Of Hanoi doğrusal çözümü sorunu çözmek için bitsel işlemleri kullanır.
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);
}
}
Bu çözümün açıklaması burada bulunabilir