Back to site

Біт склаўшы хакі

Шон Андэрсан Эрон
seander @ CS. stanford.edu

Індывідуальна, фрагменты кода тут у грамадзкай уласнасьці (калі не пазначана іншае) - не саромейцеся выкарыстаць іх, як вам будзе заўгодна. Сукупны збор і апісання © 1997-2005 Шон Эрон Андэрсан. Код і апісанне распаўсюджваецца ў надзеі, што яны будуць карысныя, але без якіх-небудзь ГАРАНТЫЙ і нават без пэўныя гарантый таварнасці або прыдатнасці для пэўнай мэты. Па стану на 5 мая 2005 года, увесь код быў правераны цалкам. Тысячы людзей чыталі яго. Акрамя таго, прафесар Рэндал Брайант , дэкан кампутарных навук Універсітэта Карнегі-Меллона, мае асабіста праверыў амаль ўсё, са сваімі Uclid сістэмы праверкі кода . Тое, што ён не правяраў, я праверыў ад усіх магчымых уваходаў-бітныя машыны 32. Для першага асобы, каб паведаміць мне аб законных памылку ў кодзе, я заплачу за галовамі ЗША $ 10 (чэкам ці Paypal ). Калі, накіраваныя на дабрачыннасць, я буду плаціць 20 даляраў ЗША.

Змест


Аб метадалогіі падліку аперацыі

Пры агульнай лік аперацый для алгарытмаў тут, любы аператар C лічыцца як адна аперацыя. Прамежкавыя заданні, якія не павінны быць запісаны ў памяць, не ўлічваюцца. Вядома, гэтая аперацыя падліку падыходу служыць толькі як набліжэнне фактычнае лік машынных каманд і процессорного часу. Усе аперацыі мяркуецца прыняць такое ж колькасць часу, што гэта не так у рэчаіснасці, але працэсары маюць ўзначальвае ўсё больш у гэтым напрамку на працягу доўгага часу. Ёсць шмат нюансаў, якія вызначаюць, наколькі хутка сістэма будзе працаваць дадзенага ўзору кода, такія як аб'ём кэш-памяці, памяць паласы, наборы інструкцый і г.д. У рэшце рэшт, бенчмаркинга з'яўляецца лепшым спосабам для вызначэння адзін метад сапраўды хутчэй, чым іншыя , таму разгледзім метады ніжэй у якасці магчымасці для тэставання на мэтавай архітэктуры.


Вылічыць знак цэлага

int v;      // we want to find the sign of v
int sign;   // the result goes here 

// CHAR_BIT is the number of bits per byte (normally 8).
sign = -(v < 0);  // if v < 0 then -1, else 0. 
// or, to avoid branching on CPUs with flag registers (IA32):
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// or, for one less instruction (but not portable):
sign = v >> (sizeof(int) * CHAR_BIT - 1); 
Апошняе выраз вышэй ацэньвае ў знак = V>> 31 для 32-разрадных цэлых лікаў. Гэта адна аперацыя хутчэй, чым відавочным чынам, знак = - (V <0). Гэты трук працуе, таму што, калі цэлых лікаў ссунутыя правы, значэнне левага біта капіюецца на іншыя біты. Крайні злева біт роўны 1, калі кошт з'яўляецца адмоўнай і 0 ў адваротным выпадку, усё 1 біт дае -1. На жаль, такія паводзіны пэўнай архітэктуры.

Акрамя таго, калі вы аддаеце перавагу выніку альбо -1 або +1, а затым выкарыстаць:

sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1));  // if v < 0 then -1, else +1

З іншага боку, калі вы аддаеце перавагу выніку альбо -1, 0 або +1, а затым выкарыстаць:


sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// Or, for more speed but less portability:
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1));  // -1, 0, or +1
// Or, for portability, brevity, and (perhaps) speed:
sign = (v > 0) - (v < 0); // -1, 0, or +1
Калі замест гэтага вы хочаце ведаць, калі што-то не з'яўляецца адмоўным, у выніку чаго +1 ці інакш 0, а затым выкарыстаць:
sign = 1 ^ ((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then 0, else 1
Перасцярогу: 7 сакавіка 2003 года, Ангус Дагган адзначыў, што ў 1989 ANSI C спецыфікацыі лісце выніку падпісанага зруху направа ад рэалізацыі, так што на некаторых сістэмах гэта ўзламаць не можа працаваць. Для большай мабільнасці, Тобі Спейт прапанаваў 28 верасня 2005 года, што CHAR_BIT быць выкарыстаны тут і ва ўсім, а не мяркуючы байт 8 біт. Ангус рэкамендаваў больш партатыўнай версіі вышэй, уключаючы ліццё 4 Сакавіка 2006. Rohit Garg прапанаваў вэрсія для неадмоўных цэлых 12 верасня 2009 года.


Выявіць, калі два цэлых лікі маюць супрацьлеглыя знакі

int x, y;               // input values to compare signs

bool f = ((x ^ y) < 0); // true iff x and y have opposite signs
Манфрэд Вайс прапанаваў мне дадаць гэты запіс ад 26 лістапада 2009 года.


Вылічыць абсалютная значэнне цэлага (ABS) без галінавання

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
int const mask = v >> sizeof(int) * CHAR_BIT - 1;

r = (v + mask) ^ mask;
Запатэнтаваная змены:
r = (v ^ mask) - mask;
Некаторыя працэсары не маюць абсалютная цэлае інструкцыяй значэння (ці кампілятар не можа іх выкарыстоўваць). На машынах, дзе галінаванне дарогай, гэты выраз можа быць хутчэй, чым відавочны падыход, R = (V <0)? - (Без подпісу) V: V, хаця колькасць аперацый ж.

7 Сакавіка 2003 года, Ангус Дагган адзначыў, што ў 1989 ANSI C спецыфікацыі лісце выніку падпісанага зруху направа ад рэалізацыі, так што на некаторых сістэмах гэта ўзламаць не можа працаваць. Я чытаў, што ANSI C не патрабуе значэння быць прадстаўлена ў выглядзе дапаўненні да двух, таму ён не можа працаваць па гэтай прычыне, а таксама (на diminishingly невялікі лік старых машын, якія па-ранейшаму выкарыстоўваць свае дапаўненні). 14 сакавіка 2004 г, Кіт Г. Даггар паслаў мяне запатэнтаванай змены вышэй; яна пераўзыходзіць той, які я першапачаткова прыдумаў, r=(+1|(v>>(sizeof(int)*CHAR_BIT-1)))*v , так як размнажаюцца не выкарыстоўваецца. На жаль, гэты метад быў запатэнтаваны ў ЗША 6 чэрвеня 2000 г. В. Ю. Валконскі і прысвойваецца Sun Microsystems . 13 жніўня 2006 года, Юрый Камінскі распавёў мне, што патэнт, хутчэй за ўсё, недапушчальны, паколькі метад быў апублікаваны задоўга да таго, патэнт быў нават пададзены, напрыклад, у Як аптымізаваць для працэсара Pentium -за туману Агнер ад 9 лістапада 1996 года. Юрый таксама адзначыў, што гэты дакумент быў пераведзены на рускую мову ў 1997 годзе, які Уладзімір мог бы прачытаць. Акрамя таго, Internet Archive таксама мае старую спасылку на яго. 30 Студзень 2007 Пётр Kankowski падзяліўся са мной ABS вэрсіі ён выявіў, што быў натхнёны Microsoft Visual C + + у выснову кампілятара. Гэта прыкметах тут у якасці асноўнага рашэння. 6 сьнежня 2007 года, Хай Джын скардзіліся, што вынік быў падпісаны, так што пры вылічэнні ABS з найбольш адмоўнае значэнне, яна па-ранейшаму адмоўны. 15 Красавік 2008 г. Эндру Шапіра адзначыў, што відавочна падыход можа перапаўнення, так як не хапала (Без подпісу) адліваныя затым, для максімальнай мабільнасці ён прапанаваў (v < 0) ? (1 + ((unsigned)(-1-v))) : (unsigned)v . Але са спасылкай C99 ISO спектру ад 9 ліпеня 2008 года, Вінцэнт Лефевр пераканаў мяне, каб выдаліць яго, таму што нават на не-2-дадатак машын - (Без подпісу) V ​​будзе рабіць правільныя рэчы. Ацэнка - (Без подпісу) V ​​Год пераўтворыць адмоўнае значэнне V для непадпісаным, дадаўшы 2 ** N, саступаючы 2s дадатак прадстаўлення значэння V аб тым, што я буду называць U. Тады U адмаўляецца, што дае жаданага выніку ,-U = 0 - U = 2 ** N - U = 2 ** N - (V 2 ** N) =- V = ABS (V).


Вылічыць мінімальную (мін) або максімум (максімум) двух цэлых лікаў без галінавання

int x;  // we want to find the minimum of x and y
int y;   
int r;  // the result goes here 

r = y ^ ((x ^ y) & -(x < y)); // min(x, y)
Аб некаторых рэдкіх машын, дзе галінаванне вельмі дарагімі, і ніякіх інструкцый ўмовы перамяшчэння існуе, гэта выраз можа быць хутчэй, чым відавочны падыход, г = (х <у)? х: у, нават калі яна складаецца з двух дадатковых інструкцый. (Як правіла, відавочны падыход лепш, ўсё ж.) Гэта працуе, таму што калі х <у, то - (х <у) будуць усе тыя, так што R = Y ^ (х ^ у) і = 0 = Y ^ X ^ у = х У адваротным выпадку, калі х> = у, то - (х <у) будуць усе нулі, таму R = Y ^ ((х ^ у) & 0) = y. На некаторых машынах, ацэнкі (х <у), 0 або 1 патрабуе інструкцыю галінавання, так што можа быць ніякага перавагі.

Каб знайсці максімальна, выкарыстаць:

r = x ^ ((x ^ y) & -(x < y)); // max(x, y)

Хуткі і брудны версіі:

Калі вы ведаеце, што INT_MIN <= х - у <= INT_MAX, то вы можаце выкарыстоўваць наступныя, якія хутчэй, таму што (х - у) толькі трэба ацэньваць адзін раз.
r = y + ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // min(x, y)
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)

Адзначым, што ў 1989 ANSI C спецыфікацыя не вызначае вынік падпісанага зруху ўправа, так што яны не пераносным. Калі выключэнняў на перапаўненне, то значэння X і Y павінны быць без знака або прыведзены да непадпісаным для аднімання, каб пазбегнуць неабходнасці кідаць выключэнне, аднак зрух направа патрэбаў падпісаў аперанд каб вырабіць усе адзін біт пры адмоўных, так літой падпісаным там.

7 Сакавіка 2003 года, Ангус Дагган паказаў пытанне зруху направа пераноснасці. 3 мая 2005 года, Рэндал Брайант Е. папярэдзіў мяне аб неабходнасці папярэдніх умоў, INT_MIN <= х - у <= INT_MAX, і прапанаваў не-хутка і брудна версіі выправіць. Абедзве гэтыя праблемы датычацца толькі хутка і брудна версіі. Найджэл Horspoon назіраецца 6 ліпеня 2005 года, што GCC вытворчасці і той жа код на Pentium як відавочнае рашэнне, таму што, як ён ацэньвае (х <у). З 9 ліпеня 2008 года Вінцэнт Лефевр адзначыў, патэнцыял для выключэння перапаўнення з аднімання ў R = Y + ((х - у) і - (х <у)), які быў у папярэдняй версіі. Timothy B. Terriberry прапанаваў выкарыстаць XOR, а не дадаваць і subract, каб пазбегнуць ліцця і рызыка перапаўнення 2 чэрвень 2009.


Вызначэнне, калі цэлае лік з'яўляецца ступенню 2

unsigned int v; // we want to see if v is a power of 2
bool f;         // the result goes here 

f = (v & (v - 1)) == 0;
Note that 0 is incorrectly considered a power of 2 here. To remedy this, use:
f = v && !(v & (v - 1));


Ўвайдзіце распасціраецца ад пастаяннай бітавай шырыні

Ўвайдзіце пашырэнне аўтаматычныя для ўбудаваных тыпаў, такіх як сімвалы і цэлыя. Але выкажам здагадку, у вас ёсць падпісаны з дадаткам да двух лік, X, які захоўваецца выкарыстоўваючы толькі біты б. Акрамя таго, выкажам здагадку, вы хочаце, каб пераўтварыць х да Int, які мае больш, чым B біт. Простае капіраванне будзе працаваць, калі х з'яўляецца станоўчым, але калі адмоўная, то знак павінен быць працягнуты. Напрыклад, калі ў нас толькі 4 біта для захоўвання ліку, то -3 уяўляецца як 1101 ў двайковай сыстэме. Калі ў нас ёсць 8 біт, то -3 з'яўляецца 11111101. Самы старэйшы біт прадстаўленне 4-бітны реплицируется sinistrally запоўніць прызначэння, калі мы пераўтварыць у паказ з больш бітаў, гэта знак пашырэння. У C, знакавая пашырэнне з пастаяннай бітавай шырыні трывіяльна, так як бітавы поля могуць быць паказаны ў структуры і саюзы. Напрыклад, для пераўтварэння з 5 біт для поўнага ліку:
int x; // convert this from using 5 bits to a full int
int r; // resulting sign extended number goes here
struct {signed int x:5;} s;
r = s.x = x;
Ніжэй C + + шаблён функцыі, якая выкарыстоўвае тую ж функцыю мовы для пераўтварэння з B біт у адной аперацыі (хоць кампілятар генэруе больш, вядома).

template <typename T, unsigned B>
inline T signextend(const T x)
{
  struct {T x:B;} s;
  return s.x = x;
}

int r = signextend<signed int,5>(x);  // sign extend 5 bit number x to r

Джон Бэрд злавілі памылку друку ў кодзе (прыпісваецца HTML фарматавання) 2 мая 2005 года. 4 сакавіка 2006, Пэт Вуд адзначыў, што стандарт ANSI C патрабуе, каб бітавы поля маюць ключавое слова "падпісалі" будзе падпісаны, у адваротным выпадку знак не вызначаны.


Ўвайдзіце распасціраецца ад зменнай бітавай шырыні

Часам нам трэба пашырыць знак нумары, але мы не ведаем апрыёры лік бітаў, бы, у якой ён прадстаўлены. (Або мы маглі б быць праграмавання на мове Java, як, у якім адсутнічаюць бітавы поля.)
unsigned b; // number of bits representing the number in x
int x;      // sign extend this b-bit number to r
int r;      // resulting sign-extended number
int const m = 1U << (b - 1); // mask can be pre-computed if b is fixed

x = x & ((1U << b) - 1);  // (Skip this if bits in x above position b are already zero.)
r = (x ^ m) - m;
Код вышэй, патрабуе чатыры аперацыі, але калі bitwidth з'яўляецца пастаяннай, а не зменнай, яна патрабуе толькі дзве аперацыі хутка, лічачы верхні біт ўжо нулямі.

Трохі хутчэй, але меней партатыўны метад, які не залежыць ад бітаў у х б вышэй пазіцыя роўная нулю з'яўляецца:

int const m = CHAR_BIT * sizeof(x) - b;
r = (x << m) >> m;

Шон А. Ірвін прапанаваў мне дадаць метады пашырэння знака на гэтую старонку на 13 чэрвеня 2004 года, і ён прадставіў m = (1 << (b - 1)) - 1; r = -(x & ~m) | x; у якасці адпраўным пункту, ад якой я аптымізаваны, каб атрымаць т = 1U <<(Ь - 1); R = - (X & M) | X. Але тады, 11 траўня 2007 года, шый Зялёны прапанаваў версію вышэй, што патрабуе на адзінку менш працы, чым мая. Vipin Шарма прапанаваў мне дадаць крок мець справу з сітуацыямі, калі х былі магчымымі ў бітах, акрамя B біт мы хацелі рэгістрацыі падоўжыць на 15 кастрычніка 2008 года. На 31 снежня 2009 Крыс Pirazzi прапанаваў мне дадаць больш хуткая версія, якая патрабуе дзве аперацыі на пастаяннай бітавай шырыні і тры для зменнай шырыні.


Ўвайдзіце распасціраецца ад зменнай бітавай шырынёй у 3 аперацыі

Наступныя можа быць павольным на некаторых машынах з-за намаганняў, неабходных для множання і дзялення. Гэтая версія 4 аперацыі. Калі вы ведаеце, што ваш першапачатковы біт шырыня, B, больш 1, вы маглі б зрабіць гэты тып знакавая пашырэнне ў 3 аперацыі з дапамогай R = (х * мультыплікатараў [б]) / мультыплікатараў [б], які патрабуе толькі аднаго масіў пошуку.
unsigned b; // number of bits representing the number in x
int x;      // sign extend this b-bit number to r
int r;      // resulting sign-extended number
#define M(B) (1U << ((sizeof(x) * CHAR_BIT) - B)) // CHAR_BIT=bits/byte
static int const multipliers[] = 
{
  0,     M(1),  M(2),  M(3),  M(4),  M(5),  M(6),  M(7),
  M(8),  M(9),  M(10), M(11), M(12), M(13), M(14), M(15),
  M(16), M(17), M(18), M(19), M(20), M(21), M(22), M(23),
  M(24), M(25), M(26), M(27), M(28), M(29), M(30), M(31),
  M(32)
}; // (add more if using more than 64 bits)
static int const divisors[] = 
{
  1,    ~M(1),  M(2),  M(3),  M(4),  M(5),  M(6),  M(7),
  M(8),  M(9),  M(10), M(11), M(12), M(13), M(14), M(15),
  M(16), M(17), M(18), M(19), M(20), M(21), M(22), M(23),
  M(24), M(25), M(26), M(27), M(28), M(29), M(30), M(31),
  M(32)
}; // (add more for 64 bits)
#undef M
r = (x * multipliers[b]) / divisors[b];
The following variation is not portable, but on architectures that employ an arithmetic right-shift, maintaining the sign, it should be fast.
const int s = -b; // OR:  sizeof(x) * CHAR_BIT - b;
r = (x << s) >> s;

Рэндал Э. Брайант адзначыў, памылка на 3 мая 2005 года ў больш ранняй версіі (што выкарыстоўвалі мультыплікатары [] для дивизоров []), дзе яна не на выпадак х = 1 і B = 1.


Умоўна ўсталяваць або скінуць біт без галінавання

bool f;         // conditional flag
unsigned int m; // the bit mask
unsigned int w; // the word to modify:  if (f) w |= m; else w &= ~m; 

w ^= (-f ^ w) & m;

// OR, for superscalar CPUs:
w = (w & ~m) | (-f & m);

У некаторых архітэктурах, адсутнасць галінавання можа больш чым кампенсаваць тое, што, як уяўляецца, у два разы больш аперацый. Напрыклад, неафіцыйныя выпрабаванні хуткасцю на AMD Athlon ™ XP 2100 + паказала, што яна была на 5-10% хутчэй. Intel Core 2 Duo пабег суперскалярных версіі каля 16% хутчэй, чым першы. Глен Слейден паведаміў мне аб першым выразе на 11 снежня 2003 года. Марка Ю. агульных суперскалярных версія са мной на 3 красавіка 2007 года і папярэдзіў мяне памылку друку 2 дні пазней.


Умоўна адмаўляць значэнне без галінавання

Калі вам трэба адмаўляць толькі тады, калі сцяг няслушна, то выкарыстоўвайце наступны пазбегнуць галінавання:
bool fDontNegate;  // Flag indicating we should not negate v.
int v;             // Input value to negate if fDontNegate is false.
int r;             // result = fDontNegate ? v : -v;

r = (fDontNegate ^ (fDontNegate - 1)) * v;

Калі вам трэба адмаўляць толькі тады, калі сцяг дакладна, то выкарыстоўвайце гэта:
bool fNegate;  // Flag indicating if we should negate v.
int v;         // Input value to negate if fNegate is true.
int r;         // result = fNegate ? -v : v;

r = (v ^ -fNegate) + fNegate;
Абрагам Plotnitzky прапанаваў мне дадаць першая версія 2 чэрвеня 2009 года. Матываваны, каб пазбегнуць множцеся, я прыйшоў з другой версіі на 8 чэрвеня 2009 года. Альфонса дэ Грэгары адзначыў, што некаторыя круглыя дужкі зніклі без вестак 26 лістапада 2009 года, і атрымаў памылку шчодрасці.


Зліццё біты з двух значэнняў у адпаведнасці з маскай

unsigned int a;    // value to merge in non-masked bits
unsigned int b;    // value to merge in masked bits
unsigned int mask; // 1 where bits from b should be selected; 0 where from a.
unsigned int r;    // result of (a & ~mask) | (b & mask) goes here

r = a ^ ((a ^ b) & mask); 
Гэта голіцца адной аперацыі з відавочны спосаб аб'яднання двух набораў бітаў у адпаведнасці з бітавай маскай. Калі маска стала, то не можа быць ніякага перавагі.

Рон Джэфры паслаў мне гэта на 9 лютага 2006 года.


Падлік бітаў (наіўна)

unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v

for (c = 0; v; v >>= 1)
{
  c += v & 1;
}
Наіўны падыход патрабуе адну ітэрацыя на біт, пакуль не больш біты. Так на 32-разраднае слова, толькі з высока пастаўлены, ён будзе ісці да 32 ітэрацый.


Падлік біт устаноўленых табліцу

static const unsigned char BitsSetTable256[256] = 
{
#   define B2(n) n,     n+1,     n+1,     n+2
#   define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#   define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
    B6(0), B6(1), B6(1), B6(2)
};

unsigned int v; // count the number of bits set in 32-bit value v
unsigned int c; // c is the total bits set in v

// Option 1:
c = BitsSetTable256[v & 0xff] + 
    BitsSetTable256[(v >> 8) & 0xff] + 
    BitsSetTable256[(v >> 16) & 0xff] + 
    BitsSetTable256[v >> 24]; 

// Option 2:
unsigned char * p = (unsigned char *) &v;

c = BitsSetTable256[p[0]] + 
    BitsSetTable256[p[1]] + 
    BitsSetTable256[p[2]] +	
    BitsSetTable256[p[3]];


// Каб спачатку генерыраваць табліцы алгарытмічных:
BitsSetTable256[0] = 0;
for (int i = 0; i < 256; i++)
{
  BitsSetTable256[i] = (i & 1) + BitsSetTable256[i / 2];
}

На 14 ліпеня 2009 г Hallvard Фурусет прапанаваў макрас ушчыльненай табліцы.


Падлік бітаў, Керниган Браян у шляху

unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
  v &= v - 1; // clear the least significant bit set
}
Метад Браян Керниган ідзе праз столькі ітэрацый як Ёсць мноства бітаў. Так што калі ў нас ёсць 32-разраднае слова, толькі з устаноўленым старэйшым бітам, то яна будзе ісці толькі адзін раз праз завесу.

Апублікавана ў 1988 годзе, другі C Мова праграмавання рэд. (Браян У. Керниган і Дэніс М. Рытчы) згадвае пра гэта ў парадку 02/09. На 19 красавіка 2006 г. Дон Кнут паказаў мне, што гэты метад "быў упершыню апублікаваны ў Піцер Вегнер ЦАОР 3 (1960), 322. (Таксама выяўлена незалежна Дэрык Лемера і апублікаваны ў 1964 годзе кніга пад рэдакцыяй Беккенбах.)"


Падлік бітаў, устаноўленых у 14, 24, або 32-разрадных слоў, выкарыстоўваючы 64-разрадныя інструкцыі

unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v

// option 1, for at most 14-bit values in v:
c = (v * 0x200040008001ULL & 0x111111111111111ULL) % 0xf;

// option 2, for at most 24-bit values in v:
c =  ((v & 0xfff) * 0x1001001001001ULL & 0x84210842108421ULL) % 0x1f;
c += (((v & 0xfff000) >> 12) * 0x1001001001001ULL & 0x84210842108421ULL) 
     % 0x1f;

// option 3, for at most 32-bit values in v:
c =  ((v & 0xfff) * 0x1001001001001ULL & 0x84210842108421ULL) % 0x1f;
c += (((v & 0xfff000) >> 12) * 0x1001001001001ULL & 0x84210842108421ULL) % 
     0x1f;
c += ((v >> 24) * 0x1001001001001ULL & 0x84210842108421ULL) % 0x1f;

Гэты метад патрабуе 64-бітны працэсар з хуткім модулем падзелу каб быць эфектыўным. Першы варыянт займае ўсяго 3 аперацыі, другі варыянт займае 10; і трэці варыянт займае 15.

Багатыя Schroeppel створана 9-разрадны версія, падобна на варыянт 1, гл. раздзел хакі Праграмаванне Билер, М., Госпер, RW, і Schroeppel, Р. HAKMEM. MIT AI Memo 239, 29 лютага 1972. Яго метад быў натхненнем для варыянтаў вышэй, распрацаваны Шон Андэрсан. Рэндал Э. Брайант прапанаваных выпраўленняў пара памылка 3 мая 2005 года. Брус Доусон аптымальнай тое, што было 12-разрадную версію і зрабілі яго прыдатным для 14 біт з выкарыстаннем тых жа лік аперацый на 1 Feburary 2007 года.


Падлік бітаў, паралельна

unsigned int v; // count bits set in this (32-bit value)
unsigned int c; // store the total here
static const int S[] = {1, 2, 4, 8, 16}; // Magic Binary Numbers
static const int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF};

c = v - ((v >> 1) & B[0]);
c = ((c >> S[1]) & B[1]) + (c & B[1]);
c = ((c >> S[2]) + c) & B[2];
c = ((c >> S[3]) + c) & B[3];
c = ((c >> S[4]) + c) & B[4];

Масіва B, выяўленая ў выглядзе двайковых, з'яўляецца:
B[0] = 0x55555555 = 01010101 01010101 01010101 01010101
B[1] = 0x33333333 = 00110011 00110011 00110011 00110011
B[2] = 0x0F0F0F0F = 00001111 00001111 00001111 00001111
B[3] = 0x00FF00FF = 00000000 11111111 00000000 11111111
B[4] = 0x0000FFFF = 00000000 00000000 11111111 11111111
Мы можам адрэгуляваць метад для павелічэння памераў цэлага, працягваючы з мадэляў для двайковых Magic Numbers, У і С. Калі Ёсць K біт, то мы павінны масівы S і B для столі (LG (K)) элементы доўга, і мы павінны вылічыць столькі ж выразы для З, S або B доўгія. Для V 32-біт, 16 аперацый выкарыстоўваюцца.

Лепшы метад для падліку бітаў у 32-разраднае цэлы лік V заключаецца ў наступным:

v = v - ((v >> 1) & 0x55555555);                    // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);     // temp
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count

Лепшы біт метадам рахунку займае ўсяго 12 аперацый, якія так жа, як метад пошуку сталом, але пазбягае памяці і патэнцыйных прамашкі з табліцы. Гэта гібрыд паміж чыста паралельнага метаду вышэй, і раней метадаў, якія выкарыстоўваюць памнажае (у раздзеле аб падліку біт з 64-разрадныя інструкцыі), хоць ён не выкарыстоўвае 64-разрадныя інструкцыі. Пунктам біты ў байты ажыццяўляецца паралельна, а сума бітаў у байтах вылічаецца шляхам множання 0x1010101 і пераход права 24 біта.

Абагульненне лепшых трохі метад падліку на цэлых бітавай шырыні да 128 (параметризованные тыпу Т) заключаецца ў наступным:

v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT; // count

Глядзіце прыемна навін Ян Эшдаун паведамленне для атрымання дадатковай інфармацыі на падліку колькасці бітаў (таксама вядомы як бокам дадатак). Лепшы біт метад падліку было даведзена да майго звесткі 5 кастрычнік 2005 Эндру Шапіра , ён знайшоў яго ў 187-188 старонак з праграмнага забеспячэння Кіраўніцтва па аптымізацыі для працэсараў AMD Athlon ™ 64 і Opteron ™ Працэсары . Чарлі Гордан прапанаваў спосаб згаліць адну аперацыю з чыста паралельнай версіі 14 снежня 2005 года, і Дон Клагстон падстрыжаныя яшчэ тры ад яе на 30 снежня 2005 года. Я зрабіў памылку друку з прапановай Доне аб тым, што Эрык Коўл плямісты 8 студзеня 2006 г.. Эрык пазней прапанаваў адвольныя абагульнення бітавай шырыні лепшы метад 17 лістапада 2006 г. 5 красавіка 2007 Аль Уільямс адзначыў, што я лінія мёртвага кода ў верхняй частцы першага метаду.


Граф біты (ранг) з найбольш значных біт да зададзенай пазіцыі

Наступныя знаходзіць ранг біт, гэта значыць ён вяртае суму біты, устаноўленыя да 1 з найбольш signficant трохі downto біт на дадзенай пазіцыі.
  uint64_t v;       // Compute the rank (bits set) in v from the MSB to pos.
  unsigned int pos; // Bit position to count bits upto.
  uint64_t r;       // Resulting rank of bit at pos goes here.

  // Shift out bits after given position.
  r = v >> (sizeof(v) * CHAR_BIT - pos);
  // Count set bits in parallel.
  // r = (r & 0x5555...) + ((r >> 1) & 0x5555...);
  r = r - ((r >> 1) & ~0UL/3);
  // r = (r & 0x3333...) + ((r >> 2) & 0x3333...);
  r = (r & ~0UL/5) + ((r >> 2) & ~0UL/5);
  // r = (r & 0x0f0f...) + ((r >> 4) & 0x0f0f...);
  r = (r + (r >> 4)) & ~0UL/17;
  // r = r % 255;
  r = (r * (~0UL/255)) >> ((sizeof(v) - 1) * CHAR_BIT);

Юха Ярви паслаў мне гэта 21 лістапада 2009 г. як зваротная аперацыя па вылічальнай трохі становішча дадзенага рангу, які наступным чынам.


Выберыце трохі пазіцыя (з найбольш значных біт) з зададзеным кол (ранг)

Наступныя-бітнага кода 64 выбірае пазіцыю г-м 1 біт пры падліку з левага боку. Іншымі словамі, калі мы пачынаем у самы старэйшы біт і прыступіць да правай, лічачы колькасць біт усталяваны ў 1 пакуль мы не дасягнем жаданага рангу г, тое месца, дзе мы спыняемся вяртаецца. Калі ранг прасіў перавышае колькасць бітаў, то 64 вяртаецца. Код можа быць зменены для 32-бітнай або лічачы з правай.
  uint64_t v;          // Input value to find position with rank r.
  unsigned int r;      // Input: bit's desired rank [1-64].
  unsigned int s;      // Output: Resulting position of bit with rank r [1-64]
  uint64_t a, b, c, d; // Intermediate temporaries for bit count.
  unsigned int t;      // Bit count temporary.

  / / У нармальных кол бітны паралельны для 64-бітнае цэлае,
 / / але захоўваць усе прамежкавыя крокі.                                        
  // a = (v & 0x5555...) + ((v >> 1) & 0x5555...);
  a =  v - ((v >> 1) & ~0UL/3);
  // b = (a & 0x3333...) + ((a >> 2) & 0x3333...);
  b = (a & ~0UL/5) + ((a >> 2) & ~0UL/5);
  // c = (b & 0x0f0f...) + ((b >> 4) & 0x0f0f...);
  c = (b + (b >> 4)) & ~0UL/0x11;
  // d = (c & 0x00ff...) + ((c >> 8) & 0x00ff...);
  d = (c + (c >> 8)) & ~0UL/0x101;
  t = (d >> 32) + (d >> 48);
  // Now do branchless select!                                                
  s  = 64;
  // if (r > t) {s -= 32; r -= t;}
  s -= ((t - r) & 256) >> 3; r -= (t & ((t - r) >> 8));
  t  = (d >> (s - 16)) & 0xff;
  // if (r > t) {s -= 16; r -= t;}
  s -= ((t - r) & 256) >> 4; r -= (t & ((t - r) >> 8));
  t  = (c >> (s - 8)) & 0xf;
  // if (r > t) {s -= 8; r -= t;}
  s -= ((t - r) & 256) >> 5; r -= (t & ((t - r) >> 8));
  t  = (b >> (s - 4)) & 0x7;
  // if (r > t) {s -= 4; r -= t;}
  s -= ((t - r) & 256) >> 6; r -= (t & ((t - r) >> 8));
  t  = (a >> (s - 2)) & 0x3;
  // if (r > t) {s -= 2; r -= t;}
  s -= ((t - r) & 256) >> 7; r -= (t & ((t - r) >> 8));
  t  = (v >> (s - 1)) & 0x1;
  // if (r > t) s--;
  s -= ((t - r) & 256) >> 8;
  s = 65 - s;

Калі галінаванне хутка на вашай мэтавай працэсар, лічаць раскаментаваць калі-заяў і каментароў лініі, якія ідуць за імі.

Юха Ярви паслаў мне гэта 21 лістапада 2009 года.


Вылічальны парытэту наіўным спосабам

unsigned int v;       // word value to compute the parity of
bool parity = false;  // parity will be the parity of v

while (v)
{
  parity = !parity;
  v = v & (v - 1);
}


Прыведзены вышэй код выкарыстоўвае падыход, як трохі падліку Браян Kernigan, і перш. Час, неабходнае прапарцыйнае колькасць бітаў.


Вылічыць парытэту табліцу

static const bool ParityTable256[256] = 
{
#   define P2(n) n, n^1, n^1, n
#   define P4(n) P2(n), P2(n^1), P2(n^1), P2(n)
#   define P6(n) P4(n), P4(n^1), P4(n^1), P4(n)
    P6(0), P6(1), P6(1), P6(0)
};

unsigned char b;  // byte value to compute the parity of
bool parity = ParityTable256[b];

// OR, for 32-bit words:
unsigned int v;
v ^= v >> 16;
v ^= v >> 8;
bool parity = ParityTable256[v & 0xff];

// Variation:
unsigned char * p = (unsigned char *) &v;

parity = ParityTable256[p[0] ^ p[1] ^ p[2] ^ p[3]];

Рэндал Э. Брайант заклікаў даданне (праўда) відавочна Апошняе змяненне з зменнай р ад 3 мая 2005 года. Брус Ролс выявілі памылку друку ў асобнік назва табліцы зменных ад 27 верасня 2005 года, і ён атрымаў $ 10 памылка шчодрасці. 9 кастрычніка 2006 г., Фабрыцыо Беллард прапанаваў 32-разрадных варыяцыі вышэй, якія патрабуюць толькі адзін пошук у табліцы; папярэдняй версіі было чатыры пошуку (па адным на б) і былі павольней. На 14 ліпеня 2009 г Hallvard Фурусет прапанаваў макрас ушчыльненай табліцы.


Вылічыць суадносіны байт выкарыстоўваецца 64-разрадны размнажацца і модуль падзелу

unsigned char b;  // byte value to compute the parity of
bool parity = 
  (((b * 0x0101010101010101ULL) & 0x8040201008040201ULL) % 0x1FF) & 1;

Апісаным вышэй спосабам займае каля 4 аперацыі, але працуе толькі на байт.


