Bit operatörleri ne işe yarar? [kapalı]


19

Programlama dilleri genellikle çeşitli bit işleçleriyle gelir (örn. Bitsel sola ve sağa kaydırma, bitsel AND, OR, XOR ...). Bunlar çok fazla kullanılmıyor ya da en azından benim deneyimlerim böyle oldu. Bazen programlama zorluklarında veya röportaj sorularında kullanılırlar veya çözüm gerektirebilir, örneğin:

  • Herhangi bir eşitlik operatörü kullanmadan, geri dönen bir işlev oluşturun true iki değer eşit olduğunda
  • Üçüncü bir değişken kullanmadan, iki değişkenin değerini değiştirin

Bunlar yine, muhtemelen çok az gerçek dünya kullanımına sahiptir. Sanırım daha hızlı olmalılar çünkü hafızayı doğrudan düşük seviyede manipüle ediyorlar.

Neden çoğu programlama dilinde bulunur? Gerçek dünya kullanım durumları var mı?


@Anto - Kolay bir örnek, bir istemciye bir seferde 256 kelime (4096 bayt) hızında 256Kb değerinde veri göndermek olacaktır.
Ramhound

1
C return !(x-y);:? Bilmiyorum
Andrew Arnold

@Andrew: Bu bir çözüm, ancak bitsel operatörlerle de yapabilirsiniz.
Anto

19
"Bunlar çok fazla kullanılmıyor" - Emin misin? Onları her zaman kullanıyorum. Hepimiz sorun alanınızda çalışmıyoruz.
Ed S.

2
Tam bir cevap için yeterli değil, ancak bitin ilk 4 bitini biraz uğraşmadan okumaya çalışın ve ardından bazı veri formatlarının çok sıkı bir şekilde paketlendiğini düşünün .
Brendan Long

Yanıtlar:


53

Hayır, birçok gerçek dünya uygulamaları var ve bilgisayarlardaki temel işlemler.

Onlar için kullanılır

  • Programlama dilleri veri türlerine uymayan bayt bloklarını çevirme
  • Kodlamayı büyük ve küçük endiandan ileri geri değiştirme.
  • Bazı seri veya usb bağlantısı için 4 bitlik veriyi 3 bayta paketleme
  • Birçok görüntü formatı, her renk kanalına atanan farklı miktarlarda bitlere sahiptir.
  • Gömülü uygulamalarda IO pinlerini içeren her şey
  • Genellikle veri içermeyen veri sıkıştırma, 8 bitlik güzel sınırlara uyuyor. \
  • Karma algoritmalar, CRC veya diğer veri bütünlüğü kontrolleri.
  • Şifreleme
  • Sıralanan sayı oluşturma
  • Raid 5, pariteyi hesaplamak için birimler arasında bitsel XOR kullanır.
  • Ton daha

Aslında, mantıksal olarak, bir bilgisayardaki tüm işlemler sonuç olarak işlemcinin elektrik kapıları içinde gerçekleşen bu düşük seviyeli bitsel işlemlerin kombinasyonlarına kaynatılır.


1
Hatta eklemekte olduğunuz oldukça kapsamlı listeniz için +1
Anto

28
+1. @Anto: Bu liste ise hiçbir yerde yakın kapsamlı. Sistem programlamasında bitsel operatörler için kapsamlı bir kullanım durumları listesi, iş uygulamalarındaki SQL sorguları için kapsamlı bir liste kadar uzun olacaktır. Eğlenceli gerçek: Her zaman bitsel işlemleri kullanıyorum, ancak yıllar içinde bir SQL ifadesi yazmadım ;-)
nikie

4
@nikie: Ve her zaman SQL yazıyorum, ancak yıllardır bitsel operatör kullanmadım! :)
FrustratedWithFormsDesigner

3
Gömülü sistemlerde çalışıyorum - bitsel operatörler ekmek ve tereyağı şeyleridir. Hiç düşünmeden her gün kullanılır.
quickly_now

9
SQL'de zaman zaman bitshifting kullanırsam bir ödül alır mıyım?
Karınca

13

Çünkü onlar temel operasyonlar.

Düşünce aynı hat ederek, iddia olabilir eklenmesi o çıkarma (ve olumsuzlama) ve çarpma ile tamamen değiştirmek mümkün olduğundan, birkaç gerçek dünya kullanımları vardır. Ama eklemeye devam ediyoruz çünkü bu temel bir işlem.

Ve bir an için düşünün, sadece bitsel işlemlere çok fazla ihtiyaç duymadığınız için çok sık kullanılmadıkları anlamına gelmez. Gerçekten de, bit maskeleme gibi şeyler için kullandığım neredeyse her dilde bitsel ops kullandım.

