Luchian का एक विवरण क्यों इस व्यवहार होता है देता है, लेकिन मैंने सोचा कि यह इस समस्या का एक संभव समाधान को दिखाने के लिए एक अच्छा विचार होगा और एक ही समय में कैश अनजान एल्गोरिदम के बारे में थोड़ा दिखा।
आपका एल्गोरिथ्म मूल रूप से करता है:
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
A[j][i] = A[i][j];
जो सिर्फ एक आधुनिक सीपीयू के लिए भयानक है। एक समाधान है कि आप अपने कैश सिस्टम के बारे में विवरण जान सकें और उन समस्याओं से बचने के लिए एल्गोरिदम को ट्विक करें। जब तक आप उन विवरणों को जानते हैं तब तक बढ़िया काम करता है .. विशेष रूप से पोर्टेबल नहीं।
क्या हम उससे बेहतर कर सकते हैं? हाँ हम कर सकते हैं: इस समस्या का एक सामान्य दृष्टिकोण cache oblivious algorithms हैं कि जैसा कि नाम से कहते हैं बचा जाता है [1]
समाधान इस प्रकार दिखाई देगा विशिष्ट कैश आकार पर निर्भर किया जा रहा है:
void recursiveTranspose(int i0, int i1, int j0, int j1) {
int di = i1 - i0, dj = j1 - j0;
const int LEAFSIZE = 32; // well ok caching still affects this one here
if (di >= dj && di > LEAFSIZE) {
int im = (i0 + i1)/2;
recursiveTranspose(i0, im, j0, j1);
recursiveTranspose(im, i1, j0, j1);
} else if (dj > LEAFSIZE) {
int jm = (j0 + j1)/2;
recursiveTranspose(i0, i1, j0, jm);
recursiveTranspose(i0, i1, jm, j1);
} else {
for (int i = i0; i < i1; i++)
for (int j = j0; j < j1; j++)
mat[j][i] = mat[i][j];
}
}
थोड़ा और अधिक जटिल है, लेकिन आकार के प्रभाव के बारे में:: एक छोटी परीक्षण MATSIZE 8192
int main() {
LARGE_INTEGER start, end, freq;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
recursiveTranspose(0, MATSIZE, 0, MATSIZE);
QueryPerformanceCounter(&end);
printf("recursive: %.2fms\n", (end.QuadPart - start.QuadPart)/(double(freq.QuadPart)/1000));
QueryPerformanceCounter(&start);
transpose();
QueryPerformanceCounter(&end);
printf("iterative: %.2fms\n", (end.QuadPart - start.QuadPart)/(double(freq.QuadPart)/1000));
return 0;
}
results:
recursive: 480.58ms
iterative: 3678.46ms
के लिए कुछ VS2010 64 रिलीज के साथ मेरी प्राचीन E8400 पर काफी रोचक, testcode संपादित चलता यह बहुत कम, हालांकि अभी भी ध्यान देने योग्य कुछ हद तक स्पष्ट है, ऐसा इसलिए है क्योंकि हम 1 (रिकर्सिव एल्गोरिदम के लिए सामान्य अनुकूलन) को रिकर्स करने के बजाए एक पत्ता नोड के रूप में पुनरावृत्त समाधान का उपयोग कर रहे हैं। अगर हम LEAFSIZE = 1 सेट करते हैं, तो कैश का मेरे लिए कोई प्रभाव नहीं पड़ता है [8193: 1214.06; 8192: 1171.62ms, 8191: 1351.07ms
- यह त्रुटि के मार्जिन के अंदर है, उतार-चढ़ाव 100ms क्षेत्र में हैं; यह "बेंचमार्क" ऐसा कुछ नहीं है जिसे हम पूरी तरह सटीक मान चाहते हैं, तो मैं बहुत सहज महसूस करूंगा]
[1] इस सामग्री के लिए स्रोत: ठीक है अगर आप किसी ऐसे व्यक्ति से व्याख्यान नहीं ले सकते जो काम करता है Leiserson और इस पर सह .. मैं अपने कागजात एक अच्छा प्रारंभिक बिंदु मानते हैं। उन एल्गोरिदम अभी भी बहुत ही कम वर्णित हैं - सीएलआर के बारे में उनके बारे में एक फुटनोट है। फिर भी लोगों को आश्चर्यचकित करने का यह एक शानदार तरीका है।
संपादित (ध्यान दें: मैं एक है जो इस उत्तर पोस्ट नहीं हूँ, मैं सिर्फ इस जोड़ना चाहते थे):
यहां एक संपूर्ण सी ++ उपरोक्त कोड का संस्करण है:
template<class InIt, class OutIt>
void transpose(InIt const input, OutIt const output,
size_t const rows, size_t const columns,
size_t const r1 = 0, size_t const c1 = 0,
size_t r2 = ~(size_t) 0, size_t c2 = ~(size_t) 0,
size_t const leaf = 0x20)
{
if (!~c2) { c2 = columns - c1; }
if (!~r2) { r2 = rows - r1; }
size_t const di = r2 - r1, dj = c2 - c1;
if (di >= dj && di > leaf)
{
transpose(input, output, rows, columns, r1, c1, (r1 + r2)/2, c2);
transpose(input, output, rows, columns, (r1 + r2)/2, c1, r2, c2);
}
else if (dj > leaf)
{
transpose(input, output, rows, columns, r1, c1, r2, (c1 + c2)/2);
transpose(input, output, rows, columns, r1, (c1 + c2)/2, r2, c2);
}
else
{
for (ptrdiff_t i1 = (ptrdiff_t) r1, i2 = (ptrdiff_t) (i1 * columns);
i1 < (ptrdiff_t) r2; ++i1, i2 += (ptrdiff_t) columns)
{
for (ptrdiff_t j1 = (ptrdiff_t) c1, j2 = (ptrdiff_t) (j1 * rows);
j1 < (ptrdiff_t) c2; ++j1, j2 += (ptrdiff_t) rows)
{
output[j2 + i1] = input[i2 + j1];
}
}
}
}
आपका कोड कैश को असभ्य रूप से दिखता है। – CodesInChaos
@CodeInChaos और यह है। –
यह इस प्रश्न के समान ही एक ही मुद्दा है: http://stackoverflow.com/questions/7905760/matrix-multiplication-small-difference-in-matrix-size-large-difference-in-timi – Mysticial