Вылічыць суадносіны слова з размнажацца

Наступны метад вылічае суадносіны 32-бітнае значэнне толькі ў 8 аперацый з выкарыстаннем размножвацца.
    unsigned int v; // 32-bit word
    v ^= v >> 1;
    v ^= v >> 2;
    v = (v & 0x11111111U) * 0x11111111U;
    return (v >> 28) & 1;

Акрамя таго, для 64-біт, 8 аперацый па-ранейшаму дастаткова.
    unsigned long long v; // 64-bit word
    v ^= v >> 1;
    v ^= v >> 2;
    v = (v & 0x1111111111111111UL) * 0x1111111111111111UL;
    return (v >> 60) & 1;

Эндру Шапіра прыйшоў з гэтым і паслаў яго да мне 2 верасня 2007 года.


Вылічыць парытэту ў паралельным

unsigned int v;  // word value to compute the parity of
v ^= v >> 16;
v ^= v >> 8;
v ^= v >> 4;
v &= 0xf;
return (0x6996 >> v) & 1;

Апісаным вышэй спосабам займае каля 9 аперацый, і працуе для 32-разрадных слоў. Гэта можа быць аптымізаваная для працы толькі на байт у 5 аперацый, выдаліўшы два радкі адразу пасля "непадпісаным Int V;". Спачатку метад зрухі і XORs восем грызе з 32-бітнае значэнне разам, пакінуўшы ў выніку нізкага грызці В. Далей, двайковых лікаў 0110 1001 1001 0110 (0x6996 ў шаснаццатковай) зрушваецца направа на значэнне, прадстаўленае у ніжэйшым грызці У. Гэта лік як мініяцюрныя парытэту 16-бітавай табліцы індэксуюцца нізкай чатыры біта ў V. У выніку суадносіны V ў біт 1, які маскіруецца і не вяртаюцца.

Дзякуючы Мэцью Хендри за ўказанне Shift-пошуку ідэя ў канцы 15 снежня 2002 года. Гэта аптымізацыя голіцца дзве аперацыі з выкарыстаннем толькі змены і аперацыі XOR знайсці парытэт.


Замена значэнняў з адніманне і складанне


#define SWAP(a, b) ((&(a) == &(b)) || \
                    (((a) -= (b)), ((b) += (a)), ((a) = (b) - (a))))
Гэта свопы значэння і б без выкарыстання часовай зменнай. Першапачатковая праверка для і б час жа месца ў памяці, можа быць апушчаны, калі вы ведаеце, гэта не можа адбыцца. (Перакладчык можа апусціць яго ў любым выпадку, як аптымізацыя.) Калі вы ўключыце перапаўнення выключэння, а затым перадаць значэнняў без знака так выключэнне не ствараецца. XOR метад, які варта, можа быць крыху хутчэй на некаторых машынах. Не выкарыстоўваць гэта з лікамі з якая плавае кропкай (калі вы працуеце на іх сыравіну прадстаўлення цэлага ліку).

Санджив Sivasankaran прапанаваў мне дадаць гэта 12 чэрвеня 2007 года. Вінцэнт Лефевр адзначыў, патэнцыял для выключэння перапаўнення на 9 ліпеня 2008 года


Замена значэнняў з XOR

#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
Гэта стары трук для абмену значэнняў зменных А і В без выкарыстання дадатковага прасторы для часовых пераменных.

20 Студзень 2005, Иэн Флемінг А. адзначыў, што макрас вышэй не працуе, калі трэба памяняць месцамі з той жа ячэйкі памяці, такіх як SWAP ([я], [J]) з я == J. Так што, калі, якія могуць паўстаць, разгледзець пытанне аб вызначэнні макраса ((() == (б)) | | ((() = (б)), ((B) = ()), (( ) = (B )))). 14 ліпеня 2009 года, Hallvard Фурусет прапанаваў, што на некаторых машынах ((() * (B)) & & ((B) = () = (б), () = (B))) можа быць хутчэй, так як () ^ (б) выраз выкарыстоўваецца паўторна.


Замена асобных бітаў з XOR

unsigned int i, j; // positions of bit sequences to swap
unsigned int n;    // number of consecutive bits in each sequence
unsigned int b;    // bits to swap reside in b
unsigned int r;    // bit-swapped result goes here

unsigned int x = ((b >> i) ^ (b >> j)) & ((1U << n) - 1); // XOR temporary
r = b ^ ((x << i) | (x << j));

Як прыклад замены дыяпазоны біт Няхай мы маем В = 001 0111 1 (выражаны ў двайковай сыстэме), і мы хочам памяняць N = 3 паслядоўных бітаў, пачынаючы з I = 1 (другі біт справа) з 3 паслядоўных бітаў, пачынаючы з J = 5; вынік будзе R = 111 0001 1 (двайковыя).

Гэты метад замены падобны на агульныя мэты XOR падпампоўкі трук, але прызначаны для працы на асобных бітаў. Зменнай х крам выніку аперацыі XOR пар бітныя значэння мы хочам памяняць, а затым біты ўсталёўваюцца ў выніку самі XORed з X. Вядома, вынік не вызначаны, калі паслядоўнасці перакрываюцца.

На 14 ліпеня 2009 Hallvard Фурусет прапанаваў змяніць 1 <<п да 1U <<N, паколькі значэнне ў цяперашні час прызначаныя без знака і, каб пазбегнуць зрушэнні ў біт знака.


Зваротны біт відавочным чынам

unsigned int v;     // input bits to be reversed
unsigned int r = v; // r will be reversed bits of v; first get LSB of v
int s = sizeof(v) * CHAR_BIT - 1; // extra shift needed at end

for (v >>= 1; v; v >>= 1)
{   
  r <<= 1;
  r |= v & 1;
  s--;
}
r <<= s; // shift when v's highest bits are zero

15 кастрычніка 2004 г., Майкл Hoisie адзначыў, памылка ў арыгінальнай версіі. Рэндал Э. Брайант прапанаваў перанесці дадатковыя аперацыі на 3 мая 2005 года. Behdad Esfabod прапанаваў невялікае змяненне, што ліквідаваць адну ітэрацыя цыкла 18 мая 2005 года. Тады, 6 лютага 2007 года, Liyong Чжоу прапанаваў лепшы варыянт, што ў той час як завесы V не роўна 0, так што замест перабірае ўсё біты ён спыняецца рана.


Зваротны біт ў слова табліцу

static const unsigned char BitReverseTable256[256] = 
{
#   define R2(n)     n,     n + 2*64,     n + 1*64,     n + 3*64
#   define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16)
#   define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 )
    R6(0), R6(2), R6(1), R6(3)
};

unsigned int v; // reverse 32-bit value, 8 bits at time
unsigned int c; // c will get v reversed

// Option 1:
c = (BitReverseTable256[v & 0xff] << 24) | 
    (BitReverseTable256[(v >> 8) & 0xff] << 16) | 
    (BitReverseTable256[(v >> 16) & 0xff] << 8) |
    (BitReverseTable256[(v >> 24) & 0xff]);

// Option 2:
unsigned char * p = (unsigned char *) &v;

unsigned char * q = (unsigned char *) &c;
q[3] = BitReverseTable256[p[0]]; 
q[2] = BitReverseTable256[p[1]]; 
q[1] = BitReverseTable256[p[2]]; 
q[0] = BitReverseTable256[p[3]];
Першы спосаб займае каля 17 аперацый, а другі займае каля 12, мяркуецца, што ваш працэсар можа загружаць і захоўваць б лёгка.

На 14 ліпеня 2009 г Hallvard Фурусет прапанаваў макрас ушчыльненай табліцы.


Зваротны біт у байце з 3 аперацыі (64-разрадны размнажацца і модуль дзяленне):

unsigned char b; // reverse this (8-bit) byte
 
b = (b * 0x0202020202ULL & 0x010884422010ULL) % 1023;
Памножым аперацыя стварае пяць асобных копій 8-бітны байт шаблон для разгалінаваная ў 64-бітнае значэнне. Аперацыі і выбірае біты, якія знаходзяцца ў правільным (наадварот) пазіцый па стаўленні сябар да 10-бітнай групы біт. Размнажацца і і аперацый копію біт з арыгінальных б так кожны з іх з'яўляюцца толькі ў адным з 10-бітных набораў. Зваротным пазіцый бітаў з арыгінальнага байт супадаюць з іх адноснага становішча ў рамках любога набору 10-біт. Апошні крок, які ўключае ў сябе модуль дзялення на 2 ^ 10 - 1, мае эфект зліцця разам кожны набор з 10 біт (з пазіцый 0-9, 10-19, 20-29, ...) у 64-бітных значэнне. Яны не перасякаюцца, таму акрамя крокі, якія ляжаць у аснове модуля падзелу паводзяць сябе як або аперацый.

Гэты метад быў аднесці да багатым Schroeppel ў хакі раздзеле Праграмаванне Билер, М., Госпер, RW, і Schroeppel, Р. HAKMEM. MIT AI Memo 239, 29 Люты 1972.


Зваротны біт у байце з 4 аперацыі (64-разрадны размнажацца, няма падзелу):

unsigned char b; // reverse this byte
 
b = ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
Паказвае наступны паток біт значэння з Булева зменнымі a, b, c, d, e, f, g, і h , якія складаюць 8-бітны байт. Звярніце ўвагу, як першая памножыць прыхільнікаў бітаў у некалькі копій, у той час як апошнія памножыць аб'ядноўвае іх у пяты б з правага боку.
                                                                                        abcd efgh (-> hgfe dcba)
*                                                      1000 0000  0010 0000  0000 1000  0000 0010 (0x80200802)
-------------------------------------------------------------------------------------------------
                                            0abc defg  h00a bcde  fgh0 0abc  defg h00a  bcde fgh0
&                                           0000 1000  1000 0100  0100 0010  0010 0001  0001 0000 (0x0884422110)
-------------------------------------------------------------------------------------------------
                                            0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
*                                           0000 0001  0000 0001  0000 0001  0000 0001  0000 0001 (0x0101010101)
-------------------------------------------------------------------------------------------------
                                            0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
                                 0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
                      0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
           0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
-------------------------------------------------------------------------------------------------
0000 d000  h000 dc00  hg00 dcb0  hgf0 dcba  hgfe dcba  hgfe 0cba  0gfe 00ba  00fe 000a  000e 0000
>> 32
-------------------------------------------------------------------------------------------------
                                            0000 d000  h000 dc00  hg00 dcb0  hgf0 dcba  hgfe dcba  
&                                                                                       1111 1111
-------------------------------------------------------------------------------------------------
                                                                                        hgfe dcba
Адзначым, што два апошніх кроку могуць быць аб'яднаны на некаторых працэсарах, паколькі рэгістры могуць быць даступныя як байты, проста памножыць, каб зарэгістравацца крам верхняй 32 біта выніку і прыняць малодшы байт. Такім чынам, гэта можа заняць толькі 6 аперацый.

Распрацавана Шон Андэрсан 13 ліпеня 2001.


Зваротны біт у байце з 7 аперацый (не 64-біт):

b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; 
Пераканайцеся, што вы прызначыць або літой вынік непадпісаным знак для выдалення смецця ў вышэйшых разрадаў. Распрацавана Шон Андэрсан 13 ліпеня 2001. Опечатка плямамі і карэкцыі пастаўляецца Майкам Кіт, 3 студзеня 2002 года.


Зваротны N-разрадныя колькасць паралельна ў 5 * LG (N) аперацый:

unsigned int v; // 32-bit word to reverse bit order

// swap odd and even bits
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
// swap consecutive pairs
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
// swap nibbles ... 
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
// swap bytes
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
// swap 2-byte long pairs
v = ( v >> 16             ) | ( v               << 16);