Başımın üstünde, görüntü işleme, bit alanları ve bayraklar, metin işleme (örneğin, belirli bir sınıfın tüm karakterleri genellikle ortak bir bit desenini paylaşıyor), seri veriyi kodlama ve kod çözme, VM veya CPU kod çözme için bitsel ops kullandım opcodes vb. Bitsel oplar olmadan, bu görevlerin çoğu, görevi daha az güvenilir veya daha düşük okunabilirlikle gerçekleştirmek için birçok kez daha karmaşık işlemler gerektirir.

Örneğin:

// Given a 30-bit RGB color value as a 32-bit int
// A lot of image sensors spit out 10- or 12-bit data
// and some LVDS panels have a 10- or 12-bit format
b = (color & 0x000003ff);
g = (color & 0x000ffc00) >> 10;
r = (color & 0x3ff00000) >> 20;

// Going the other way:
color = ((r << 20) & 0x3ff00000) | ((g << 10) & 0x000ffc00) | (b & 0x000003ff);

RISC tipi CPU'lar için CPU yönergelerinin kodunun çözülmesi (başka bir platform taklit edilirken olduğu gibi) yukarıdaki gibi büyük bir değere sahip bölümlerin çıkarılmasını gerektirir. Bazen, bu işlemleri çarpma ve bölme ve modulo, vb. İle yapmak, eşdeğer bitsel op'lardan on kat daha yavaş olabilir.


12

Tipik bir örnek, 24 bit RGB değerinden ve arkadan ayrı renkleri ayıklamaktır.


DÜZENLEME: http://www.docjar.com/html/api/java/awt/Color.java.html

    value =  ((int)(frgbvalue[2]*255 + 0.5))    |
                (((int)(frgbvalue[1]*255 + 0.5)) << 8 )  |
                (((int)(frgbvalue[0]*255 + 0.5)) << 16 ) |
                (((int)(falpha*255 + 0.5)) << 24 );

Bu örnek pratikte gösterilsin mi? Kod pasajı?
Anto

Daha iyi bir örnek, 16 bit (4.5bpc) veya 30 bit (10bpc) RGB değerlerini işlemek olabilir.
greyfade

@grey, böyle örnekler eklemekten çekinmeyin.

6

İşte Quake 3, Quake 4'te bulabileceğiniz gerçek bir dünya örneği . Doom III. Q3 motorunu kullanan tüm bu oyunlar .

float Q_rsqrt( float number )
{
        long i;
        float x2, y;
        const float threehalfs = 1.5F;

        x2 = number * 0.5F;
        y  = number;
        i  = * ( long * ) &y;                       // evil floating point bit level hacking [sic]
        i  = 0x5f3759df - ( i >> 1 );               // what the fuck? [sic]
        y  = * ( float * ) &i;
        y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//    y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

        return y;
}

(Kayan nokta numaralarının nasıl saklandığını anlamanız gereken kodu anlamak için kesinlikle bu konuda ayrıntılı bilgi veremiyorum)

Kullanım açısından, ağ veya grafik gibi biraz kaydırma gerektiren alanlarda değilseniz, amaçlarını biraz akademik bulabilirsiniz. Ama yine de ilginç (benim için en azından).


+1 Siz olmasanız bile bu yorumlar için. Beni kıkırdadı.
Baslayıcı

4

Kaydırma, iki güçle çarpmaktan veya bölmekten daha hızlıdır. Örneğin, bir << = 2, a ile 4'ü çarpar. Bunun tersine, bir >> = 2, a'yı dörde böler. Bir de bit-bilge operatörleri kullanarak bir cihaza veri bit-bang olabilir. Örneğin, N döngülerindeki shift, xor ve "ve" işlemlerini kullanarak N pin bağlantı noktasından N seri veri akışı gönderebiliriz. Dijital mantıkta gerçekleştirilebilecek her şey yazılım üzerinden de yapılabilir.


1
Sadece yukarı veya aşağı yuvarlama vb. benim için.
Daemin

@Daemin: Bu tekniği kullandığımda tamsayılarla çalışıyorum. C ve C ++ 'da tamsayı bölümü için varsayılan davranış sıfıra doğru kesilmesidir; bu nedenle, bir tamsayıyı iki güçle değiştirmek, tamsayıyı iki güçle bölmekle aynı sonucu verir.
bit-twiddler

1
@ bit-twiddler Sağ kaydırma, negatif sayıların bölünmesiyle aynı şekilde çalışmaz.
Daemin

