Std :: bitset üzerinden c-tarzı bit manipülasyonunun herhangi bir avantajı var mı?


17

Neredeyse sadece C ++ 11 / 14'te çalışıyorum ve genellikle böyle bir kod gördüğümde cringe:

std::int64_t mArray;
mArray |= someMask << 1;

Bu sadece bir örnek; Genel olarak biraz akıllı manipülasyondan bahsediyorum. C ++ 'ta gerçekten bir anlamı var mı? Yukarıda belirtilenler, aşağıdakileri std::bitsetyapmanıza olanak tanıyan zihin çözgü ve hataya açıktır :

  1. std::bitsetbir şablon parametresini ayarlayarak ve uygulamanın geri kalanıyla ilgilenmesine izin vererek boyutunu gerektiği gibi daha kolay değiştirin ve
  2. neler olduğunu anlamak (ve muhtemelen hata yapmak) için daha az zaman harcayın ve diğer veri kaplarına std::bitsetbenzer şekilde yazın std::array.

Sorum şu; herhangi bir neden yoktur değil kullanmak std::bitsetgeriye dönük uyumlu olacak dışındaki üzerinde ilkel türleri,?


A'nın boyutu std::bitsetderleme zamanında sabitlenir. Aklıma gelen tek sakıncası bu.
rwong

1
@rwong Derleme zamanında da sabitlenen std::bitsetc-stili bit manipülasyonundan (örn. int) bahsediyorum .
miktar

Bunun bir nedeni eski kod olabilir: Kod, std::bitsetkullanılabilir olmadığında (veya yazar tarafından biliniyorsa) yazılmıştır ve kullanılacak kodu yeniden yazmak için bir neden yoktur std::bitset.
Bart van Ingen Schenau

Ben şahsen "bir set / harita / ikili değişkenler dizisi üzerindeki operasyonlar" herkes için anlaşılması kolay hale nasıl konu hala büyük ölçüde çözülmüş olduğunu düşünüyorum, çünkü pratikte kullanılan basit operasyonlara indirgenemez birçok işlem vardır. Ayrıca, bu tür kümeleri temsil etmenin çok fazla yolu vardır bitset, ancak bunlardan biri küçüktür veya küçük bir ints veya bit dizisi kümesi de meşru olabilir. C / C ++ felsefesi bu seçim karmaşıklıklarını programcıdan gizlemez.
rwong

Yanıtlar:


12

Mantıksal (teknik olmayan) bakış açısından hiçbir avantajı yoktur.

Herhangi bir düz C / C ++ kodu uygun "kütüphane yapısı" içine sarılabilir. Böyle bir sargıdan sonra, "bunun bundan daha avantajlı olup olmadığı" konusu tartışmalı bir soru haline gelir.

Bir hız bakış açısından, C / C ++, kütüphane yapısının sardığı düz kod kadar verimli kod üretmesine izin vermelidir. Ancak bu aşağıdakilere tabidir:

  • İşlev satır içi
  • Derleme zamanı denetimi ve gereksiz çalışma zamanı denetiminin ortadan kaldırılması
  • Ölü kod ortadan kaldırılması
  • Diğer birçok kod optimizasyonu ...

Bu tür teknik olmayan argüman kullanılarak, herhangi bir "eksik fonksiyon" herkes tarafından eklenebilir ve bu nedenle dezavantaj olarak sayılmaz.

Ancak, yerleşik gereksinimler ve sınırlamalar ek kodla aşılamaz. Aşağıda, boyutunun std::bitsetbir derleme zamanı sabiti olduğunu ve bu nedenle dezavantaj olarak sayılmamasına rağmen, hala kullanıcının seçimini etkileyen bir şey olduğunu iddia ediyorum .


Estetik bir bakış açısından (okunabilirlik, bakım kolaylığı vb.), Bir fark vardır.

Ancak, std::bitsetkodun hemen düz C kodunu kazandığı açık değildir . Kullanımının std::bitsetkaynak kodun insan kalitesini iyileştirip iyileştirmediğini söylemek için daha büyük kod parçalarına (bazı oyuncak örneklerine değil) bakmak gerekir .


Bit manipülasyonunun hızı kodlama stiline bağlıdır. Kodlama stili hem C / C ++ bit manipülasyonunu etkiler ve std::bitsetaşağıda açıklandığı gibi aynı şekilde uygulanabilir .


Biri kullanan kodu yazarsa operator [] bir kerede bir bit okumak ve yazmak için yazarsa, manipüle edilecek birden fazla bit varsa, bunu birden çok kez yapmak gerekir. Aynı şey C stili kod için de söylenebilir.

Bununla birlikte, bitsetaynı zamanda, diğer operatörler sahiptir operator &=, operator <<=vb bit kümesi tam genişliğine faaliyet. Temeldeki makineler genellikle aynı anda 32 bit, 64 bit ve bazen 128 bit (SIMD ile) çalışabildiğinden (aynı sayıda CPU döngüsünde), bu tür çok bit işlemlerinden yararlanmak üzere tasarlanmış kod "loopy" bit işleme kodundan daha hızlı olabilir.

Genel fikir SWAR (bir kayıt içinde SIMD) olarak adlandırılır ve bit manipülasyonları altında bir subtopiktir .


Bazı C ++ satıcıları bitsetSIMD ile 64 bit ve 128 bit arasında uygulama yapabilir. Bazı satıcılar yapamayabilir (ancak sonunda yapabilir). C ++ satıcının kitaplığının ne yaptığını bilmek gerekirse, tek yol sökme işlemine bakmaktır.