Наступныя змены таксама O (LG (N)), аднак ён патрабуе больш аперацый зваротнага V. Яго цнота ў прыняцці менш крыху памяці шляхам вылічэння канстанты "на лета".
unsigned int s = sizeof(v) * CHAR_BIT; // bit size; must be power of 2 
unsigned int mask = ~0;         
while ((s >>= 1) > 0) 
{
  mask ^= (mask << s);
  v = ((v >> s) & mask) | ((v << s) & ~mask);
}
Гэтыя метады вышэй, лепш за ўсё падыходзіць для сітуацый, калі N вяліка. Калі вы выкарыстоўваеце вышэй з 64-бітнымі цэлымі (ці больш), то вам неабходна дадаць некалькі радкоў (па ўзоры), у адваротным выпадку толькі 32 біта будзе адмененае, і вынік будзе ў 32 біта.

Глядзіце д-р Dobb's Journal 1983 года, артыкул Эдвін Фрыда па двайковым магічных лікаў для атрымання дадатковай інфармацыі. Другі варыянт быў прапанаваны Кен Рэберн 13 Верасня 2005. Veldmeijer адзначыў, што першы варыянт можа абыйсціся без НСРА ў апошняй радку 19 Сакавік 2006.


Вылічыць модуль дзяленне на 1 <<S без падзелу аператара

const unsigned int n;          // numerator
const unsigned int s;
const unsigned int d = 1U << s; // So d will be one of: 1, 2, 4, 8, 16, 32, ...
unsigned int m;                // m will be n % d
m = n & (d - 1); 
Большасць праграмістаў пазнаць гэты трук рана, але ён быў уключаны для паўнаты карціны.


Вылічыць модуль дзяленне на (1 <<S) - 1 без падзелу аператара

unsigned int n;                      // numerator
const unsigned int s;                // s > 0
const unsigned int d = (1 << s) - 1; // so d is either 1, 3, 7, 15, 31, ...).
unsigned int m;                      // n % d goes here.

for (m = n; n > d; n = m)
{
  for (m = 0; n; n >>= s)
  {
    m += n & d;
  }
}
// Now m is a value from 0 to d, but since with modulus division
// we want m to be 0 when it is d.
m = m == d ? 0 : m;
Гэты метад модуля дзялення на лік, на адзінку менш, чым ступень ліку 2 займае не больш за 5 + (4 + 5 * столлю (N / S)) * столі (LG (N / S)) аперацый, дзе N з'яўляецца колькасць біт у лічніку. Іншымі словамі, яна займае не больш за O (N * LG (N)) часу.

Распрацавана Шон Андэрсан 15 Аўгуста 2001. Перад Шон А. Ірвайн паправіў мяне 17 чэрвеня 2004 г. я памылкова заявіў, што мы маглі б альтэрнатыўна прызначыць m = ((m + 1) & d) - 1; ў канцы. Майкл Мілер выявіў памылку друку ў кодзе 25 красавіка 2005 года.


Вылічыць модуль дзяленне на (1 <<S) - 1 паралельна, без падзелу аператара


// The following is for a word size of 32 bits!

static const unsigned int M[] = 
{
  0x00000000, 0x55555555, 0x33333333, 0xc71c71c7,  
  0x0f0f0f0f, 0xc1f07c1f, 0x3f03f03f, 0xf01fc07f, 
  0x00ff00ff, 0x07fc01ff, 0x3ff003ff, 0xffc007ff,
  0xff000fff, 0xfc001fff, 0xf0003fff, 0xc0007fff,
  0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 
  0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
  0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
  0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff
};

static const unsigned int Q[][6] = 
{
  { 0,  0,  0,  0,  0,  0}, {16,  8,  4,  2,  1,  1}, {16,  8,  4,  2,  2,  2},
  {15,  6,  3,  3,  3,  3}, {16,  8,  4,  4,  4,  4}, {15,  5,  5,  5,  5,  5},
  {12,  6,  6,  6 , 6,  6}, {14,  7,  7,  7,  7,  7}, {16,  8,  8,  8,  8,  8},
  { 9,  9,  9,  9,  9,  9}, {10, 10, 10, 10, 10, 10}, {11, 11, 11, 11, 11, 11},
  {12, 12, 12, 12, 12, 12}, {13, 13, 13, 13, 13, 13}, {14, 14, 14, 14, 14, 14},
  {15, 15, 15, 15, 15, 15}, {16, 16, 16, 16, 16, 16}, {17, 17, 17, 17, 17, 17},
  {18, 18, 18, 18, 18, 18}, {19, 19, 19, 19, 19, 19}, {20, 20, 20, 20, 20, 20},
  {21, 21, 21, 21, 21, 21}, {22, 22, 22, 22, 22, 22}, {23, 23, 23, 23, 23, 23},
  {24, 24, 24, 24, 24, 24}, {25, 25, 25, 25, 25, 25}, {26, 26, 26, 26, 26, 26},
  {27, 27, 27, 27, 27, 27}, {28, 28, 28, 28, 28, 28}, {29, 29, 29, 29, 29, 29},
  {30, 30, 30, 30, 30, 30}, {31, 31, 31, 31, 31, 31}
};

static const unsigned int R[][6] = 
{
  {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
  {0x0000ffff, 0x000000ff, 0x0000000f, 0x00000003, 0x00000001, 0x00000001},
  {0x0000ffff, 0x000000ff, 0x0000000f, 0x00000003, 0x00000003, 0x00000003},
  {0x00007fff, 0x0000003f, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
  {0x0000ffff, 0x000000ff, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f},
  {0x00007fff, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f},
  {0x00000fff, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f},
  {0x00003fff, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f},
  {0x0000ffff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff},
  {0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff}, 
  {0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff}, 
  {0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff}, 
  {0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff}, 
  {0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff}, 
  {0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff}, 
  {0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff}, 
  {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}, 
  {0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff}, 
  {0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff}, 
  {0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff},
  {0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff}, 
  {0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff}, 
  {0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff}, 
  {0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff}, 
  {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff},
  {0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}, 
  {0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}, 
  {0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff},
  {0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff},
  {0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff}, 
  {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff}, 
  {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}
};

unsigned int n;       // numerator
const unsigned int s; // s > 0
const unsigned int d = (1 << s) - 1; // so d is either 1, 3, 7, 15, 31, ...).
unsigned int m;       // n % d goes here.

m = (n & M[s]) + ((n >> s) & M[s]);

for (const unsigned int * q = &Q[s][0], * r = &R[s][0]; m > d; q++, r++)
{
  m = (m >> *q) + (m & *r);
}
m = m == d ? 0 : m; // OR, less portably: m = m & -((signed)(m - d) >> s);

Гэты метад знаходжання модуля дзялення на лік, на адзінку менш ступені 2 прымае не больш O (LG (N)) часу, дзе N гэты лік біт у лічніку (32 біт, на код вышэй). Колькасць аперацый не перавышае 12 + 9 * столі (LG (N)). Табліцы могуць быць выдаленыя, калі вы ведаеце, назоўнік падчас кампіляцыі, проста атрымаць некалькі адпаведных запісаў і разгарнуць цыкл. Гэта можа быць лёгка пашырана больш біт.

Ён лічыць, вынік сумавання значэнняў ў базе (1 <<S) паралельна. Першая любы іншы базы (1 <<S) значэнне дадаецца да папярэдняга. Уявіце сабе, што вынік запісваецца на лістку паперы. Выразаць паперы напалову, так што палова значэння на кожным выразаць кавалак. Выраўнаваць каштоўнасці і сумы іх на новы аркуш паперы. Паўтарыце за кошт скарачэння працы ў палове (якая будзе чвэрць памеру папярэдняга) і сумуючы, пакуль вы не можаце выразаць далей. Пасля выканання LG (N/s/2) парэзы, мы абсякаць не больш, проста працягваем дадаваць значэння і змясціць вынік на новы аркуш паперы як і раней, у той час як Ёсць па крайняй меры два S-разрадныя значэння.

Распрацавана Шон Андэрсан 20 жніўні 2001. Опечатка была заўважаная Рэндзі Э. Брайант 3 мая 2005 года (пасля ўстаўкі кода, я пазней дадаў: "unsinged" для аб'явы зменных). Як і ў папярэднім секчы, я памылкова заявіў, што мы маглі б альтэрнатыўна прызначыць m = ((m + 1) & d) - 1; ў канцы, і Дон Кнут паправіў мяне 19 Красавік 2006 года і прапанаваў m = m & -((signed)(m - d) >> s) . На 18 чэрвень 2009 г. Шон Ірвайн прапанаваных змен, якія выкарыстоўвалі ((n >> s) & M[s]) замест ((n & ~M[s]) >> s) , якая звычайна патрабуе менш аперацый, паколькі M [S] пастаянная ужо загружаны.


Знайсці часопіса базы 2 з цэлага з MSB Н ўсталяваць у O (N) аперацый (відавочным чынам)

unsigned int v; // 32-bit word to find the log base 2 of
unsigned r = 0; // r will be lg(v)

while (v >>= 1) // unroll for more speed...
{
  r++;
}
Уваход падставы 2 ад цэлага такі ж, як становішча высокае біт (ці найбольш значных біт, MSB). Наступныя базы часопіса 2 метаду хутчэй, чым гэты.


Знайсці часопіса базы цэлых 2 з цэлага з-бітны IEEE 64 паплаўка

int v; // 32-bit integer to find the log base 2 of
int r; // result of log_2(v) goes here
union { unsigned int u[2]; double d; } t; // temp

t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] = 0x43300000;
t.u[__FLOAT_WORD_ORDER!=LITTLE_ENDIAN] = v;
t.d -= 4503599627370496.0;
r = (t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] >> 20) - 0x3FF;
Гэты код загружае 64-біт (IEEE-754 з якая плавае кропкай) з падвойным-разраднае цэлы лік 32 (без якіх-небудзь paddding біт), захоўваючы лік у мантиссы у той час як паказчык устаноўлены на 2 52. З гэтай Новаспечаныя двухместных, 2 52 (у выглядзе двайны) адымаецца, які ўсталёўвае ў выніку паказчык у часопіс падставы 2 ад уваходнага значэння, В. Усё, што засталося ссоўваецца паказчык біт у пазіцыі (20 біт справа) і аднімання зрушэння, 0x3ff (што 1023 у дзесятковай сістэме). Гэтая методыка займае ўсяго 5 аперацый, але многія працэсары павольна маніпулявання падвойваецца, і прытрымлівання байтаў ў архітэктуры павінны быць улічаныя.

Эрык Коўл паслаў мне гэта 15 студзеня 2006 года. Эван Фелікс адзначыў памылку друку 4 красавіка 2006 г. Вінцэнт Лефевр сказаў мне, 9 ліпеня 2008 года па змене парадку байтаў праверыць выкарыстоўваць байтаў паплаўка, які можа адрознівацца ад парадку байтаў у цэлае.


Знайсці часопіса базы 2 з цэлага з табліцай пошуку

static const char LogTable256[256] = 
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
    -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
    LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};

unsigned int v; // 32-bit word to find the log of
unsigned r;     // r will be lg(v)
register unsigned int t, tt; // temporaries

