เป็นที่เข้าใจกันว่ากรณีที่เลวร้ายที่สุดคือO(N)
มีการเพิ่มประสิทธิภาพขนาดเล็กมาก
วิธีการที่ไร้เดียงสาทำการเปรียบเทียบอักขระและการเปรียบเทียบสิ้นสุดข้อความสำหรับแต่ละอักขระ
การใช้Sentinel (เช่นสำเนาของตัวละครเป้าหมายที่ส่วนท้ายของข้อความ) ลดจำนวนการเปรียบเทียบ 1 ต่อตัวละคร
ที่ระดับ twiddling มีอยู่:
#define haszero(v) ( ((v) - 0x01010101UL) & ~(v) & 0x80808080UL )
#define hasvalue(x, n) ( haszero((x) ^ (~0UL / 255 * (n))) )
เพื่อทราบว่าไบต์ใด ๆ ในคำ ( x
) มีค่าเฉพาะ ( n
)
subexpression v - 0x01010101UL
ประเมินชุดบิตสูงในไบต์เมื่อใดก็ตามไบต์สอดคล้องกันในการเป็นศูนย์หรือมากกว่าv
0x80
นิพจน์ย่อย~v & 0x80808080UL
ประเมินค่าเป็นบิตสูงที่ตั้งเป็นไบต์ที่ไบต์ของv
ไม่มีชุดบิตสูง (ดังนั้นไบต์น้อยกว่า0x80
)
โดย ANDing นิพจน์ย่อยทั้งสองนี้ ( haszero
) ผลลัพธ์คือชุดบิตสูงที่ไบต์v
เป็นศูนย์ตั้งแต่บิตสูงตั้งเนื่องจากค่าที่มากกว่า0x80
ในนิพจน์ย่อยแรกถูกปิดโดยวินาที (27 เมษายน) 2530 โดยอลัน Mycroft)
ตอนนี้เราสามารถ XOR ค่าที่จะทดสอบ ( x
) ด้วยคำที่เต็มไปด้วยค่าไบต์ที่เราสนใจ ( n
) เพราะ XORing haszero
ค่ากับตัวเองส่งผลให้ไบต์และไม่ใช่ศูนย์ศูนย์มิฉะนั้นเราสามารถส่งผลให้
สิ่งนี้มักใช้ในstrchr
การนำไปใช้โดยทั่วไป
(Stephen M Bennet แนะนำสิ่งนี้ในวันที่ 13 ธันวาคม 2009 รายละเอียดเพิ่มเติมในBit Twiddling Hacks ที่รู้จักกันดี)
PS
รหัสนี้เสียสำหรับการรวมกันของ1111
ถัดจาก0
การแฮกผ่านการทดสอบกำลังดุร้าย (แค่อดทน):
#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;
}
จำนวน upvotes สำหรับคำตอบซึ่งทำให้สมมติฐานหนึ่งอักขระ = หนึ่งไบต์ซึ่งทุกวันนี้ไม่ใช่มาตรฐานอีกต่อไป
ขอบคุณสำหรับข้อสังเกต
คำตอบนั้นหมายถึงอะไร แต่เป็นบทความเกี่ยวกับการเข้ารหัสแบบหลายไบต์ / ตัวแปรความกว้าง :-) (ในความเป็นธรรมทั้งหมดที่ไม่ใช่ความเชี่ยวชาญของฉันและฉันไม่แน่ใจว่าเป็นสิ่งที่ OP กำลังมองหา)
อย่างไรก็ตามสำหรับฉันแล้วความคิด / เทคนิคข้างต้นสามารถปรับให้เข้ากับ MBE ได้บ้าง (โดยเฉพาะการเข้ารหัสการซิงโครไนซ์ด้วยตนเอง ):
- ตามที่ระบุไว้ในความคิดเห็นของ Johanการแฮ็คสามารถขยายได้อย่างง่ายดายเพื่อทำงานสองไบต์หรืออะไรก็ได้ (แน่นอนว่าคุณไม่สามารถยืดได้มากเกินไป)
- ฟังก์ชั่นทั่วไปที่หาตำแหน่งของตัวละครในสตริงอักขระหลายไบต์:
- เทคนิคยามสามารถใช้กับการมองการณ์ไกลเล็กน้อย