@Daemin: Bana yanlış olduğunu kanıtlarken cehennem gibi görünüyorsun. İlk olarak, yuvarlama problemini atıyorsunuz. Bu iddiayı, C ve C ++ bölümlerinin sıfıra doğru kesildiğini belirterek reddettiğimde, imzalanan tam sayı sorununu atarsınız. Vardiya operatörünü, tamamlayıcı negatif tamsayıları imzaladığımı nereden söyledim? Bununla birlikte, biri iki kişilik bir güce bölmek için vardiya operatörünü kullanmaya devam edebilir. Ancak, C ve C ++ düz eski sağ kaydırma yerine aritmetik sağ kaydırma gerçekleştirdiğinden, değerin negatif olup olmadığını kontrol etmek gerekir. Değer negatifse,
bit-twiddler

1
Kesin olarak, küçük farklılıklar olduğu için kaydırma özelliğini çarpma ve bölme yerine kullanırken dikkatli olun. Ne fazla ne az.
Daemin

3

Uzun zaman önce, bit operatörleri faydalıydı. Bugün daha az. Ah onlar tamamen yararsız değildir, ama bir o kullanılmış görmeyeli uzun zaman oldu should kullanılmıştır.

1977'de meclis dili programcısıydım. Meclisin tek gerçek dil olduğuna ikna oldum. Pascal gibi bir dilin, hiçbir zaman gerçek bir şey elde etmek zorunda olmayan akademik deneyimler için olduğundan emindim .

Sonra Kernighan ve Ritchie'nin "C Programlama Dili" ni okudum. Fikrimi tamamen değiştirdi. Sebep? Biraz operatör vardı! O was bir derleme dil! Sadece farklı bir sözdizimi vardı.

O günlerde ands, ors, shift ve rots olmadan kod yazmayı düşünemedim. Bugünlerde neredeyse hiç kullanmıyorum.

Yani, sorunuzun kısa cevabı: "Hiçbir şey." Ama bu pek adil değil. Yani daha uzun cevap: "Çoğunlukla hiçbir şey."


xkcd.com/378 akla geliyor.
En fazla

Bit operatörleri bu gün için yararlıdır. Alan adınızda kullanılmadıkları gerçeği, onu kullanılmaz veya çok sık kullanılmaz. İşte basit bir örnek: Bit operatörleri olmadan AES'yi deneyin ve uygulamayı. Bu, çoğu bilgisayarda günlük olarak günde yüzlerce veya binlerce kez yapılan bir şeylerin manşet dışı bir örneğidir.
SADECE DOĞRU GÖRÜŞÜM

Verileri bit-bilge operatörler kullanmadan kodlamak / kodunu çözmek en iyi ihtimalle acı vericidir. Örneğin, bir mesaja MIME ekleri eklemek, üç ila dört veri kodlamasını (yani radix64 kodlaması) işleyebilmemizi gerektirir.
bit-twiddler

2

Şifreleme

DES şifreleme algoritmasından çok küçük bir snippet'e göz atmanızı öneririm :

temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);

Bu günlerde DES'in tavsiye edilmemesine rağmen: P
Armand

@Alison: Hayır, ancak yerini alan şifreleme algoritmalarının daha fazla bit manipülasyon işlemi içerdiğini düşünüyorum. :-)
Carson63000

@Alison - elbette, ancak TripleDES sadece 3 kez anahtar biti ile 3 kez yapılır.
Scott Whitlock

2

Birçok iyi cevap, bu yüzden bu kullanımları tekrar etmeyeceğim.