if (tt = v >> 16)
{
  r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else 
{
  r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}

Табліцу метаду займае ўсяго каля 7 аперацый, каб знайсці часопіс 32-бітнае значэнне. Калі падоўжаны на 64-бітныя велічыні, гэта зойме прыкладна 9 аперацый. Іншая аперацыя можа быць зрэзаная з дапамогай чатырох табліц, з магчымымі дапаўненнямі ўключаны ў кожнай. Выкарыстаньне Int элементаў табліцы можа быць хутчэй, у залежнасці ад вашай архітэктуры.

Код вышэй настроены на раўнамерна размеркаваных значэнняў выхадны. Калі ваш уклад раўнамерна размеркаваны па ўсіх 32-бітныя значэння, а затым разгледзець пытанне аб выкарыстанні наступнае:

if (tt = v >> 24) 
{
  r = 24 + LogTable256[tt];
} 
else if (tt = v >> 16) 
{
  r = 16 + LogTable256[tt];
} 
else if (tt = v >> 8) 
{
  r = 8 + LogTable256[tt];
} 
else 
{
  r = LogTable256[v];
}

Каб спачатку генерыраваць табліцы часопіса алгарытмічных:
LogTable256[0] = LogTable256[1] = 0;
for (int i = 2; i < 256; i++) 
{
  LogTable256[i] = 1 + LogTable256[i / 2];
}
LogTable256[0] = -1; // if you want log(0) to return -1
Behdad Esfahbod і я згаліў доля аперацый (у сярэднім) 18 мая 2005 года. Яшчэ адна частка аперацыі была выдаленая 14 лістападзе 2006 года Эмануіл Хоогевеен. Варыянт, які наладжаны, каб раўнамерна размеркаваных значэнняў ўваходных было прапанавана Дэвід А. Баттэрфілда 19 верасня 2008 г.. Venkat Редди сказаў мне, 5 студзеня 2009 года, што часопіс (0) павінна вяртаць -1, каб паказаць памылку, таму я замяніў першая запіс у табліцы да гэтага.

Find the log base 2 of an N-bit integer in O(lg(N)) operations

unsigned int v;  // 32-bit value to find the log2 of 
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const unsigned int S[] = {1, 2, 4, 8, 16};
int i;

register unsigned int r = 0; // result of log2(v) will go here
for (i = 4; i >= 0; i--) // unroll for speed...
{
  if (v & b[i])
  {
    v >>= S[i];
    r |= S[i];
  } 
}


// OR (IF YOUR CPU BRANCHES SLOWLY):

unsigned int v;	         // 32-bit value to find the log2 of 
register unsigned int r; // result of log2(v) will go here
register unsigned int shift;

r =     (v > 0xFFFF) << 4; v >>= r;
shift = (v > 0xFF  ) << 3; v >>= shift; r |= shift;
shift = (v > 0xF   ) << 2; v >>= shift; r |= shift;
shift = (v > 0x3   ) << 1; v >>= shift; r |= shift;
                                        r |= (v >> 1);


// OR (IF YOU KNOW v IS A POWER OF 2):

unsigned int v;  // 32-bit value to find the log2 of 
static const unsigned int b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 
                                 0xFF00FF00, 0xFFFF0000};
register unsigned int r = (v & b[0]) != 0;
for (i = 4; i > 0; i--) // unroll for speed...
{
  r |= ((v & b[i]) != 0) << i;
}

Вядома, каб пашырыць код, каб знайсці часопіс 33 - нумар на 64-біт, мы хацелі б дадаць яшчэ адзін элемент, 0xFFFFFFFF00000000, У, дадаць 32 да S, і петлі ад 5 да 0. Гэты метад значна павольней, чым раней табліцы-пошуку версіі, але калі вы не хочаце, вялікі стол або вашай архітэктуры павольны доступ да памяці, гэта добры выбар. Другі варыянт уключае ў сябе некалькі больш аперацый, але гэта можа быць хутчэй на машынах з высокай коштам галіны (напрыклад, PowerPC).

Другі варыянт быў накіраваны на мяне Эрык Коўл 7 студзеня 2006. Эндру Шапіра пасля падстрыжаныя некалькі аперацый пакінуць яго і даслаў мне свой варыянт (гл. вышэй) 1 верасня 2007 года. Трэці варыянт быў прапанаваны мне Джон Оуэнс 24 красавіка 2002; гэта хутчэй, але гэта падыходзіць толькі, калі ўваход, як вядома, сіла 2. 25 Май 2003 года, Кен Рэберн прапанаваў паляпшэння агульным выпадку, выкарыстоўваючы меншае лік для B [], якія загружаюцца хутчэй на некаторых архітэктур (напрыклад, калі памер словы складае 16 біта, то толькі адзін нагрузкі інструкцыі могуць быць неабходныя). Гэтыя значэння працы на агульную версію, але не для спецыяльнага выпадку версія ніжэй, дзе V з'яўляецца ступенню 2; Глен Слейден прынёс гэты недагляд мая ўвага на 12 снежня 2003 года.


Find the log base 2 of an N-bit integer in O(lg(N)) operations with multiply and lookup

uint32_t v; // find the log base 2 of 32-bit v
int r;      // result goes here

static const int MultiplyDeBruijnBitPosition[32] = 
{
  0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
  8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};

v |= v >> 1; // first round down to one less than a power of 2 
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;

r = MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];

Прыведзены вышэй код вылічае часопіса базы 2 з 32-бітнай цэлага са столікам пошуку і размнажацца. Ён патрабуе усяго 13 аперацый, у параўнанні з (да) 20 для папярэдняга метаду. Чыста таблічных метад патрабуе найменшую колькасць аперацый, але гэта прапаноўвае разумны кампраміс паміж памерамі стала і хуткасцю.

Калі вы ведаеце, што V з'яўляецца ступенню 2, то вам неабходна наступнае:

static const int MultiplyDeBruijnBitPosition2[32] = 
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r = MultiplyDeBruijnBitPosition2[(uint32_t)(v * 0x077CB531U) >> 27];

Эрык Коўл распрацаваў гэтым 8 Студзень 2006 пасля чытання аб уступленні ніжэй, каб акругліць да ступені 2 і метад ніжэй для вылічэння ліку нулявыя біты з размнажацца і пошуку з дапамогай паслядоўнасці DeBruijn. 10 сьнежня 2009, Марк Дзікінсана згаліў пару аперацый, патрабуючы V акругляецца да адной менш чым на наступны ступень ліку 2, а не ступень 2.


Знайсці цэлага часопіса базы 10 з цэлага

unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of 
int r;          // result goes here
int t;          // temporary

static unsigned int const PowersOf10[] = 
    {1, 10, 100, 1000, 10000, 100000,
     1000000, 10000000, 100000000, 1000000000};

t = (IntegerLogBase2(v) + 1) * 1233 >> 12; // (use a lg2 method from above)
r = t - (v < PowersOf10[t]);
Базы цэлага часопіса 10 вылічаецца першым выкарыстаннем аднаго з метадаў вышэй для знаходжання часопіса базы 2. Па адносіны часопіса 10 (V) = часопіса 2 (V) / часопіс 2 (10), мы павінны памножыць яго на 1/log 2 (10), што прыкладна на 1233/4096 або 1233 наступным правам зрух 12. Даданне аднаго неабходная таму, што IntegerLogBase2 раундаў ўніз. Нарэшце, так як велічыня Т з'яўляецца толькі набліжэннем, якія могуць быць з адным, дакладнае значэнне знаходзіцца шляхам адымання выніку V <PowersOf10 [T].

Гэты метад займае 6 больш аперацый, чым IntegerLogBase2. Гэта можа быць скарочана (на машынах з хуткім доступам да памяці), змяніўшы часопіса базы 2 арт-метад пошуку вышэй, так што запісы правесці тое, што вылічаецца для Т (т. е. папярэдне дадаць,-mulitply, і зрух). Гэта запатрабуе ў агульнай складанасці усяго 9 аперацый, каб знайсці часопіс з падставай 10, мяркуючы, 4 табліцы былі выкарыстаныя (па адным на кожны байт V).

Эрык Коўл прапанаваў мне дадаць версію гэтага 7 студзеня 2006.


Знайсці цэлага часопіса базы 10 з цэлага відавочным чынам

unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of 
int r;          // result goes here

