En kötü durum olduğu anlaşılıyor ki, O(N)
bazı çok güzel mikro optimizasyonlar var.
Naif yöntemi, her karakter için karakter karşılaştırması ve metin sonu karşılaştırması gerçekleştirir.
Sentinel kullanmak (yani metnin sonundaki hedef karakterin bir kopyası), karakter sayısını karşılaştırma sayısını 1'e düşürür.
Biraz twiddling düzeyinde var:
#define haszero(v) ( ((v) - 0x01010101UL) & ~(v) & 0x80808080UL )
#define hasvalue(x, n) ( haszero((x) ^ (~0UL / 255 * (n))) )
( x
) kelimesindeki herhangi bir baytın belirli bir değeri ( n
) olup olmadığını bilmek .
Alt ifade v - 0x01010101UL
, karşılık gelen bayt v
sıfır veya daha büyük olduğunda, herhangi bir byte'ta ayarlanan yüksek bir bit olarak değerlendirilir 0x80
.
Alt ifade ~v & 0x80808080UL
, baytın v
yüksek bit kümesine sahip olmadığı baytlarda ayarlanan yüksek bitleri değerlendirir (bu nedenle bayt daha küçüktü 0x80
).
Bu iki alt ifadenin ( haszero
) AND sonucu, sonuç, baytların v
sıfır olduğu yüksek bitlerdir çünkü 0x80
ilk alt ifadedeki değerden daha büyük bir değere göre ayarlanan yüksek bitler , ikinci tarafından maskelenir (27 Nisan, 1987, Alan Mycroft).
Şimdi test etmeyi ( x
) ilgilendiğimiz bayt değeriyle doldurulmuş bir sözcükle ( ) XOR yapabiliriz n
. XORing kendisi ile bir değer sıfır bayt ile sonuçlanır, aksi halde sıfırla sonuçlanmadığından sonucu geçebiliriz haszero
.
Bu genellikle tipik bir strchr
uygulamada kullanılır.
(Stephen M Bennet bunu 13 Aralık 2009'da önerdi. İyi bilinen Bit Twiddling Hack'lerinde daha ayrıntılı bilgi var ).
PS
Bu kod 1111
bir yanındaki herhangi bir kombinasyonu için bozulur.0
Hack, kaba kuvvet testini geçer (sadece sabırlı olun):
#include <iostream>
#include <limits>
bool haszero(std::uint32_t v)
{
return (v - std::uint32_t(0x01010101)) & ~v & std::uint32_t(0x80808080);
}
bool hasvalue(std::uint32_t x, unsigned char n)
{
return haszero(x ^ (~std::uint32_t(0) / 255 * n));
}
bool hasvalue_slow(std::uint32_t x, unsigned char n)
{
for (unsigned i(0); i < 32; i += 8)
if (((x >> i) & 0xFF) == n)
return true;
return false;
}
int main()
{
const std::uint64_t stop(std::numeric_limits<std::uint32_t>::max());
for (unsigned c(0); c < 256; ++c)
{
std::cout << "Testing " << c << std::endl;
for (std::uint64_t w(0); w != stop; ++w)
{
if (w && w % 100000000 == 0)
std::cout << w * 100 / stop << "%\r" << std::flush;
const bool h(hasvalue(w, c));
const bool hs(hasvalue_slow(w, c));
if (h != hs)
std::cerr << "hasvalue(" << w << ',' << c << ") is " << h << '\n';
}
}
return 0;
}
Bu varsayımı bir karakter niteliğinde kılan bir cevap için çok fazla teklif = bir bayt, günümüzde artık standart değil
Açıklama için teşekkürler.
Cevap, çok baytlı / değişken genişlikli kodlamalar :-) üzerine yapılan bir yazıdan başka bir şey değildi, (tüm adaletlerde bu benim uzmanlık alanım değil ve OP'nin aradığı şey olduğundan emin değilim).
Her neyse bana, yukarıdaki fikirlerin / püf noktaların bir şekilde MBE'ye uyarlanabileceğini (özellikle kendiliğinden senkron olan kodlamaları ):
- Johan'ın yorumunda belirtildiği gibi , kesmek 'kolayca' çift bayt veya herhangi bir şey için çalışmaya uzatılabilir (elbette çok fazla uzatamazsınız);
- çok baytlı karakter dizesindeki bir karakteri bulan tipik bir işlev:
- Sentinel tekniği biraz öngörü ile kullanılabilir.