total += ((i & mask) != 0) * value[j];
के स्थान पर प्रयास करें
total += (-((i & mask) != 0)) & value[j];
यह गुणा से बचाता है। चाहे कोई शाखा होगी या नहीं, इस पर निर्भर है कि संकलक के लिए शाखा-मुक्त कोड खोजने के लिए पर्याप्त चालाक है - (foo! = 0)। (जो संभव है, लेकिन मैं थोड़ा आश्चर्य होगा।)
(बेशक, इस two's-पूरक प्रतिनिधित्व पर निर्भर करता है;। सी मानक उस पर नास्तिक है)
आप संकलक बाहर मदद कर सकता है की तरह तो, 32-बिट ints संभालने और उस पर हस्ताक्षर किए >> प्रसारित संकेत बिट:
total += (((int)((i & mask) << (31 - j))) >> 31) & value[j];
है यही कारण है, बदलाव संभवतः सेट बिट सबसे महत्वपूर्ण पद के लिए छोड़ दिया है, पर हस्ताक्षर किए पूर्णांक के रूप में कास्ट, तो सही सब उपरोक्त कार्यान्वयन-परिभाषित धारणाओं के तहत, कम से कम महत्वपूर्ण स्थिति पर वापस, सभी 0 या सभी 1 को उपज देना। (मैंने इसका परीक्षण नहीं किया है।)
एक और संभावना: एक समय में 4 बिट्स (कहें) के ब्लॉक पर विचार करें। 16 अलग-अलग जोड़ अनुक्रम हैं; आप प्रत्येक कोड ब्लॉक के भीतर कोई परीक्षण नहीं होने के साथ, उनमें से प्रत्येक के लिए अनियंत्रित कोड प्रेषित कर सकते हैं। यहां आशा है कि एक अप्रत्यक्ष कूद के लिए 4 से कम परीक्षण और शाखाएं होंगी।
अद्यतन: जोनाथन Leffler की मचान का उपयोग करना, 4-बिट-पर-एक-समय विधि सबसे तेज है मेरी मैकबुक पर एक व्यापक अंतर से। नकारात्मक - और गुणा के समान होने के बारे में पता चला है। मुझे आश्चर्य है कि प्रोसेसर 0 और 1 तेज जैसे विशेष मामलों को गुणा करता है (या ऐसा कोई विशेष मामला नहीं है यदि यह अधिकतर बिट्स-स्पष्ट या अधिकतर बिट्स-सेट गुणों के लिए सामान्य रूप से तेज़ है)।
मैंने स्वीकार्य उत्तर को कोड नहीं किया है क्योंकि यह इस विशेष बेंचमार्क पर सबसे तेज़ होने की संभावना नहीं है (इसे केवल सेट बिट्स का आकलन करने से अधिक लाभ प्राप्त करना चाहिए, स्पैस सेट पर सर्वश्रेष्ठ प्रदर्शन करना चाहिए, लेकिन बिट्स का पूरी तरह से आधा इस बेंचमार्क में सेट हैं)। यहाँ Leffler की कोड के लिए मेरे परिवर्तन कर रहे हैं, इस मामले में किसी और को इस पर समय बिताने के लिए अजीब प्रेरित है:
#include <stdio.h>
#include <time.h>
static int value[] =
{
12, 36, 79, 21, 31, 93, 24, 15,
56, 63, 20, 47, 62, 88, 9, 36,
};
static int test_1(int i)
{
int total = 0;
for (unsigned short mask = 0x0001, j = 0; mask != 0; mask <<= 1, j++)
{
if (i & mask)
total += value[j];
}
return(total);
}
static int test_2(int i)
{
int total = 0;
for (unsigned short mask = 0x0001, j = 0; mask != 0; mask <<= 1, j++)
{
total += ((i & mask) != 0) * value[j];
}
return(total);
}
static int test_3(int i)
{
int total = 0;
for (unsigned mask = i & 0xFFFF, j = 0; mask != 0; mask >>= 1, j++)
{
total += (mask & 0x0001) * value[j];
}
return(total);
}
static int test_4(int i)
{
int total = 0;
for (unsigned mask = i & 0xFFFF, j = 0; mask != 0; mask >>= 1, j++)
{
total += -(mask & 0x0001) & value[j];
}
return(total);
}
static int test_5(int i)
{
int total = 0;
const int *p = value;
for (unsigned mask = i & 0xFFFF; mask != 0; mask >>= 4, p += 4)
{
switch (mask & 0xF)
{
case 0x0: break;
case 0x1: total += p[0]; break;
case 0x2: total += p[1]; break;
case 0x3: total += p[1] + p[0]; break;
case 0x4: total += p[2]; break;
case 0x5: total += p[2] + p[0]; break;
case 0x6: total += p[2] + p[1]; break;
case 0x7: total += p[2] + p[1] + p[0]; break;
case 0x8: total += p[3]; break;
case 0x9: total += p[3] + p[0]; break;
case 0xA: total += p[3] + p[1]; break;
case 0xB: total += p[3] + p[1] + p[0]; break;
case 0xC: total += p[3] + p[2]; break;
case 0xD: total += p[3] + p[2] + p[0]; break;
case 0xE: total += p[3] + p[2] + p[1]; break;
case 0xF: total += p[3] + p[2] + p[1] + p[0]; break;
}
}
return(total);
}
typedef int(*func_pointer)(int);
static func_pointer test[] = { test_1, test_2, test_3, test_4, test_5 };
#define DIM(x)(sizeof(x)/sizeof(*(x)))
int main()
{
int i, j, k;
for (i = 0; i < DIM(test); i++)
{
long sum = 0;
clock_t start = clock();
for (j = 0; j <= 0xFFFF; j += 13)
{
int rv;
for (k = 0; k < 1000; k++)
rv = (*test[i])(j);
sum += rv;
}
clock_t stop = clock();
printf("(sum = %ld) Test %d: %8.6f s\n", sum, i + 1,
(stop - start)/(1.0 * CLOCKS_PER_SEC));
}
}
परिणाम (gcc -O4 -std=c99 branchmult2.c
):
(sum = 1744366) Test 1: 0.225497 s
(sum = 1744366) Test 2: 0.221127 s
(sum = 1744366) Test 3: 0.126301 s
(sum = 1744366) Test 4: 0.124750 s
(sum = 1744366) Test 5: 0.064877 s
संपादित करें 2: मैंने तय कर लिया परीक्षण होगा volatile
क्वालीफायर के बिना अधिक यथार्थवादी बनें।
वे दोनों एक ही बात करने के लिए संकलन चाहिए, एक समझदार संकलक दिया। मैं अधिक पठनीय पहले विकल्प के साथ जाना होगा। क्या आपका मंच समर्थन निष्पादित करता है? यह यहां अच्छा काम करेगा, भविष्यवाणी करने के लिए केवल 1 निर्देश है (जोड़ने), इसलिए आपको इस मामले में एक सशक्त शाखा की आवश्यकता नहीं होगी। –
ध्यान देने योग्य कुछ: आप '((i & mask)! = 0)' '(i & mask) 'के साथ बदल सकते हैं। "!!" का दुरुपयोग है! ऑपरेटर को दो बार आवेदन करके "कास्ट टू बूल" ऑपरेटर बनाने के लिए। यह जेनरेट असेंबली को नहीं बदलना चाहिए, लेकिन यह एक आम मुहावरे और मेरी आंखों के लिए अधिक पठनीय है। – kquinn
एक अनुस्मारक कि ((i & mask)! = 0) पोर्टेबल नहीं हो सकता है .... झूठा 0 है, सच 0 नहीं है .... – Calyth