r = (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 : 
    (v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 : 
    (v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;

Гэты метад добра працуе, калі ўваход раўнамерна размеркаваны па 32-бітныя значэння, паколькі 76% з уваходаў злоўлены першыя параўнання, 21% злавілі другога параўнання, 2%, трапляюць у трэці, і так далей (драбненне астатнія ўніз на 90% з кожнага параўнання). У выніку, менш чым у 2,6 аперацыі неабходна ў сярэднім.

18 красавіка 2007 г., Эмануэль Хоогевеен прапанаваў варыяцыі на гэтую, дзе ўмовы, якія выкарыстоўваюцца падраздзяленнямі, якія былі не так хутка, як простае параўнанне.


Знайсці цэлага часопіса базы 2 з-бітны IEEE 32 паплаўка

const float v; // find int(log2(v)), where v > 0.0 && finite(v) && isnormal(v)
int c;         // 32-bit int c gets the result;

c = *(const int *) &v;  // OR, for portability:  memcpy(&c, &v, sizeof c);
c = (c >> 23) - 127;

Вышэй, хутка, але IEEE 754-сумяшчальных архітэктур выкарыстоўваць субнормальная (таксама званы denormal) лікаў з плаваючай кропкай. Яны маюць паказчык біты ўстаноўлены ў нуль (якое азначае ваеннапалонных (2, -127)), і мантисса не нармаваны, таму яна змяшчае нулёў і, такім чынам log2 павінны быць вылічаныя з мантиссы. Для размяшчэння для субнормальных нумары, выкарыстоўвайце наступнае:
const float v;              // find int(log2(v)), where v > 0.0 && finite(v)
int c;                      // 32-bit int c gets the result;
int x = *(const int *) &v;  // OR, for portability:  memcpy(&x, &v, sizeof x);

c = x >> 23;          

if (c)
{
  c -= 127;
}
else
{ // subnormal, so recompute using mantissa: c = intlog2(x) - 149;
  register unsigned int t; // temporary
  // Note that LogTable256 was defined earlier

  if (t = x >> 16)
  {
    c = LogTable256[t] - 133;
  }
  else
  {
    c = (t = x >> 8) ? LogTable256[t] - 141 : LogTable256[x] - 149;
  }
}
20 чэрвеня 2004 г., Шон А. Ірвін прапанаваў мне ўключаць код для апрацоўкі субнормальных нумары. 11 Чэрвень 2005 г., Фальк Hüffner адзначыў, што ISO C99 06/05 / 7 названага нявызначаны паводзіны для агульнага тыпу каламбурный * ідыёмы (Int *) і, хоць яна працавала на 99,9% кампілятары C. Ён прапанаваў выкарыстоўваць тетсру для максімальнай мабільнасці або саюз з паплаўком і Int для паляпшэння генерацыі кода, чым тетсру на некаторыя кампілятарамі.


Знайсці цэлага часопіса базы 2 з ваеннапалонных (2, R)-корань 32-разрадных IEEE з якая плавае кропкай (для цэлага ліку без знака R)

const int r;
const float v; // find int(log2(pow((double) v, 1. / pow(2, r)))), 
               // where isnormal(v) and v > 0
int c;         // 32-bit int c gets the result;

c = *(const int *) &v;  // OR, for portability:  memcpy(&c, &v, sizeof c);
c = ((((c - 0x3f800000) >> r) + 0x3f800000) >> 23) - 127;
Такім чынам, калі г 0, напрыклад, у нас ёсць з = Int (log2 ((двайны) V)). Калі г роўна 1, то мы маем з = Int (log2 (SQRT ((двайны) V))). Калі г = 2, то мы маем з = Int (log2 (ПР ((двайны) V, 1. / 4))).

11 Чэрвень 2005 г., Фальк Hüffner адзначыў, што ISO C99 06/05 / 7 левы тып каламбурный * ідыёмы (Int *) і нявызначаным, і ён прапанаваў выкарыстаць тетсру.


Граф паслядоўных нулявых бітаў (задні) на права лінейна


unsigned int v;  // input to count trailing zero bits
int c;  // output: c will count v's trailing zero bits,
        // so if v is 1101000 (base 2), then c will be 3
if (v)
{
  v = (v ^ (v - 1)) >> 1;  // Set v's trailing 0s to 1s and zero rest
  for (c = 0; v; c++)
  {
    v >>= 1;
  }
}
else
{
  c = CHAR_BIT * sizeof(v);
}
Сярэдняя колькасць завяршальных нулявых бітаў у (раўнамерна размеркаваных) выпадковай двайковай нумар адзін, так што гэта O (канчатковыя нулі) рашэнне не так ужо дрэнна ў параўнанні з больш хуткія метады ніжэй.

Джым Коўл прапанаваў мне дадаць лінейнае час метад падліку канчатковыя нулі на 15 жніўня 2007 года. 22 кастрычніка 2007, Джэйсан Канінг паказаў, што я забыўся ўставіць непадпісаным мадыфікатар для V.


Count the consecutive zero bits (trailing) on the right in parallel


unsigned int v;      // 32-bit word input to count zero bits on right
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -signed(v);
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
Тут мы ў асноўным робім тыя жа аперацыі, як пошук часопіса падставы 2 паралельна, але мы спачатку вылучыць нізкую 1 біт, а затым прыступіць C, пачынаючы з максімальнай і скарачаецца. Колькасць аперацый не перавышае 3 * LG (N) + 4, груба кажучы, для слоў N біт.

Біл Бердзік прапанаваў аптымізацыі, скарачэння часу ад 4 * LG (N) ад 4 лютага 2011 года.


Граф паслядоўных нулявых бітаў (задні) справа на бінарны пошук

unsigned int v;     // 32-bit word input to count zero bits on right
unsigned int c;     // c will be the number of zero bits on the right,
                    // so if v is 1101000 (base 2), then c will be 3
// NOTE: if 0 == v, then c = 31.
if (v & 0x1) 
{
  // special case for odd v (assumed to happen half of the time)
  c = 0;
}
else
{
  c = 1;
  if ((v & 0xffff) == 0) 
  {  
    v >>= 16;  
    c += 16;
  }
  if ((v & 0xff) == 0) 
  {  
    v >>= 8;  
    c += 8;
  }
  if ((v & 0xf) == 0) 
  {  
    v >>= 4;
    c += 4;
  }
  if ((v & 0x3) == 0) 
  {  
    v >>= 2;
    c += 2;
  }
  c -= v & 0x1;
}	
Гэты код падобны на папярэдні метад, але ён вылічае колькасць канчатковыя нулі, назапашваючы C такім чынам, падобна на бінарны пошук. На першым этапе, ён правярае, калі дно 16 біт V роўныя нулю, і калі так, то зрухі V права 16 біт і дадае 16 с, што памяншае колькасць біт у V разгледзець у два разы. Кожная з наступных крокаў умоўнага таксама палоў лік бітаў, пакуль ёсць толькі 1. Гэты метад хутчэй, чым апошні (прыкладна на 33%), так як органы, калі аператары выконваюцца радзей.

Мэт Уитлок прапанаваў гэта 25 студзеня 2006 года. Эндру Шапіра галення пару аперацый з 5 верасня 2007 (шляхам усталёўкі з = 1 і безумоўна аднімання ў канцы).


Граф паслядоўных нулявых бітаў (задні) на права з дапамогай прывядзення да паплаўка

unsigned int v;            // find the number of trailing zeros in v
int r;                     // the result goes here
float f = (float)(v & -v); // cast the least significant bit in v to a float
r = (*(uint32_t *)&f >> 23) - 0x7f;

Хоць гэта толькі займае каля 6 аперацый, час для пераўтварэння цэлага ліку з якая плавае кропкай можа быць высокім на некаторых машынах. Паказчык 32-разрадных IEEE з якая плавае кропкай ссоўваецца ўніз, і зрушэння адымаецца даць становішча малодшых 1 біт у V. Калі V роўная нулю, то вынік -127.


Граф паслядоўных нулявых бітаў (задні) на права з модулем дзялення і пошуку

unsigned int v;  // find the number of trailing zeros in v
int r;           // put the result in r
static const int Mod37BitPosition[] = // map a bit value mod 37 to its position
{
  32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
  7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
  20, 8, 19, 18
};
r = Mod37BitPosition[(-v & v) % 37];
Гэты код знаходзіць лік нулёў, якія на задняй правай, так бінарных 0100 будзе вырабляць 2. Яна выкарыстоўвае той факт, што першыя 32 бітных значэнняў пазіцыю адносна простае з 37, так выкананні модуля падзелу з 37 дае унікальны нумар ад 0 да 36 для кожнага. Гэтыя дадзеныя могуць быць супастаўленыя з колькасцю нулёў з дапамогай невялікага табліцу. Яна выкарыстоўвае толькі 4 аперацыі, аднак індэксаванне ў табліцы і выкананне модуля падзелу могуць зрабіць яго непрыдатным для некаторых сітуацыях. Я прыйшоў з гэтым самастойна, а затым шукалі подпоследовательность табліцу значэнняў, і выявілі, ён быў вынайдзены раней Райзер, у адпаведнасці з Hacker's Delight .


Граф паслядоўных нулявых бітаў (задні) на права з размнажацца і пошуку

unsigned int v;  // find the number of trailing zeros in 32-bit v 
int r;           // result goes here
static const int MultiplyDeBruijnBitPosition[32] = 
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];

Пераўтварэнне трохі вектараў індэксаў набор бітаў напрыклад, выкарыстоўваць для гэтага. Гэта патрабуе яшчэ адну аперацыю, чым раней адзін модуль з удзелам аддзела, але размножваюцца можа быць хутчэй. Выраз (V & V-) экстракты малодшы 1 біт ад В. пастаяннай 0x077CB531UL з'яўляецца паслядоўнасці дэ Брэйн, які вырабляе унікальны малюнак біты ў высокай 5 біт для кожнага магчымага становішча трохі, што яна памнажаецца. Калі Ёсць няма біты, ён вяртае 0. Больш падрабязную інфармацыю можна знайсці, чытаючы паперы Выкарыстаньне паслядоўнасцяў дэ Брэйн ў індэкс 1 у машыннае слова Чарльз Э. Лейзерсон, Харальд Прокофьеву, і Кіт Г. Randall.

На 8 кастрычнік 2005 Эндру Шапіра прапанаваў мне дадаць гэта. Дастын Spicuzza спытаў мяне, 14 красавіка 2009 года па літой вынік памножыць на 32-бітны тып так яна будзе працаваць пры кампіляцыі з 64-бітнымі цэлымі.


Круглы да наступнага найбольшая ступень 2, на паплавок ліцця

unsigned int const v; // Round this 32-bit value to the next highest power of 2
unsigned int r;       // Put the result here. (So v=3 -> r=4; v=8 -> r=8)

if (v > 1) 
{
  float f = (float)v;
  unsigned int const t = 1U << ((*(unsigned int *)&f >> 23) - 0x7f);
  r = t << (t < v);
}
else 
{
  r = 1;
}

Гэты код выкарыстоўвае 8 аперацый, але працуе на ўсіх V <= (1 <<31).

Хуткі і брудны версіі, для вобласці 1 <<V (1 <<25):

float f = (float)(v - 1);  
r = 1U << ((*(unsigned int*)(&f) >> 23) - 126);

Хоць хуткая і брудная версія выкарыстоўвае толькі каля 6 аперацый, гэта прыкладна ў тры разы павольней, чым тэхніка ніжэй (які ўключае ў сябе 12 аперацый) у супастаўленні на Athlon ™ XP 2100 + працэсар. Некаторыя працэсары будзе лепш з ім, ўсё ж.

На 27 верасня 2005 года Анди Смитерс прапанаваў мне ўключыць тэхніку для ліцця з якая плавае кропкай, каб знайсці LG шэрагу для акруглення да ступені 2. Як хутка і брудна тут версіі, яго версія працавала са значэннямі менш (1 <<25), з-за акругленьня мантиссы, але ён выкарыстаў яшчэ адну аперацыю.


Круглыя ды наступнага найбольшай что 2

unsigned int v; // compute the next highest power of 2 of 32-bit v

v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
У 12 аперацый, гэты код вылічае наступны найбольшая ступень 2, для 32-бітнай цэлага. Вынік можа быць выяўлены формулай 1U <<(LG (V - 1) + 1). Адзначым, што ў выпадку, калі краю V роўная 0, яна вяртае 0, які не з'яўляецца ступенню 2, вы можаце дадаць выраз V + = (V == 0), каб выправіць гэта, калі гэта мае значэнне. Было б хутчэй, 2 аперацыі з выкарыстаннем формулы і часопіса падставы 2 methed які выкарыстоўвае табліцы пошуку, але ў некаторых сітуацыях, даведачныя табліцы не падыходзяць, так што вышэй код можа быць лепш. (На Athlon ™ XP 2100 + я знайшоў вышэй Shift-злева, а затым або код так жа хутка, як з дапамогай аднаго рэгіёну Балтыйскага мора зборкі мове, які скануе ў зваротным, каб знайсці самы высокі бітам.) Яна працуе шляхам капіявання высокі бітам для ўсіх малодшых біта, а затым дадаўшы адну, у выніку чаго нясе, якія ўстанаўліваюць ўсе малодшыя біты ў 0, і адзін біт за бітам высокі 1. Калі зыходнае лік было ступенню 2, то декремент знізіць яго на адзін менш, так што мы акругліць да той жа першапачатковай кошту.

Вы можаце альтэрнатыўна вылічыць наступны больш высокі ступень ліку 2 усяго за 8 ці 9 аперацый з выкарыстаннем табліцы пошуку для падлогі (LG (V)), а затым ацэнкі 1 <<(1 + паверх (LG (V))); Atul Divekar прапанаваў мне аб гэтым 5 верасня 2010 года.

Распрацавана Шон Андэрсан, Sepember 14, 2001 года. Піт Харт паказаў мне на пару навін паведамленні ім і Уільям Льюіс ў лютым 1997 года, дзе яны дасягаюць таго ж алгарытму.


Interleave біт відавочным чынам

unsigned short x;   // Interleave bits of x and y, so that all of the
unsigned short y;   // bits of x are in the even positions and y in the odd;
unsigned int z = 0; // z gets the resulting Morton Number.

for (int i = 0; i < sizeof(x) * CHAR_BIT; i++) // unroll for more speed...
{
  z |= (x & 1U << i) << i | (y & 1U << i) << (i + 1);
}
Interleaved біт (ака Мортон нумара) карысныя для линеаризации 2D цэлымі каардынатамі, так што х і ў аб'ядноўваюцца ў адно лік, якое можна параўнаць з лёгкасцю і валодае тым уласцівасцю, што лік, як правіла, блізка да іншага, калі іх значэнняў х і ў блізкіх .


Interleave біты, пошук у табліцы

static const unsigned short MortonTable256[256] = 
{
  0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 
  0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 
  0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 
  0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 
  0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 
  0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 
  0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 
  0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, 
  0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 
  0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, 
  0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 
  0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 
  0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 
  0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 
  0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 
  0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 
  0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 
  0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 
  0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 
  0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 
  0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 
  0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 
  0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 
  0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, 
  0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 
  0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 
  0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 
  0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 
  0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, 
  0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 
  0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 
  0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
};

unsigned short x; // Interleave bits of x and y, so that all of the
unsigned short y; // bits of x are in the even positions and y in the odd;
unsigned int z;   // z gets the resulting 32-bit Morton Number.

z = MortonTable256[y >> 8]   << 17 | 
    MortonTable256[x >> 8]   << 16 |
    MortonTable256[y & 0xFF] <<  1 | 
    MortonTable256[x & 0xFF];


Для большай хуткасці, выкарыстоўваць дадатковую табліцу са значэннямі, якія MortonTable256 папярэдне ссунутыя на адзін біт налева. Гэта другі табліцы маглі б быць выкарыстаны для пошуку у, такім чынам памяншаючы аперацый на два, але амаль у два разы Патрабаваны аб'ём памяці. Працягваючы гэтую ж думка, чатыры табліцы могуць быць выкарыстаны, з двума з іх папярэдне ссунутыя на 16 злева ад двух папярэдніх, так што спатрэбіцца толькі 11 аперацый агульнага.

Interleave біт з 64-разраднымі размнажацца

У 11 аперацый, гэтая версія чаргуе біты з двух байт (а не шорты, як і ў іншых версіях), але многія з аперацый з'яўляюцца 64-разраднымі памнажае так што гэта не падыходзіць для ўсіх машын. Ўваходных параметраў, X і Y, павінна быць не менш 256.
unsigned char x;  // Interleave bits of (8-bit) x and y, so that all of the
unsigned char y;  // bits of x are in the even positions and y in the odd;
unsigned short z; // z gets the resulting 16-bit Morton Number.

z = ((x * 0x0101010101010101ULL & 0x8040201008040201ULL) * 
     0x0102040810204081ULL >> 49) & 0x5555 |
    ((y * 0x0101010101010101ULL & 0x8040201008040201ULL) * 
     0x0102040810204081ULL >> 48) & 0xAAAA;

Хольгер Bettag быў натхнёны прапанаваць гэтую тэхніку на 10 кастрычніка 2004 года, пасля чытання памножыць аснове развароты трохі тут.


Interleave біты двайковага Magic Numbers

static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF};
static const unsigned int S[] = {1, 2, 4, 8};

unsigned int x; // Interleave lower 16 bits of x and y, so the bits of x
unsigned int y; // are in the even positions and bits from y in the odd;
unsigned int z; // z gets the resulting 32-bit Morton Number.  
                // x and y must initially be less than 65536.

x = (x | (x << S[3])) & B[3];
x = (x | (x << S[2])) & B[2];
x = (x | (x << S[1])) & B[1];
x = (x | (x << S[0])) & B[0];

y = (y | (y << S[3])) & B[3];
y = (y | (y << S[2])) & B[2];
y = (y | (y << S[1])) & B[1];
y = (y | (y << S[0])) & B[0];

z = x | (y << 1);


Вызначце, калі слова мае нулявы байт

// Fewer operations:
unsigned int v; // 32-bit word to check if any 8-bit byte in it is 0
bool hasZeroByte = ~((((v & 0x7F7F7F7F) + 0x7F7F7F7F) | v) | 0x7F7F7F7F);
Гэты код можа быць карысна пры выкананні хуткіх копію радкі, у якіх слова капіюецца ў той час, ён выкарыстоўвае 5 аперацый. З іншага боку, тэставанне на нулявы байт у відавочных шляхоў (якія выцякаюць) маюць па крайняй меры 7 аперацый (калі ўлічваюцца ў найбольш зберагалым спосабам), і не больш за 12.

// More operations:
bool hasNoZeroByte = ((v & 0xff) && (v & 0xff00) && (v & 0xff0000) && (v & 0xff000000))
// OR:
unsigned char * p = (unsigned char *) &v;  
bool hasNoZeroByte = *p && *(p + 1) && *(p + 2) && *(p + 3);

Код у пачатку гэтага падзелу (пазначаныя "Менш аперацый") працуе першым абнулення высокі біт 4 байта ў слове. Пасля, ён дадае нумар, які будзе ў выніку перапаўнення ў старэйшы біт байта, калі любы з нізкіх біты былі Спачатку гэта мноства. Наступная высокім біт зыходнага слова з'яўляюцца ORed з гэтымі значэннямі, такім чынам, старэйшы біт байта ўсталёўваецца толькі тады, калі які-небудзь біт у байце было мноства. Нарэшце, мы вызначаем, калі любы з гэтых высокіх біты роўныя нулю па Оринг з іх усюды, акрамя старэйшых бітаў і звароты выніку. Пашырэнне да 64 біт трывіяльна: проста павелічэнне канстанты, 0x7F7F7F7F7F7F7F7F.

Для дадатковага паляпшэння, хутка папярэдняга тэставання, што патрабуе толькі 4 аперацыі могуць быць выкананы, каб вызначыць, ці з'яўляецца слова можа мець нулявы байт. Тэст таксама вяртае праўду, калі старэйшы байт 0x80, так Ёсць выпадковыя ілжывых спрацоўванняў, але павольней і больш дакладная версія вышэй, могуць быць выкарыстаны на кандыдатаў на агульнае павелічэнне ў хуткасці з правільным выхадам.

bool hasZeroByte = ((v + 0x7efefeff) ^ ~v) & 0x81010100;
if (hasZeroByte) // or may just have 0x80 in the high byte
{
  hasZeroByte = ~((((v & 0x7F7F7F7F) + 0x7F7F7F7F) | v) | 0x7F7F7F7F);
}

Існуе яшчэ больш хуткі спосаб - выкарыстоўваць hasless (V, 1), якая вызначаецца ніжэй, яна працуе ў 4 аперацыі і не патрабуе subsquent праверкі. Гэта спрашчае для

bool hasZeroByte = (v - 0x01010101UL) & ~v & 0x80808080UL;
Подвыражения (V - 0x01010101UL), вынікам якога з'яўляецца высокае біт у любы байт, калі адпаведны байт у V роўная нулю або больш, чым 0x80. Подвыражение ~ V & 0x80808080UL ацэньваецца як высокая біты ў байт, дзе б V не мае высокай біт (так б было менш, чым 0x80). Нарэшце, аперацыі AND гэтыя два подвыражения вынік высокага біты, дзе б у V была роўная нулю, так як высокія біты з-за значэння больш 0x80 ў першай катэгорыі выраз маскіруюцца ад другой.

Пол Мэсмэр прапанаваў хутка папярэдняга тэставання паляпшэнне 2 Кастрычніка 2004 года. Юха Ярви пазней прапанаваў hasless (V, 1) 6 красавіка 2005 году, які ён знайшоў на сход Лабараторыі Павел Вось , раней яна была напісана ў тэлеканферэнцыі паведамленне 27 красавіка 1987 г. Алан Майкрофт.


Вызначце, калі слова байт роўны п

Мы можам хацець ведаць, калі любы байт у слова мае пэўнае значэнне. Для гэтага, мы можам XOR значэнне для праверкі са словам, якое было запоўнена байт значэння, у якіх мы зацікаўленыя. Паколькі аперацыі XOR значэнне з сабой вынікі ў нулявы байт і выдатная ад нуля ў адваротным выпадку, мы можам перайсці вынік haszero.
#define hasvalue(x,n) \
(haszero((x) ^ (~0UL/255 * (n))))

Стывен M Бенет прапанаваў гэта 13 снежні 2009 пасля чытання запісу для haszero.


Вызначце, калі слова б менш, чым п

Выпрабаванняў, калі слова X змяшчае б без знака са значэннем <n. Спецыяльна для N = 1, яго можна выкарыстоўваць, каб знайсці 0-байт, даследуючы адзін доўгі ў той час, або любой байт за аперацыі XOR х з маскай ў першую чаргу. Карысці 4 арыфметычных / лагічных аперацый, калі п з'яўляецца канстантай.

Патрабаванні: X> = 0, 0 <= N <= 128

#define hasless(x,n) (((x)-~0UL/255*(n))&~(x)&~0UL/255*128)

Каб падлічыць колькасць байтаў ў X, якія менш чым за 7 N аперацый, выкарыстання
#define countless(x,n) \
(((~0UL/255*(127+(n))-((x)&~0UL/255*127))&~(x)&~0UL/255*128)/128%255)

Юха Ярви паслаў гэта разумная тэхніка для мяне 6 красавіка 2005 года. countless макраса дадалі Шон Андэрсан 10 красавіка 2005, натхнёныя Юха ў countmore , ніжэй.


Вызначце, калі слова мае байта больш, чым п

Выпрабаванняў, калі слова X змяшчае б без знака са значэннем> п. Карысці 3 арыфметычных / лагічных аперацый, калі п з'яўляецца канстантай.

Патрабаванні: X> = 0, 0 <= N <= 127

#define hasmore(x,n) (((x)+~0UL/255*(127-(n))|(x))&~0UL/255*128)
Каб падлічыць колькасць байтаў ў X, якія больш чым у 6 N аперацый, выкарыстання:
#define countmore(x,n) \
(((((x)&~0UL/255*127)+~0UL/255*(127-(n))|(x))&~0UL/255*128)/128%255)

Макросы hasmore было прапанавана Юха Ярви 6 Красавік 2005, і ён дадаў countmore 8 красавіка 2005.


Вызначце, калі слова байт паміж т і п

Пры т <п, гэты метад правярае, ці з'яўляецца слова X змяшчае б без знака значэння, такія, што M <<значэнне n. Ён выкарыстоўвае 7 арыфметычных / лагічных аперацый, калі N і M з'яўляюцца пастаяннымі.

Заўвага: байты, роўныя N можна паведаміць па likelyhasbetween як ілжывых спрацоўванняў, так што гэта павінна быць праверана па характары, калі пэўнага выніку неабходна.

Патрабаванні: X> = 0, 0 <= M <= 127, 0 <= N <= 128

#define likelyhasbetween(x,m,n) \
((((x)-~0UL/255*(n))&~(x)&((x)&~0UL/255*127)+~0UL/255*(127-(m)))&~0UL/255*128)

Гэты метад быў бы прыдатным для хуткага папярэдняга тэсціравання. Змены, якія прымае яшчэ адну аперацыю (8 Усяго за пастаяннай т і п), але дае дакладнага адказу:
#define hasbetween(x,m,n) \
((~0UL/255*(127+(n))-((x)&~0UL/255*127)&~(x)&((x)&~0UL/255*127)+~0UL/255*(127-(m)))&~0UL/255*128)
Каб падлічыць колькасць байтаў ў X, якія знаходзяцца паміж M і N (эксклюзіўныя) у 10 аперацый, выкарыстання:
#define countbetween(x,m,n) (hasbetween(x,m,n)/128%255)

Юха Ярви прапанаваў likelyhasbetween 6 красавіка 2005. Адтуль, Шон Андэрсан стварыў hasbetween і countbetween 10 красавіка 2005 года.


Вылічыць лексікаграфічным наступнай перастаноўкі біт

Выкажам здагадку, мы маем карціну бітаў N усталяваны ў 1 у цэлым, і мы хочам наступнай перастановай N 1 біт у лексікаграфічным сэнсе. Напрыклад, калі N з'яўляецца 3 і трохі карціна 00010011, наступнай мадэлі будзе 00010101, 00010110, 00.011.001,00011010, 00011100, 00100011, і так далей. Ніжэй хуткі спосаб для вылічэння наступнай перастаноўкі.
unsigned int v; // current permutation of bits 
unsigned int w; // next permutation of bits

unsigned int t = v | (v - 1); // t gets v's least significant 0 bits set to 1
// Next set to 1 the most significant bit to change, 
// set to 0 the least significant ones, and add the necessary 1 bits.
w = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));  

__builtin_ctz (V) GNU C Compiler ўласнай для x86 працэсараў вяртае лік канчатковых нулёў. Калі вы карыстаецеся Microsoft кампілятары для x86, з'яўляецца ўласнай _BitScanForward. Гэтыя абодва выпраменьваюць ЧФ інструкцыі, але эквіваленты могуць быць даступныя для іншых архітэктур. Калі няма, то можна скарыстацца адным з спосабаў падліку паслядоўных нулявых бітаў, згаданых раней.

Вось яшчэ адна версія, якая, як правіла, павольней, таму што яе аператар дзялення, але ён не патрабуе падліку канчатковых нулёў.

unsigned int t = (v | (v - 1)) + 1;  
w = t | ((((t & -t) / (v & -v)) >> 1) - 1);  

Дзякуючы Дарыё Sneidermanis Аргенціны, які падаў гэтую 28 Лістапада 2009.Popular Links

Published (Last edited): May 28 , source: http://graphics.stanford.edu/~seander/bithacks.html