std::bitsetSınırlamaları olup olmadığı konusunda iki örnek verebilirim.

  1. Boyutu std::bitsetderleme zamanında bilinmelidir. Dinamik olarak seçilen boyutta bir bit dizisi yapmak için,std::vector<bool> .
  2. İçin geçerli C ++ spesifikasyonu, std::bitsetdaha büyük bitsetbir M bitinden ardışık bir N bit dilimi çıkarmak için bir yol sağlamaz .

Birincisi temeldir, yani dinamik boyutlu bit setlerine ihtiyaç duyan insanlar için diğer seçenekleri seçmeleri gerekir.

İkincisi aşılabilir, çünkü standart genişletilemez olsa bile, görevi gerçekleştirmek için bir çeşit adaptör yazabilir bitset.


Kutudan çıktığı gibi sağlanmayan belirli gelişmiş SWAR işlemleri türleri vardır std::bitset. Bu web sitesinde bu işlemler hakkında bit permütasyonları hakkında bilgi verilebilir . Her zaman olduğu gibi, bunları kendi başlarına uygulayabilirler std::bitset.


Performans tartışması ile ilgili.

Bir uyarı: Birçok insan standart kütüphaneden neden (bir şeyin) basit C tarzı kodlardan çok daha yavaş olduğunu soruyor . Burada mikrobenchmarking önkoşul bilgi tekrarlamak değil, ama ben sadece bu tavsiye var: "serbest bırakma modunda" (optimizasyon etkin) karşılaştırmak için emin olun ve kod ortadan kaldırılmadığından emin olun (ölü kod ortadan kaldırılması) veya olmak bir döngü dışına çekilir (döngü değişmez kod hareketi) .

Genel olarak birisinin (internette) mikrobenzerleri doğru yapıp yapmadığını söyleyemeyeceğimiz için, güvenilir bir sonuç elde etmenin tek yolu kendi mikrobenzer işaretlerimizi yapmak ve ayrıntıları belgelemek ve kamuoyu incelemesine ve eleştirisine sunmaktır. Başkalarının daha önce yaptıkları mikrobenzerleri yeniden yapmak zarar vermez.


Sayı # 2 ayrıca bitset'in, her bir iş parçacığının bitset alt kümesi üzerinde çalışması gereken paralel kurulumlarda kullanılamayacağı anlamına gelir.
user239558

@ user239558 Herkesin aynı paralellik yapmak isteyeceğinden şüpheliyim std::bitset. Bellek tutarlılığı garantisi (in std::bitset) yoktur, yani çekirdekler arasında paylaşılmaması gerekir. Bunu çekirdekler arasında paylaşması gereken insanlar kendi uygulamalarını oluşturma eğiliminde olacaklar. Veriler farklı çekirdekler arasında paylaşıldığında, bunları önbellek sınırına hizalamak gelenekseldir. Bunu yapmamak performansı düşürür ve daha fazla atomik olmayan tuzaklar ortaya çıkarır. Paralel hale getirilebilir bir uygulamanın nasıl oluşturulacağına dair genel bir bilgi vermek için yeterli bilgim yok std::bitset.
rwong

veri paralel programlama genellikle bellek tutarlılığı gerektirmez. yalnızca fazlar arasında senkronize edersiniz. Kesinlikle paralel bir bit seti işlemek istiyorum, bence büyük bir bitsetiradeye sahip olan herkes .
user239558

@ user239558, kulağa kopyalama anlamına gelir (her çekirdek tarafından işlenecek ilgili bitset aralığı, işlem başlamadan önce kopyalanacaktır). Buna katılıyorum, ancak paralelleşmeyi düşünen herkesin kendi uygulamalarını yaymayı düşüneceğini düşünüyorum. Genel olarak, temel uygulamalar olarak birçok C ++ standart kütüphane tesisi sağlanmıştır; daha ciddi ihtiyaçları olan herkes kendi uygulayacaktır.
rwong

hayır kopya yok. sadece statik veri yapısının farklı bölümlerine erişiyor. o zaman senkronizasyon gerekmez.
user239558

2

Bu kesinlikle her durumda geçerli değildir, ancak bazen bir algoritma önemli performans kazanımları sağlamak için C tarzı bit döndürme etkinliğine bağlı olabilir. Aklıma gelen ilk örnek bitboard'ların kullanımıdır , satranç motorlarını ve benzerini hızlandırmak için , masa oyunu pozisyonlarının akıllı tamsayı kodlamalarının kullanılmasıdır. Burada, satranç tahtaları her zaman 8 * 8 olduğundan, tamsayı türlerinin sabit boyutu sorun değildir.

Basit bir örnek olarak, bir Connect Four konumunu zafer için test eden aşağıdaki işlevi ( Ben Jackson tarafından verilen bu cevaptan alınmıştır) düşünün :

// return whether newboard includes a win
bool haswon2(uint64_t newboard)
{
    uint64_t y = newboard & (newboard >> 6);
    uint64_t z = newboard & (newboard >> 7);
    uint64_t w = newboard & (newboard >> 8);
    uint64_t x = newboard & (newboard >> 1);
    return (y & (y >> 2 * 6)) | // check \ diagonal
           (z & (z >> 2 * 7)) | // check horizontal -
           (w & (w >> 2 * 8)) | // check / diagonal
           (x & (x >> 2));      // check vertical |
}

2
Sizce std::bitsetdaha yavaş olur mu?
miktar

1
Kaynağa hızlı bir bakışla, libc ++ bitset tek bir size_t veya bunlardan oluşan bir diziye dayanır, bu nedenle özellikle sizeof (size_t) == 8 - yani hayır, muhtemelen daha yavaş olmazdı.
Ryan Pavlik
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.