Onları yönetilen kodda oldukça kullanıyorum (C # / .Net) ve yerden tasarruf, yüksek performans veya akıllı bit kaydırma algoritmaları ile ilgisi yok. Bazen bazı mantık bu şekilde veri depolamak için çok uygundur. Onları bir enum'um olduğunda sıklıkla kullanıyorum, ancak örnekler aynı anda o numaradan birden fazla değer alabilir. İşten bir kod örneği gönderemiyorum, ancak "Flags enum" için hızlı bir google ("Flags" bitsel bir şekilde kullanılacak bir enum tanımlamanın C # yoludur) bu güzel örneği verir: http: // www.dotnetperls.com/enum-flags .


2

Ayrıca biraz paralel hesaplama var. Verileriniz yalnızca 1 ve 0 ise, bunlardan 64 tanesini imzasız uzun uzun bir kelimeye ekleyebilir ve 64 yönlü paralel işlemler alabilirsiniz. Genetik bilgi iki bittir (DNA'nın AGCT kodlamasını temsil eder) ve eğer çeşitli hesaplamaları biraz paralel şekilde yapabiliyorsanız, yapmamanızdan çok daha fazlasını yapabilirsiniz. Hafızadaki verilerin yoğunluğundan bahsetmemek gerekirse - bellekte veya disk kapasitesinde veya iletişim bant genişliği sınırlıysa, sıkıştırma / açma işleminin dikkate alınması gerektiği anlamına gelir. Görüntü işleme gibi alanlarda ortaya çıkan düşük hassas tamsayılar bile zor bit paralel hesaplamadan yararlanabilir. Kendi başına bir sanattır.


1

Neden bulunurlar?

Bunun nedeni büyük olasılıkla montaj talimatlarına karşılık gelmesidir ve bazen sadece üst düzey dillerdeki şeyler için yararlıdır. Aynı şey montaj talimatına GOTOkarşılık gelen korkunç için de geçerlidir JMP.

Kullanımları nelerdir?

Gerçekten isimlendirmek için birçok kullanımları var, bu yüzden son derece yerelleştirilmiş olsa da, son zamanlarda kullanacağım. 6502 montajı ile çok çalışıyorum ve bellek adreslerini, değerleri, değerleri karşılaştırıp GameGenie cihazı (temel olarak NES için bir hile uygulaması) için kullanılabilecek kodlara dönüştüren küçük bir uygulama üzerinde çalışıyordum. Kodlar biraz bit manipülasyonu ile oluşturulur.


1

Bugünlerde birçok programcı neredeyse sonsuz belleğe sahip bilgisayarlara alışkın.

Ancak bazı kullanımlar hala her bitin önemli olduğu küçük mikrodenetleyicileri programlıyor (örneğin yalnızca 1k veya daha az RAM'e sahip olduğunuzda) ve bitsel operatörler, bir programcının bu bitleri çok daha büyük programlama israf etmek yerine birer birer kullanmasına izin veriyor algoritmanın gerektirdiği bazı durumları tutmak için gerekenden daha soyutlama objesi. Bu cihazlardaki ES ayrıca bitsel olarak okunmasını veya kontrol edilmesini gerektirebilir.

"Gerçek dünya" sunucular veya bilgisayarlardan çok daha küçük mikrodenetleyicilere sahiptir.

Saf teorik CS tipleri için, Turing makineleri tamamen devlet parçalarıyla ilgilidir.


1

Bitsel operatörlerin birçok olası kullanımından sadece birkaçı ...

Bitsel operatörler, kodunuzu daha okunabilir hale getirmeye de yardımcı olabilir. Aşağıdaki işlev bildirimini göz önünde bulundurun ....

int  myFunc (bool, bool, bool, bool, bool, bool, bool, bool);

...

myFunc (false, true, false, false, false, true, true, false);

Kodu yazarken veya hatta okurken hangi boole parametresinin ne anlama geldiğini unutmak çok kolaydır. Sayımınızı takip etmek de kolaydır. Böyle bir rutin temizlenebilir.

/* More descriptive names than MY_FLAGx would be better */
#define MY_FLAG1    0x0001
#define MY_FLAG2    0x0002
#define MY_FLAG3    0x0004
#define MY_FLAG4    0x0008
#define MY_FLAG5    0x0010
#define MY_FLAG6    0x0020
#define MY_FLAG7    0x0040
#define MY_FLAG8    0x0080

int  myFunc (unsigned myFlags);

...

myFunc (MY_FLAG2 | MY_FLAG6 | MY_FLAG7);

Daha açıklayıcı bayrak adları ile çok daha okunabilir hale gelir.


1

Unicode hakkında bir şey biliyorsanız , muhtemelen UTF-8'i biliyorsunuzdur . 20 bit kod noktasını 1 ila 4 bayta paketlemek için bir grup bit testi, vardiya ve maske kullanır.


0

Onları sık kullanmıyorum ama bazen kullanışlı oluyorlar. Numaralandırma yönetimi akla geliyor.

Misal:

enum DrawBorder{None = 0, Left = 1, Top = 2, Right = 4, Bottom = 8}

DrawBorder drawBorder = DrawBorder.Left | DrawBorder.Right;//Draw right & left border
if(drawBorder & DrawBorder.Left == DrawBorder.Left)
  //Draw the left border
if(drawBorder & DrawBorder.Top == DrawBorder.Top)
  //Draw the top border
//...

0

Bu kullanımın henüz kaydedilip kaydedilmediğinden emin değilim:

Birden fazla dönüş değerini 0 veya 1'e düşürmek için illumos (openSolaris) kaynak koduyla çalışırken VEYA çok fazla görüyorum, örn.

int ret = 0;
ret |= some_function(arg, &arg2); // returns 0 or 1
ret |= some_other_function(arg, &arg2); // returns 0 or 1
return ret;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.