দ্রুততম ধরণের দৈর্ঘ্যের 6 ইন্ট অ্যারে sort


401

অন্য স্ট্যাক ওভারফ্লো প্রশ্নের উত্তর ( এটি একটি ) আমি একটি আকর্ষণীয় সাব-সমস্যায় হোঁচট খেয়েছি । 6 টি পূর্ণসংখ্যার অ্যারে বাছাই করার দ্রুততম উপায় কী?

যেহেতু প্রশ্নটি খুব নিম্ন স্তরের:

  • আমরা ধরে নিতে পারি না লাইব্রেরিগুলি উপলভ্য রয়েছে (এবং কলটির নিজস্ব মূল্য আছে), কেবল সরল সি
  • নির্দেশ পাইপলাইন (ক আছে খালি এড়াতে খুব উচ্চ মূল্য) আমরা সম্ভবত শাখা কমান উচিত জাম্প, এবং নিয়ন্ত্রণ প্রতিটি অন্য ধরনের ভঙ্গ প্রবাহিত (ইন ক্রম পয়েন্ট পিছনে লুকিয়ে মত &&বা ||)।
  • ঘরটি সীমাবদ্ধ এবং নিবন্ধগুলি হ্রাস করা এবং মেমরির ব্যবহার একটি সমস্যা, আদর্শভাবে জায়গাটি সাজানো সম্ভবত সেরা।

সত্যই এই প্রশ্নটি এক ধরণের গল্ফ যেখানে লক্ষ্যটি উত্সের দৈর্ঘ্যকে হ্রাস করা নয় তবে সম্পাদনের সময়। আমি এটা 'Zening' কোড হিসেবে বইয়ের নাম ব্যবহার করা কল কোড অপ্টিমাইজেশান এর জেন দ্বারা মাইকেল Abrash এবং তার চরিত্র

কেন আকর্ষণীয় এটি হিসাবে বিভিন্ন স্তর রয়েছে:

  • উদাহরণটি সহজ এবং বোঝার জন্য সহজ এবং পরিমাপ, খুব বেশি দক্ষতার সাথে জড়িত নয়
  • এটি সমস্যার জন্য ভাল একটি অ্যালগরিদম নির্বাচনের প্রভাবগুলি দেখায় তবে সংকলক এবং অন্তর্নিহিত হার্ডওয়্যারগুলির প্রভাবগুলিও দেখায়।

এখানে আমার রেফারেন্স (নিষ্পাপ, অনুকূল নয়) বাস্তবায়ন এবং আমার পরীক্ষার সেট।

#include <stdio.h>

static __inline__ int sort6(int * d){

    char j, i, imin;
    int tmp;
    for (j = 0 ; j < 5 ; j++){
        imin = j;
        for (i = j + 1; i < 6 ; i++){
            if (d[i] < d[imin]){
                imin = i;
            }
        }
        tmp = d[j];
        d[j] = d[imin];
        d[imin] = tmp;
    }
}

static __inline__ unsigned long long rdtsc(void)
{
  unsigned long long int x;
     __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
     return x;
}

int main(int argc, char ** argv){
    int i;
    int d[6][5] = {
        {1, 2, 3, 4, 5, 6},
        {6, 5, 4, 3, 2, 1},
        {100, 2, 300, 4, 500, 6},
        {100, 2, 3, 4, 500, 6},
        {1, 200, 3, 4, 5, 600},
        {1, 1, 2, 1, 2, 1}
    };

    unsigned long long cycles = rdtsc();
    for (i = 0; i < 6 ; i++){
        sort6(d[i]);
        /*
         * printf("d%d : %d %d %d %d %d %d\n", i,
         *  d[i][0], d[i][6], d[i][7],
         *  d[i][8], d[i][9], d[i][10]);
        */
    }
    cycles = rdtsc() - cycles;
    printf("Time is %d\n", (unsigned)cycles);
}

কাঁচা ফলাফল

যেহেতু ভেরিয়েন্টগুলির সংখ্যা বড় হচ্ছে, আমি সেগুলি এখানে খুঁজে পাওয়া যায় এমন একটি টেস্ট স্যুইটে সংগ্রহ করেছি । প্রকৃত পরীক্ষাগুলি কেভিন স্টকের ধন্যবাদ, উপরে দেখানো থেকে কিছুটা নিখরচায়। আপনি এটি আপনার নিজের পরিবেশে সংকলন এবং সম্পাদন করতে পারেন। আমি বিভিন্ন টার্গেট আর্কিটেকচার / সংকলকগুলির আচরণের দ্বারা বেশ আগ্রহী। (ওকে বলছি, এর উত্তরে রাখুন, আমি নতুন ফলাফলের প্রতিটি অবদানকারীকে +1 করব)।

আমি এক বছর আগে ড্যানিয়েল স্টুটজবাচের (গল্ফিংয়ের জন্য) জবাব দিয়েছিলাম কারণ তিনি তখনকার দ্রুততম সমাধানের উত্সে ছিলেন (নেটওয়ার্কগুলি বাছাই)।

লিনাক্স 64 বিট, জিসিসি 4.6.1 64 বিট, ইন্টেল কোর 2 ডুও ই 8400, -ও 2

  • Qsort লাইব্রেরি ফাংশনে সরাসরি কল: 689.38
  • নিষ্পাপ বাস্তবায়ন (সন্নিবেশ সাজানোর): 285.70
  • সন্নিবেশ বাছাই (ড্যানিয়েল স্টুটজবাচ): 142.12
  • সন্নিবেশ বাছাই করুন তালিকাভুক্ত: 125.47
  • র‌্যাঙ্ক অর্ডার: 102.26
  • রেজিস্টারগুলির সাথে ক্রম ক্রম: 58.03
  • নেটওয়ার্ক বাছাই করা (ড্যানিয়েল স্টুটজবাচ): 111.68
  • নেটওয়ার্ক বাছাই (পল আর): 66.36
  • দ্রুত অদলবদুর সাথে নেটওয়ার্ক 12 বাছাই করা হচ্ছে: 58.86
  • বাছাই করা নেটওয়ার্কগুলি 12 পুনরায় সাজানো সোয়াপ: 53.74
  • নেটওয়ার্কগুলি বাছাই করা 12 সরল সোয়্যাপটি পুনরায় সাজানো হয়েছে: 31.54
  • পুনরায় সাজানো বাছাইকরণ নেটওয়ার্ক ডাব্লু / ফাস্ট অদলবদল: 31.54
  • পুনরায় সাজানো বাছাইকরণ নেটওয়ার্ক ডাব্লু / দ্রুত স্যুইপ ভি 2: 33.63
  • ইনলাইনড বুদ্বুদ সাজান (পাওলো বনজিনি): 48.85
  • নিবন্ধভুক্ত সারণি বাছাই করুন (পাওলো বনজিনি): 75.30

লিনাক্স 64 বিট, জিসিসি 4.6.1 64 বিট, ইন্টেল কোর 2 ডুও ই 8400, -ও 1

  • Qsort লাইব্রেরি ফাংশনে সরাসরি কল: 705.93
  • নিষ্পাপ বাস্তবায়ন (সন্নিবেশ সাজানোর): 135.60
  • সন্নিবেশ সাজান (ড্যানিয়েল স্টুটজবাচ): 142.11
  • সন্নিবেশ বাছাই করুন তালিকাভুক্ত: 126.75
  • র‌্যাঙ্ক অর্ডার: 46.42
  • রেজিস্টারগুলির সাথে রেঙ্ক অর্ডার: 43.58
  • নেটওয়ার্ক বাছাই করা (ড্যানিয়েল স্টুটজবাচ): 115.57
  • নেটওয়ার্ক বাছাই (পল আর): .4৪.৪৪
  • দ্রুত অদলবদুর সাথে নেটওয়ার্ক 12 বাছাই করা হচ্ছে: 61.98
  • বাছাই করা নেটওয়ার্কগুলি 12 পুনরায় সাজানো সোয়াপ: 54.67
  • নেটওয়ার্কগুলি বাছাই করা 12 সরল সোয়্যাপটি পুনরায় সাজানো হয়েছে: 31.54
  • পুনরায় সাজানো বাছাইকরণ নেটওয়ার্ক ডাব্লু / ফাস্ট অদলবদল: 31.24
  • পুনঃক্রমিত বাছাই নেটওয়ার্ক W / দ্রুত অদলবদল V2: 33.07
  • ইনলাইন করা বুদ্বুদ সাজান (পাওলো বনজিনি): 45.79
  • নিবন্ধভুক্ত সারণি বাছাই করুন (পাওলো বনজিনি): 80.15

আমি -O1 এবং -O2 ফলাফল উভয়ই অন্তর্ভুক্ত করেছি কারণ আশ্চর্যজনকভাবে বেশ কয়েকটি প্রোগ্রামের জন্য O2 O1 এর চেয়ে কম দক্ষ। আমি অবাক হই কোন নির্দিষ্ট অপ্টিমাইজেশনের এই প্রভাব আছে?

প্রস্তাবিত সমাধান সম্পর্কে মন্তব্য

সন্নিবেশ সাজান (ড্যানিয়েল স্টুটজবাচ)

যেমনটি প্রত্যাশিত ক্ষুদ্রাক্রমে শাখাগুলি হ'ল এটি অবশ্যই একটি ভাল ধারণা।

নেটওয়ার্ক বাছাই করা (ড্যানিয়েল স্টুটজবাচ)

সন্নিবেশ সাজানোর চেয়ে ভাল। আমি ভাবলাম যে যদি বাহ্যিক লুপটি এড়ানো থেকে প্রধান প্রভাবটি না পাওয়া যায়। আমি এটি পরীক্ষার জন্য অনিবন্ধিত সন্নিবেশ সাজানোর মাধ্যমে চেষ্টা করেছি এবং প্রকৃতপক্ষে আমরা প্রায় একই পরিসংখ্যান পাই (কোডটি এখানে )।

নেটওয়ার্ক বাছাই (পল আর)

এখন পর্যন্ত সেরা। আমি পরীক্ষার জন্য আসল কোডটি এখানে ব্যবহার করেছি । অন্যান্য সাজানোর নেটওয়ার্ক বাস্তবায়নের তুলনায় এটি কেন প্রায় দ্বিগুণ দ্রুত তা এখনও জানেন না। প্যারামিটার পাস হচ্ছে? দ্রুত সর্বোচ্চ?

নেটওয়ার্কগুলি 12 অদলবদল দ্রুত অদলবদলের সাথে বাছাই করা হচ্ছে

ড্যানিয়েল স্টুটজবাচের পরামর্শ অনুসারে, আমি শাখাবিহীন দ্রুত অদলবদলের (কোডটি এখানে ) তার সাথে 12 টি সোয়াপ বাছাই করার নেটওয়ার্কটি একত্রিত করেছি । এটি প্রকৃতপক্ষে দ্রুততর, 1 টি কম স্বাপের সাহায্যে আশা করা যায় এমন একটি ছোট মার্জিন (প্রায় 5%) দিয়ে সেরা এখন পর্যন্ত

এটি লক্ষণীয়ও আকর্ষণীয় যে পিপিসি আর্কিটেকচারে যদি ব্রাঞ্চহীন অদলবদলকে সহজ (4 গুণ) কম কার্যকর বলে মনে হয়।

লাইব্রেরি Qsort কল করা হচ্ছে

অন্য একটি রেফারেন্স পয়েন্ট দেওয়ার জন্য আমি কেবল লাইব্রেরি Qsort কল করার পরামর্শ হিসাবে চেষ্টা করেছি (কোডটি এখানে রয়েছে )। প্রত্যাশিত হিসাবে এটি অনেক ধীর: 10 থেকে 30 গুণ ধীর গতির ... নতুন পরীক্ষার স্যুইটের সাথে এটি স্পষ্ট হয়ে উঠলে, প্রধান সমস্যাটি প্রথম কলের পরে গ্রন্থাগারের প্রাথমিক লোড বলে মনে হয়, এবং এটি অন্যের সাথে এতটা খারাপভাবে তুলনা করে না ares সংস্করণ। এটি আমার লিনাক্সের চেয়ে ধীরে ধীরে 3 থেকে 20 গুণ কম। অন্যের দ্বারা পরীক্ষার জন্য ব্যবহৃত কিছু আর্কিটেকচারে এটি আরও দ্রুত বলে মনে হয় (গ্রন্থাগার কিউসোর্ট আরও জটিল এপিআই ব্যবহার করায় আমি এটি দেখে আশ্চর্য হয়েছি)।

পদক্রম

রেক্স কের আরও একটি সম্পূর্ণ ভিন্ন পদ্ধতি প্রস্তাব করেছিলেন: অ্যারে গণনা প্রতিটি আইটেমের জন্য সরাসরি এটির চূড়ান্ত অবস্থান। এটি দক্ষ কারণ গণনা র‌্যাঙ্ক অর্ডার শাখার প্রয়োজন নেই। এই পদ্ধতির অসুবিধাটি হ'ল এটি অ্যারের মেমরির পরিমাণের তিনগুণ বেশি নেয় (র‌্যাঙ্ক ক্রম সংরক্ষণের জন্য অ্যারে এবং ভেরিয়েবলগুলির একটি অনুলিপি)। পারফরম্যান্স ফলাফল খুব অবাক (এবং আকর্ষণীয়)। 32 বিট ওএস এবং ইন্টেল কোর 2 কোয়াড ই 8300 সহ আমার রেফারেন্স আর্কিটেকচারে, চক্র গণনাটি 1000 এর নীচে ছিল (ব্রাঞ্চিং সোয়াপযুক্ত নেটওয়ার্কগুলি বাছাই করার মতো)। কিন্তু যখন আমার its৪ বিট বাক্সে সংকলিত এবং কার্যকর করা হয়েছে (ইন্টেল কোর 2 ডুও) এটি আরও ভাল পারফর্ম করেছে: এটি এখন পর্যন্ত দ্রুততম হয়ে উঠেছে। অবশেষে আমি আসল কারণটি খুঁজে পেলাম। আমার 32 বিট বাক্সে জিসিসি 4.4.1 এবং আমার 64 বিট বাক্স জিসিসি 4.4 ব্যবহার করে।

আপডেট :

উপরের প্রকাশিত পরিসংখ্যানগুলি দেখায় যে এই প্রভাবটি এখনও সিসিসি পরবর্তী সংস্করণগুলির দ্বারা বর্ধিত হয়েছিল এবং রেঙ্ক অর্ডার অন্য কোনও বিকল্পের তুলনায় ধারাবাহিকভাবে দ্বিগুণ দ্রুত হয়ে ওঠে।

পুনরায় সাজানো অদলবদুর সাথে নেটওয়ার্কগুলি বাছাই করা 12

জিসিসি ৪.৪.৩ সহ রেক্স কের প্রস্তাবটির আশ্চর্য দক্ষতা আমাকে অবাক করে তুলেছে: ব্রাচলেস বাছাই করা নেটওয়ার্কগুলির চেয়ে 3 গুণ বেশি মেমরির ব্যবহার সহ একটি প্রোগ্রাম কীভাবে দ্রুত হতে পারে? আমার অনুমানটি ছিল যে এটি লেখার পরে পড়ার ধরণের নির্ভরতা কম ছিল, যার ফলে x86 এর সুপারক্যালার নির্দেশিকার সময়সূচীর আরও ভাল ব্যবহার করা যাবে। এটি আমাকে একটি ধারণা দিয়েছে: লেখার নির্ভরতার পরে পড়া কমিয়ে আনার জন্য অদলবদল পুনরায় অর্ডার করুন। আরও সহজভাবে বলতে গেলে: যখন আপনাকে SWAP(1, 2); SWAP(0, 2);দ্বিতীয় স্বরূপ সম্পাদন করার আগে প্রথম অদলবদলটি শেষ হওয়ার জন্য অপেক্ষা করতে হবে কারণ একটি সাধারণ মেমরি কোষ উভয়ই অ্যাক্সেস করতে পারে। আপনি যখন SWAP(1, 2); SWAP(4, 5);প্রসেসর সমান্তরাল উভয় চালিত করতে পারেন। আমি এটি চেষ্টা করেছি এবং এটি প্রত্যাশার মতো কাজ করে, বাছাই করার নেটওয়ার্কগুলি প্রায় 10% দ্রুত চলছে।

সরল সোয়াপ দিয়ে নেটওয়ার্কগুলি বাছাই করা 12

মূল পোস্টের এক বছর পর স্টেইনার এইচ। গাউনসন পরামর্শ দিয়েছিলেন, আমাদের কম্পাইলারকে আউটসামার্ট করার এবং অদলবদলের কোডটি সহজ রাখার চেষ্টা করা উচিত নয়। ফলস্বরূপ কোডটি প্রায় 40% দ্রুত হওয়ায় এটি সত্যিই একটি ভাল ধারণা! তিনি x86 ইনলাইন এসেম্বলি কোড ব্যবহার করে হাতে কলমে অপ্টিমাইজড একটি সোয়াপ প্রস্তাব করেছিলেন যা এখনও আরও কিছু চক্র এড়াতে পারে। সবচেয়ে আশ্চর্যজনক (এটি প্রোগ্রামারের মনোবিজ্ঞানের খণ্ডগুলি বলে) এটি যে এক বছর আগে ব্যবহৃত কেউই সেই অদলবদলের সংস্করণটি ব্যবহার করে নি। আমি পরীক্ষার জন্য যে কোডটি ব্যবহার করতাম তা এখানে । অন্যরা সি-র দ্রুত স্বাপটি লেখার জন্য অন্যান্য উপায়ের পরামর্শ দিয়েছিল, তবে এটি শালীন সংকলক সহ সাধারণের মতোই পারফরম্যান্স দেয়।

"সেরা" কোডটি এখন অনুসরণ হিসাবে রয়েছে:

static inline void sort6_sorting_network_simple_swap(int * d){
#define min(x, y) (x<y?x:y)
#define max(x, y) (x<y?y:x) 
#define SWAP(x,y) { const int a = min(d[x], d[y]); \
                    const int b = max(d[x], d[y]); \
                    d[x] = a; d[y] = b; }
    SWAP(1, 2);
    SWAP(4, 5);
    SWAP(0, 2);
    SWAP(3, 5);
    SWAP(0, 1);
    SWAP(3, 4);
    SWAP(1, 4);
    SWAP(0, 3);
    SWAP(2, 5);
    SWAP(1, 3);
    SWAP(2, 4);
    SWAP(2, 3);
#undef SWAP
#undef min
#undef max
}

যদি আমরা আমাদের পরীক্ষার সেটটিকে বিশ্বাস করি (এবং, হ্যাঁ এটি বেশ দুর্বল, তবে এটির সুবিধায় স্বল্প, সহজ এবং আমরা কী পরিমাপ করছি তা বোঝা সহজ), এক ধরণের ফলাফলের কোডের চক্রের গড় সংখ্যা 40 টি চক্রের নীচে ( 6 পরীক্ষা কার্যকর করা হয়)। যা প্রতিটি স্বাপকে গড়ে ৪ টি চক্র রাখে। আমি আশ্চর্যরূপে দ্রুত কল। অন্য কোন উন্নতি সম্ভব?


2
আপনার কি কিছুটা বাধা আছে? উদাহরণস্বরূপ, আমরা কি ধরে নিতে পারি যে কোনও 2 x, y এর জন্য x-yএবং x+yভূগর্ভস্থ বা প্রবাহের কারণ হবে না?
ম্যাথিউ এম।

3
পলের ব্রাঞ্চবিহীন অদলবদল ফাংশনের সাথে আমার 12-সোয়াপ বাছাই করা নেটওয়ার্কটি একত্রিত করার চেষ্টা করা উচিত। তার দ্রবণটি অ্যারেতে একক পয়েন্টারের পরিবর্তে স্ট্যাকের পৃথক উপাদান হিসাবে সমস্ত পরামিতিগুলি পাস করে। এটি একটি পার্থক্য করতে পারে।
ড্যানিয়েল স্টুটজবাচ

2
নোট করুন যে d৪-বিটের উপর rdtsc এর সঠিক বাস্তবায়ন __asm__ volatile (".byte 0x0f, 0x31; shlq $32, %%rdx; orq %%rdx, %0" : "=a" (x) : : "rdx");কারণ rdtsc উত্তরটি EDX: EAX এ রাখে যখন GCC এটি একক 64৪-বিট রেজিস্টারে প্রত্যাশা করে। আপনি -O3 এ সংকলন করে বাগটি দেখতে পাচ্ছেন। আরও দ্রুত সুইপ সম্পর্কে পল আর-এর কাছে আমার মন্তব্য নীচে দেখুন।
পাওলো বনজিণী

3
@ টাইলার: আপনি শাখা ছাড়াই কীভাবে এটি সমাবেশ পর্যায়ে বাস্তবায়ন করবেন?
লরেন পেচটেল

4
@ লরেন: যথাক্রমে বড় বা ছোট কিনা তার উপর নির্ভর করে CMP EAX, EBX; SBB EAX, EAX0 বা 0xFFFFFFFF রাখবে । "orrowণ সহ বিয়োগ", ("বহন সহ যুক্ত করুন") এর সমকক্ষ ; আপনি যে স্ট্যাটাস বিটটি উল্লেখ করেছেন সেটি হ'ল ক্যারি বিট। তারপরে আবারও, আমার মনে আছে এবং পেন্টিয়াম 4 বনাম এবং এর ভয়াবহ লেটেন্সি ও থ্রুপুট ছিল এবং কোর সিপিইউতে এখনও দ্বিগুণ ধীর ছিল। 80386 সাল থেকে শর্তসাপেক্ষে দোকান এবং শর্তসাপেক্ষে স্থানান্তর নির্দেশাবলীও রয়েছে তবে সেগুলিও ধীর গতির। EAXEAXEBXSBBADCADCSBBADDSUBSETccCMOVcc
j_random_hacker

উত্তর:


162

যে কোনও অপ্টিমাইজেশনের জন্য, পরীক্ষা করা, পরীক্ষা করা, পরীক্ষা করা সর্বদা সেরা। আমি অন্তত নেটওয়ার্ক এবং সন্নিবেশ বাছাই চেষ্টা করব। যদি আমি বাজি ধরতাম তবে আমি আমার অভিজ্ঞতার উপর ভিত্তি করে আমার টাকা সন্নিবেশ সাজানোর উপর রাখি।

আপনি কি ইনপুট ডেটা সম্পর্কে কিছু জানেন? কিছু অ্যালগরিদম নির্দিষ্ট ধরণের ডেটা দিয়ে আরও ভাল সম্পাদন করবে। উদাহরণস্বরূপ, সন্নিবেশ সাজানো বাছাই করা বা প্রায়-বাছাই করা ডেটাতে আরও ভাল সম্পাদন করে, তাই প্রায় সজ্জিত ডেটার উপরের-গড় সুযোগ থাকলে এটি আরও ভাল পছন্দ হবে।

আপনার পোস্ট করা অ্যালগরিদম একটি সন্নিবেশ সাজানোর অনুরূপ, তবে দেখে মনে হচ্ছে আপনি আরও তুলনার ব্যয়ে অদলবদলের সংখ্যা কমিয়েছেন। তুলনাগুলি অদল বদলের তুলনায় অনেক বেশি ব্যয়বহুল, কারণ শাখা নির্দেশাবলী পাইপলাইন স্টল করতে পারে।

এখানে একটি সন্নিবেশ সাজানোর বাস্তবায়ন:

static __inline__ int sort6(int *d){
        int i, j;
        for (i = 1; i < 6; i++) {
                int tmp = d[i];
                for (j = i; j >= 1 && tmp < d[j-1]; j--)
                        d[j] = d[j-1];
                d[j] = tmp;
        }
}

এখানে আমি কীভাবে বাছাইয়ের নেটওয়ার্ক তৈরি করব। প্রথমে, উপযুক্ত দৈর্ঘ্যের একটি নেটওয়ার্কের জন্য ন্যূনতম সেট সুইপ ম্যাক্রোগুলি তৈরি করতে এই সাইটটি ব্যবহার করুন । একটি ফাংশন এ আপ মোড়ানো আমাকে দেয়:

static __inline__ int sort6(int * d){
#define SWAP(x,y) if (d[y] < d[x]) { int tmp = d[x]; d[x] = d[y]; d[y] = tmp; }
    SWAP(1, 2);
    SWAP(0, 2);
    SWAP(0, 1);
    SWAP(4, 5);
    SWAP(3, 5);
    SWAP(3, 4);
    SWAP(0, 3);
    SWAP(1, 4);
    SWAP(2, 5);
    SWAP(2, 4);
    SWAP(1, 3);
    SWAP(2, 3);
#undef SWAP
}

9
+1: দুর্দান্ত, আপনি আমার হাতের কোডেড এবং উপরের উত্সর্গীকৃত নেটওয়ার্কের 13 টির চেয়ে 12 এক্সচেঞ্জের মাধ্যমে এটি করেছেন। আপনার জন্য নেটওয়ার্ক তৈরি করা সাইটের লিঙ্কটি যদি আমি করতে পারি তবে আমি আপনাকে আরও একটি +1 দেব - এখন বুকমার্ক।
পল আর

9
আপনি যদি সর্বাধিক অনুরোধগুলি ছোট আকারের অ্যারে হিসাবে প্রত্যাশা করেন তবে এটি সাধারণ উদ্দেশ্যে বাছাই করার জন্য একটি দুর্দান্ত ধারণা। এই পদ্ধতিটি ব্যবহার করে আপনি যে কেসগুলি অনুকূল করতে চান সেগুলির জন্য একটি স্যুইচ বিবৃতি ব্যবহার করুন; ডিফল্ট কেসটি একটি লাইব্রেরির বাছাই ফাংশন ব্যবহার করতে দিন।
মার্ক রান্সম

5
@ মার্ক একটি ভাল গ্রন্থাগার সাজানোর কার্যক্রমে ইতিমধ্যে ছোট অ্যারেগুলির জন্য একটি দ্রুতগতি রয়েছে। অনেকগুলি আধুনিক লাইব্রেরি পুনরাবৃত্তি করার পরে সন্নিবেশতলে স্যুইচ করে এমন একটি পুনরাবৃত্ত কুইকসোর্ট বা মার্জসার্ট ব্যবহার করবে n < SMALL_CONSTANT
ড্যানিয়েল স্টুটজবাচ

3
@ মার্ক ওয়েল, একটি সি লাইব্রেরি বাছাই করা ফাংশনটির জন্য আপনাকে কোনও ফাংশন পোর্টারের মাধ্যমে তুলনা ক্রিয়াকলাপ নির্দিষ্ট করতে হবে। প্রতিটি তুলনার জন্য একটি ফাংশন কল করার ওভারহেড বিশাল। সাধারণত, এটি এখনও যাওয়ার সবচেয়ে পরিষ্কার উপায়, কারণ প্রোগ্রামে এটি খুব কমই একটি সমালোচনামূলক পথ। যাইহোক, যদি এটি সমালোচনামূলক পথ হয় তবে আমরা যদি আরও ভালভাবে বাছাই করতে পারি যদি আমরা জানতে পারি যে আমরা পূর্ণসংখ্যার এবং তার মধ্যে ঠিক। টি সাজিয়ে রেখেছি। :)
ড্যানিয়েল স্টুটজবাচ

7
@ টিজিডব্লু: এক্সওআর অদলবদল প্রায়শই একটি খারাপ ধারণা।
পল আর

63

বাছাই করা নেটওয়ার্কগুলি ব্যবহার করে এখানে একটি বাস্তবায়ন দেওয়া হচ্ছে :

inline void Sort2(int *p0, int *p1)
{
    const int temp = min(*p0, *p1);
    *p1 = max(*p0, *p1);
    *p0 = temp;
}

inline void Sort3(int *p0, int *p1, int *p2)
{
    Sort2(p0, p1);
    Sort2(p1, p2);
    Sort2(p0, p1);
}

inline void Sort4(int *p0, int *p1, int *p2, int *p3)
{
    Sort2(p0, p1);
    Sort2(p2, p3);
    Sort2(p0, p2);  
    Sort2(p1, p3);  
    Sort2(p1, p2);  
}

inline void Sort6(int *p0, int *p1, int *p2, int *p3, int *p4, int *p5)
{
    Sort3(p0, p1, p2);
    Sort3(p3, p4, p5);
    Sort2(p0, p3);  
    Sort2(p2, p5);  
    Sort4(p1, p2, p3, p4);  
}

এর জন্য আপনার সত্যই খুব দক্ষ শাখাবিহীন minএবং maxবাস্তবায়ন প্রয়োজন , যেহেতু কার্যকরভাবে এই কোডটি কীভাবে এটিকে ফুটিয়ে তোলে - একটি ক্রম minএবং maxক্রিয়াকলাপ (মোট 13 টি), মোট 13 টি। আমি এটি পাঠকের অনুশীলন হিসাবে রেখেছি।

নোট করুন যে এই প্রয়োগটি নিজেকে ভেক্টরাইজেশনে সহজেই ndsণ দেয় (যেমন সিমডি - বেশিরভাগ সিমডি আইএসএতে ভেক্টর ন্যূনতম / সর্বাধিক নির্দেশাবলী থাকে) এবং জিপিইউ বাস্তবায়নগুলিতেও (যেমন সিউডিএ - শাখাবিহীন থাকায় ওয়ার্প ডাইভারজেন্স ইত্যাদি সমস্যা নেই)।

আরও দেখুন: খুব অল্প তালিকাকে সাজাতে দ্রুত অ্যালগরিদম বাস্তবায়ন


1
: এর জন্য ন্যুনতম / সর্বাধিক কিছু বিট হ্যাক জন্য graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
Rubys

1
@ পল: বাস্তব সিউডিএ প্রসঙ্গে, এটি অবশ্যই সেরা উত্তর। গল্ফ x64 প্রসঙ্গে এটি (এবং কত) তা পরীক্ষা করে ফলাফল প্রকাশ করব।
ক্রিস

1
Sort3আপনি যদি উল্লেখ করেন যে (a+b+c)-(min+max)এটি কেন্দ্রীয় সংখ্যা faster
রেক্স কের

1
@ রেক্স: আমি দেখছি - এটি দেখতে ভাল লাগছে। অ্যালটিভেক এবং এসএসইয়ের মতো সিমড আর্কিটেকচারের জন্য এটি একই সংখ্যার নির্দেশিকা চক্র হবে (সর্বাধিক এবং কমপক্ষে একক / চিকিত্সার যোগ / বিয়োগের মতো চক্র নির্দেশাবলী) তবে সাধারণ স্কেলারের সিপিইউয়ের জন্য আপনার পদ্ধতিটি আরও ভাল দেখাচ্ছে।
পল আর

2
যদি আমি শর্তসাপেক্ষ পদক্ষেপ নির্দেশাবলী সহ জিসিসি অপ্টিমাইজ মিনিট দিন আমি একটি 33% speedup পাবেন: #define SWAP(x,y) { int dx = d[x], dy = d[y], tmp; tmp = d[x] = dx < dy ? dx : dy; d[y] ^= dx ^ tmp; }। এখানে আমি ব্যবহার করছি না?: ডি [ই] এর জন্য কারণ এটি কিছুটা খারাপ পারফরম্যান্স দেয়, তবে এটি প্রায় গোলমালে।
পাওলো বনজিণী

45

যেহেতু এগুলি পূর্ণসংখ্যা এবং তুলনাগুলি দ্রুত, তাই কেন প্রত্যেকে সরাসরি র‌্যাঙ্ক ক্রম গণনা করা হয় না:

inline void sort6(int *d) {
  int e[6];
  memcpy(e,d,6*sizeof(int));
  int o0 = (d[0]>d[1])+(d[0]>d[2])+(d[0]>d[3])+(d[0]>d[4])+(d[0]>d[5]);
  int o1 = (d[1]>=d[0])+(d[1]>d[2])+(d[1]>d[3])+(d[1]>d[4])+(d[1]>d[5]);
  int o2 = (d[2]>=d[0])+(d[2]>=d[1])+(d[2]>d[3])+(d[2]>d[4])+(d[2]>d[5]);
  int o3 = (d[3]>=d[0])+(d[3]>=d[1])+(d[3]>=d[2])+(d[3]>d[4])+(d[3]>d[5]);
  int o4 = (d[4]>=d[0])+(d[4]>=d[1])+(d[4]>=d[2])+(d[4]>=d[3])+(d[4]>d[5]);
  int o5 = 15-(o0+o1+o2+o3+o4);
  d[o0]=e[0]; d[o1]=e[1]; d[o2]=e[2]; d[o3]=e[3]; d[o4]=e[4]; d[o5]=e[5];
}

@ রেক্স: জিসিসি -ओ 1 সহ এটি 1000 চক্রের নীচে, এটি নেটওয়ার্কের বাছাইয়ের চেয়ে বেশ দ্রুত কিন্তু ধীর। কোড উন্নত করার কোন ধারণা? হতে পারে যদি আমরা অ্যারে অনুলিপি এড়াতে পারি ...
ক্রিসস

@ ক্রিসস: এটি আমার জন্য ওও -2 দিয়ে বাছাই করার নেটওয়ার্কের চেয়ে দ্রুত। -O2 ঠিকঠাক না হওয়ার কোনও কারণ আছে কি না, অথবা -O2-তেও এটি আপনার পক্ষে ধীর? সম্ভবত এটি মেশিন আর্কিটেকচারের মধ্যে একটি পার্থক্য?
রেক্স কের

1
@ রেক্স: দুঃখিত, আমি প্রথম> দর্শনে> বনাম> প্যাটার্নটি মিস করেছি। এটি প্রতিটি ক্ষেত্রেই কাজ করে।
ক্রিস

3
@ ক্রিসস: আহা। এটি সম্পূর্ণ আশ্চর্যজনক নয় - প্রচুর ভেরিয়েবলগুলি ভাসমান রয়েছে এবং তাদের সাবধানে অর্ডার করতে হবে এবং রেজিস্টারগুলিতে ক্যাশে করতে হবে ইত্যাদি।
রেক্স কের

2
@ এসপোকের 0+1+2+3+4+5=15যেহেতু তাদের একজন নিখোঁজ রয়েছে, তাই বাকি 15 টি বিয়োগফলের যোগফল একটি অনুপস্থিত
গ্লেন টাইটেলবাম

35

দেখে মনে হচ্ছে আমি এক বছর দেরিতে পার্টিতে এসেছি, তবে আমরা এখানে যাচ্ছি ...

জিসিসি ৪.৪.২ দ্বারা উত্পন্ন সমাবেশটি দেখে আমি লক্ষ্য করেছি যে প্রতিটি সোয়াপের জন্য বোঝা এবং স্টোরগুলি করা হচ্ছে, যা সত্যই প্রয়োজন হয় না which 6 মানগুলিকে নিবন্ধগুলিতে লোড করা, সেগুলি সাজানো এবং মেমরিতে ফিরিয়ে আনি আরও ভাল। আমি স্টোরগুলিতে লোডগুলিকে যথাসম্ভব কাছাকাছি হওয়ার আদেশ দিয়েছিলাম সেখানে রেজিস্টারগুলি প্রথমে প্রয়োজনীয় এবং শেষবার ব্যবহার করা হচ্ছে। আমি স্টেইনার এইচ। গন্ডারসনের সুইপ ম্যাক্রোও ব্যবহার করেছি। আপডেট: আমি পাওলো বনজিনির সুইড ম্যাক্রোতে স্যুইচ করেছি যা জিসিসি গন্ডসনের মতো কিছুতে রূপান্তরিত করেছে, তবে জিসিসি নির্দেশাবলীর সুস্পষ্ট সমাবেশ হিসাবে না দেওয়ার কারণে আরও ভালভাবে নির্দেশ দিতে সক্ষম হয়।

আমি আরও ভাল অর্ডার দিতে হতে পারে, যদিও সেরা পারফরম্যান্স হিসাবে দেওয়া পুনরায় সাজানো সোয়াপ নেটওয়ার্ক হিসাবে একই স্বাপ ক্রম ব্যবহার। যদি আমি আরও কিছু সময় পাই তবে আমি একগুচ্ছ ক্রম উত্পাদন এবং পরীক্ষা করব।

আমি 4000 টিরও বেশি অ্যারে বিবেচনা করার জন্য পরীক্ষার কোডটি পরিবর্তন করেছি এবং প্রত্যেককে বাছাই করার জন্য প্রয়োজনীয় চক্রের গড় সংখ্যা দেখাই। একটি আই 5-650-তে আমি পুনরায় সাজানো বাছাই করা নেটওয়ার্কের সাথে তুলনা করে ~ 34.1 চক্র / সাজান (-O3 ব্যবহার করে) পাচ্ছি,-65.3 চক্র / সাজান (-O1, বিট -O2 এবং -O3 ব্যবহার করে)।

#include <stdio.h>

static inline void sort6_fast(int * d) {
#define SWAP(x,y) { int dx = x, dy = y, tmp; tmp = x = dx < dy ? dx : dy; y ^= dx ^ tmp; }
    register int x0,x1,x2,x3,x4,x5;
    x1 = d[1];
    x2 = d[2];
    SWAP(x1, x2);
    x4 = d[4];
    x5 = d[5];
    SWAP(x4, x5);
    x0 = d[0];
    SWAP(x0, x2);
    x3 = d[3];
    SWAP(x3, x5);
    SWAP(x0, x1);
    SWAP(x3, x4);
    SWAP(x1, x4);
    SWAP(x0, x3);
    d[0] = x0;
    SWAP(x2, x5);
    d[5] = x5;
    SWAP(x1, x3);
    d[1] = x1;
    SWAP(x2, x4);
    d[4] = x4;
    SWAP(x2, x3);
    d[2] = x2;
    d[3] = x3;

#undef SWAP
#undef min
#undef max
}

static __inline__ unsigned long long rdtsc(void)
{
    unsigned long long int x;
    __asm__ volatile ("rdtsc; shlq $32, %%rdx; orq %%rdx, %0" : "=a" (x) : : "rdx");
    return x;
}

void ran_fill(int n, int *a) {
    static int seed = 76521;
    while (n--) *a++ = (seed = seed *1812433253 + 12345);
}

#define NTESTS 4096
int main() {
    int i;
    int d[6*NTESTS];
    ran_fill(6*NTESTS, d);

    unsigned long long cycles = rdtsc();
    for (i = 0; i < 6*NTESTS ; i+=6) {
        sort6_fast(d+i);
    }
    cycles = rdtsc() - cycles;
    printf("Time is %.2lf\n", (double)cycles/(double)NTESTS);

    for (i = 0; i < 6*NTESTS ; i+=6) {
        if (d[i+0] > d[i+1] || d[i+1] > d[i+2] || d[i+2] > d[i+3] || d[i+3] > d[i+4] || d[i+4] > d[i+5])
            printf("d%d : %d %d %d %d %d %d\n", i,
                    d[i+0], d[i+1], d[i+2],
                    d[i+3], d[i+4], d[i+5]);
    }
    return 0;
}

আমি পরীক্ষার স্যুইটটি পরিবর্তন করেছি প্রতি ধরণের ঘড়ি প্রতিবেদন করতে এবং আরও পরীক্ষা চালানোর জন্য (সিএমপি ফাংশনটিও ইন্টিজার ওভারফ্লো হ্যান্ডেল করার জন্য আপডেট করা হয়েছিল), এখানে কিছু ভিন্ন স্থাপত্যের ফলাফল রয়েছে। আমি একটি এএমডি সিপিইউতে পরীক্ষার চেষ্টা করেছি কিন্তু rdtsc আমার উপলব্ধ X6 1100T এর উপর নির্ভরযোগ্য নয়।

Clarkdale (i5-650)
==================
Direct call to qsort library function      635.14   575.65   581.61   577.76   521.12
Naive implementation (insertion sort)      538.30   135.36   134.89   240.62   101.23
Insertion Sort (Daniel Stutzbach)          424.48   159.85   160.76   152.01   151.92
Insertion Sort Unrolled                    339.16   125.16   125.81   129.93   123.16
Rank Order                                 184.34   106.58   54.74    93.24    94.09
Rank Order with registers                  127.45   104.65   53.79    98.05    97.95
Sorting Networks (Daniel Stutzbach)        269.77   130.56   128.15   126.70   127.30
Sorting Networks (Paul R)                  551.64   103.20   64.57    73.68    73.51
Sorting Networks 12 with Fast Swap         321.74   61.61    63.90    67.92    67.76
Sorting Networks 12 reordered Swap         318.75   60.69    65.90    70.25    70.06
Reordered Sorting Network w/ fast swap     145.91   34.17    32.66    32.22    32.18

Kentsfield (Core 2 Quad)
========================
Direct call to qsort library function      870.01   736.39   723.39   725.48   721.85
Naive implementation (insertion sort)      503.67   174.09   182.13   284.41   191.10
Insertion Sort (Daniel Stutzbach)          345.32   152.84   157.67   151.23   150.96
Insertion Sort Unrolled                    316.20   133.03   129.86   118.96   105.06
Rank Order                                 164.37   138.32   46.29    99.87    99.81
Rank Order with registers                  115.44   116.02   44.04    116.04   116.03
Sorting Networks (Daniel Stutzbach)        230.35   114.31   119.15   110.51   111.45
Sorting Networks (Paul R)                  498.94   77.24    63.98    62.17    65.67
Sorting Networks 12 with Fast Swap         315.98   59.41    58.36    60.29    55.15
Sorting Networks 12 reordered Swap         307.67   55.78    51.48    51.67    50.74
Reordered Sorting Network w/ fast swap     149.68   31.46    30.91    31.54    31.58

Sandy Bridge (i7-2600k)
=======================
Direct call to qsort library function      559.97   451.88   464.84   491.35   458.11
Naive implementation (insertion sort)      341.15   160.26   160.45   154.40   106.54
Insertion Sort (Daniel Stutzbach)          284.17   136.74   132.69   123.85   121.77
Insertion Sort Unrolled                    239.40   110.49   114.81   110.79   117.30
Rank Order                                 114.24   76.42    45.31    36.96    36.73
Rank Order with registers                  105.09   32.31    48.54    32.51    33.29
Sorting Networks (Daniel Stutzbach)        210.56   115.68   116.69   107.05   124.08
Sorting Networks (Paul R)                  364.03   66.02    61.64    45.70    44.19
Sorting Networks 12 with Fast Swap         246.97   41.36    59.03    41.66    38.98
Sorting Networks 12 reordered Swap         235.39   38.84    47.36    38.61    37.29
Reordered Sorting Network w/ fast swap     115.58   27.23    27.75    27.25    26.54

Nehalem (Xeon E5640)
====================
Direct call to qsort library function      911.62   890.88   681.80   876.03   872.89
Naive implementation (insertion sort)      457.69   236.87   127.68   388.74   175.28
Insertion Sort (Daniel Stutzbach)          317.89   279.74   147.78   247.97   245.09
Insertion Sort Unrolled                    259.63   220.60   116.55   221.66   212.93
Rank Order                                 140.62   197.04   52.10    163.66   153.63
Rank Order with registers                  84.83    96.78    50.93    109.96   54.73
Sorting Networks (Daniel Stutzbach)        214.59   220.94   118.68   120.60   116.09
Sorting Networks (Paul R)                  459.17   163.76   56.40    61.83    58.69
Sorting Networks 12 with Fast Swap         284.58   95.01    50.66    53.19    55.47
Sorting Networks 12 reordered Swap         281.20   96.72    44.15    56.38    54.57
Reordered Sorting Network w/ fast swap     128.34   50.87    26.87    27.91    28.02

আপনার রেজিস্টার ভেরিয়েবলগুলির ধারণাটি রেক্স কেরারের "র‌্যাঙ্ক অর্ডার" সমাধানে প্রয়োগ করা উচিত। এটি দ্রুত হওয়া উচিত, এবং সম্ভবত তখন -O3অপ্টিমাইজেশনটি পাল্টা-উত্পাদনশীল হবে না।
cdunn2001

1
@ cdunn2001 আমি কেবল এটি পরীক্ষা করেছি, আমি উন্নতি দেখছি না (-O0 এবং -O- তে কয়েকটি চক্র ব্যতীত)। এই এসএমটির দিকে তাকালে এটি প্রদর্শিত হয় যে জিসিসি ইতিমধ্যে রেজিস্টারগুলি ব্যবহার করতে এবং ম্যাকসিপিতে কলটি নির্মূল করতে সক্ষম হয়েছে।
কেভিন স্টক

আপনি কি টেস্ট স্যুটে সহজ সোয়াপ সংস্করণটি যুক্ত করতে আপত্তি জানাতে পারেন, আমার ধারণা এটি হাতের মাধ্যমে অনুকূলিত হওয়া অ্যাসেম্বলি ফাস্ট অদলবদলের সাথে তুলনা করা আকর্ষণীয় হতে পারে।
25:48

1
আপনার কোডটি এখনও গ্রাউন্ডসনের অদলবদল ব্যবহার করে, আমার হবে #define SWAP(x,y) { int oldx = x; x = x < y ? x : y; y ^= oldx ^ x; }
পাওলো বনজিণী

@ পাওলো বনজিনি: হ্যাঁ, আমি আপনার সাথে একটি পরীক্ষার মামলা যুক্ত করার ইচ্ছা নিয়েছিলাম, এখনও সময় হয়নি। তবে আমি ইনলাইন এসেম্বলি এড়িয়ে চলব।

15

আমি গুগল থেকে এই প্রশ্নে হোঁচট খেয়েছি কিছু দিন আগে কারণ আমারও দ্রুত দৈর্ঘ্যের 6 টি পূর্ণসংখ্যার সাজানোর প্রয়োজন ছিল। তবে আমার ক্ষেত্রে, আমার পূর্ণসংখ্যাগুলি কেবলমাত্র 8 টি বিট (32 এর পরিবর্তে) এবং আমার কেবলমাত্র সি ব্যবহারের কঠোর প্রয়োজন নেই thought

আমি অ্যাসেমব্লিতে এমন একটি নেটওয়ার্ক সাজানোর একটি বৈকল্পিক প্রয়োগ করেছি যা এসএসই ব্যবহার করে তুলনা এবং স্ব্যাপ অপারেশনগুলিকে যথাসম্ভব ভেক্টরাইজ করতে ব্যবহার করে। অ্যারের সম্পূর্ণরূপে বাছাই করতে ছয়টি "পাস" লাগে। আমি পিসিএমপিজিটিবি (ভেক্টরাইজড তুলনা) এর ফলাফলগুলি সরাসরি পিএইচডিইউবিবি (ভেক্টরাইজড অদলবদল) এর পরামিতিগুলিতে রূপান্তর করতে একটি অভিনব পদ্ধতি ব্যবহার করেছি, কেবলমাত্র একটি প্যাডডিবি (ভেক্টরাইজড অ্যাড) এবং কিছু ক্ষেত্রে একটি প্যান্ড (বিটওয়াইস এন্ড) নির্দেশও ব্যবহার করে।

এই পদ্ধতির সত্যিকারের শাখাবিহীন কার্য সম্পাদনেরও পার্শ্ব প্রতিক্রিয়া ছিল । এখানে কোনও লাফ দেওয়ার নির্দেশনা নেই।

দেখা যাচ্ছে যে এই বাস্তবায়ন বাস্তবায়নের তুলনায় প্রায় 38% দ্রুত যা বর্তমানে প্রশ্নের দ্রুততম বিকল্প হিসাবে চিহ্নিত হয়েছে ("সরল সোয়াপযুক্ত নেটওয়ার্কগুলি 12 বাছাই করা")। charতুলনাটি ন্যায্য করার জন্য, আমি আমার পরীক্ষার সময় অ্যারে উপাদানগুলি ব্যবহার করতে প্রয়োগটি সংশোধন করেছি।

আমি নোট করা উচিত যে এই পদ্ধতির 16 টি উপাদান পর্যন্ত কোনও অ্যারে আকারে প্রয়োগ করা যেতে পারে। আমি বড় অ্যারেগুলির জন্য বিকল্পগুলির তুলনায় আপেক্ষিক গতির সুবিধা আশা করি expect

কোডটি এসএসএসই 3 সহ x86_64 প্রসেসরের জন্য এমএএসএম-এ লেখা আছে। ফাংশনটি "নতুন" উইন্ডোজ x64 কলিং কনভেনশন ব্যবহার করে। এটা এখানে...

PUBLIC simd_sort_6

.DATA

ALIGN 16

pass1_shuffle   OWORD   0F0E0D0C0B0A09080706040503010200h
pass1_add       OWORD   0F0E0D0C0B0A09080706050503020200h
pass2_shuffle   OWORD   0F0E0D0C0B0A09080706030405000102h
pass2_and       OWORD   00000000000000000000FE00FEFE00FEh
pass2_add       OWORD   0F0E0D0C0B0A09080706050405020102h
pass3_shuffle   OWORD   0F0E0D0C0B0A09080706020304050001h
pass3_and       OWORD   00000000000000000000FDFFFFFDFFFFh
pass3_add       OWORD   0F0E0D0C0B0A09080706050404050101h
pass4_shuffle   OWORD   0F0E0D0C0B0A09080706050100020403h
pass4_and       OWORD   0000000000000000000000FDFD00FDFDh
pass4_add       OWORD   0F0E0D0C0B0A09080706050403020403h
pass5_shuffle   OWORD   0F0E0D0C0B0A09080706050201040300h
pass5_and       OWORD 0000000000000000000000FEFEFEFE00h
pass5_add       OWORD   0F0E0D0C0B0A09080706050403040300h
pass6_shuffle   OWORD   0F0E0D0C0B0A09080706050402030100h
pass6_add       OWORD   0F0E0D0C0B0A09080706050403030100h

.CODE

simd_sort_6 PROC FRAME

    .endprolog

    ; pxor xmm4, xmm4
    ; pinsrd xmm4, dword ptr [rcx], 0
    ; pinsrb xmm4, byte ptr [rcx + 4], 4
    ; pinsrb xmm4, byte ptr [rcx + 5], 5
    ; The benchmarked 38% faster mentioned in the text was with the above slower sequence that tied up the shuffle port longer.  Same on extract
    ; avoiding pins/extrb also means we don't need SSE 4.1, but SSSE3 CPUs without SSE4.1 (e.g. Conroe/Merom) have slow pshufb.
    movd    xmm4, dword ptr [rcx]
    pinsrw  xmm4,  word ptr [rcx + 4], 2  ; word 2 = bytes 4 and 5


    movdqa xmm5, xmm4
    pshufb xmm5, oword ptr [pass1_shuffle]
    pcmpgtb xmm5, xmm4
    paddb xmm5, oword ptr [pass1_add]
    pshufb xmm4, xmm5

    movdqa xmm5, xmm4
    pshufb xmm5, oword ptr [pass2_shuffle]
    pcmpgtb xmm5, xmm4
    pand xmm5, oword ptr [pass2_and]
    paddb xmm5, oword ptr [pass2_add]
    pshufb xmm4, xmm5

    movdqa xmm5, xmm4
    pshufb xmm5, oword ptr [pass3_shuffle]
    pcmpgtb xmm5, xmm4
    pand xmm5, oword ptr [pass3_and]
    paddb xmm5, oword ptr [pass3_add]
    pshufb xmm4, xmm5

    movdqa xmm5, xmm4
    pshufb xmm5, oword ptr [pass4_shuffle]
    pcmpgtb xmm5, xmm4
    pand xmm5, oword ptr [pass4_and]
    paddb xmm5, oword ptr [pass4_add]
    pshufb xmm4, xmm5

    movdqa xmm5, xmm4
    pshufb xmm5, oword ptr [pass5_shuffle]
    pcmpgtb xmm5, xmm4
    pand xmm5, oword ptr [pass5_and]
    paddb xmm5, oword ptr [pass5_add]
    pshufb xmm4, xmm5

    movdqa xmm5, xmm4
    pshufb xmm5, oword ptr [pass6_shuffle]
    pcmpgtb xmm5, xmm4
    paddb xmm5, oword ptr [pass6_add]
    pshufb xmm4, xmm5

    ;pextrd dword ptr [rcx], xmm4, 0    ; benchmarked with this
    ;pextrb byte ptr [rcx + 4], xmm4, 4 ; slower version
    ;pextrb byte ptr [rcx + 5], xmm4, 5
    movd   dword ptr [rcx], xmm4
    pextrw  word ptr [rcx + 4], xmm4, 2  ; x86 is little-endian, so this is the right order

    ret

simd_sort_6 ENDP

END

আপনি এটিকে একটি এক্সিকিউটেবল অবজেক্টে সংকলন করতে পারেন এবং এটি আপনার সি প্রকল্পের সাথে লিঙ্ক করতে পারেন। ভিজ্যুয়াল স্টুডিওতে এটি কীভাবে করা যায় তার জন্য নির্দেশাবলীর জন্য, আপনি এই নিবন্ধটি পড়তে পারেন । আপনার সি কোড থেকে ফাংশনটি কল করতে আপনি নীচের সি প্রোটোটাইপটি ব্যবহার করতে পারেন:

void simd_sort_6(char *values);

আপনার বিধানসভা স্তরের অন্যান্য প্রস্তাবের সাথে তুলনা করা হস্তক্ষেপ করবে। বাস্তবায়নের তুলনামূলক পারফরম্যান্সগুলি তাদের অন্তর্ভুক্ত করে না। এসএসই ব্যবহার করা যাই হোক না কেন ভাল লাগছে।
ক্রিস

ভবিষ্যতের গবেষণার আর একটি ক্ষেত্র হ'ল এই সমস্যার জন্য নতুন ইনটেল অ্যাভিএক্স নির্দেশিকাগুলির প্রয়োগ। বৃহত্তর 256-বিট ভেক্টর 8 ডিডাব্লোর্ডের জন্য যথেষ্ট বড়।
জো ক্রিভেলো

1
পরিবর্তে pxor / pinsrd xmm4, mem, 0, শুধু ব্যবহার movd!
পিটার কর্ডেস

14

পরীক্ষার কোডটি বেশ খারাপ; এটি প্রাথমিক অ্যারেটিকে উপচে ফেলেছে (লোকে এখানে সংকলক সতর্কতাগুলি পড়ে না?), প্রিন্টফ ভুল উপাদানগুলি মুদ্রণ করছে, এটি কোনও ভাল কারণে আরডিএসসির জন্য ব্যবহার করে, কেবলমাত্র একটি রান (!) আছে, যাচাই করে দেখার মতো কিছুই নেই শেষের ফলাফলগুলি আসলে সঠিক (তাই এটি খুব সহজেই কিছু ভুল করার জন্য "অনুকূলিতকরণ" খুব সহজ), অন্তর্ভুক্ত পরীক্ষাগুলি খুব উদ্দীপনাজনক (কোনও নেতিবাচক সংখ্যা নয়?) এবং সংকলকটিকে কেবল ডেড কোড হিসাবে পুরো ফাংশনটি ত্যাগ করা থেকে বিরত রাখার মতো কিছুই নেই।

বলা হচ্ছে, বিটোনিক নেটওয়ার্ক সমাধানে উন্নতি করা বেশ সহজ; কেবলমাত্র নূন্যতম / সর্বাধিক / সোয়াপ স্টাফ এ পরিবর্তন করুন

#define SWAP(x,y) { int tmp; asm("mov %0, %2 ; cmp %1, %0 ; cmovg %1, %0 ; cmovg %2, %1" : "=r" (d[x]), "=r" (d[y]), "=r" (tmp) : "0" (d[x]), "1" (d[y]) : "cc"); }

এবং এটি আমার কাছে প্রায় 65% দ্রুত আসে (দেবিয়ান জিসিসি 4.4.5 এর সাথে -O2, এএমডি 64, কোর আই 7)।


ঠিক আছে, পরীক্ষার কোডটি দরিদ্র। এটি উন্নত নির্দ্বিধায়। এবং হ্যাঁ, আপনি সমাবেশ কোড ব্যবহার করতে পারেন। কেন আপনি সমস্ত উপায়ে যাচ্ছেন না এবং x86 এসেম্বেলার ব্যবহার করে এটি পুরোপুরি কোড করছেন না? এটি কিছুটা কম পোর্টেবল হতে পারে তবে কেন বিরক্ত করবেন?

অ্যারে ওভারফ্লো লক্ষ্য করার জন্য ধন্যবাদ, আমি এটি সংশোধন করেছি। অন্যান্য লোকেরা এটি লক্ষ্য নাও করতে পারে কারণ অনুলিপি নেই এমন কপি / পেস্ট কোডের লিঙ্কটিতে ক্লিক করেছেন।
24:40

4
আপনার আসলে এমনকি এসেম্বলারের দরকার নেই; যদি আপনি কেবল সমস্ত চতুর কৌশলগুলি বাদ দেন, জিসিসি ক্রমটি সনাক্ত করবে এবং আপনার জন্য শর্তযুক্ত পদক্ষেপগুলি সন্নিবেশ করবে: # নির্ধারিত মিনিট (ক, খ) ((একটি <বি)? a: বি) # নির্ধারিত সর্বাধিক (ক, খ) ( (a <b)? b: a) # নির্ধারিত সোয়্যাপ (x, y) {int a = min (d [x], d [y]); int b = সর্বোচ্চ (d [x], d [y]); d [x] = ক; d [y] = খ; } এটি ইনলাইন asm বৈকল্পিকের তুলনায় কয়েক শতাংশ ধীর হতে পারে, তবে সঠিক বেঞ্চমার্কিংয়ের অভাবের কারণে এটি বলা শক্ত।
স্টেইনার এইচ। গাউনসন

3
… এবং পরিশেষে, যদি আপনার নম্বরগুলি ভাসমান হয়, এবং আপনাকে এনএএন ইত্যাদির বিষয়ে চিন্তা করতে হবে না, জিসিসি এটিকে মাইন / ম্যাক্সএস এসএসই নির্দেশিকায় রূপান্তর করতে পারে, যা এখনও 25% ডলার দ্রুত is মনোবল: চতুর বিটফিডলিং কৌশলগুলি ফেলে দিন এবং সংকলকটি এর কাজটি করতে দিন। :-)
স্টেইনার এইচ। গাউনসন

13

আমি সত্যিই প্রদত্ত সোয়াপ ম্যাক্রো পছন্দ করি:

#define min(x, y) (y ^ ((x ^ y) & -(x < y)))
#define max(x, y) (x ^ ((x ^ y) & -(x < y)))
#define SWAP(x,y) { int tmp = min(d[x], d[y]); d[y] = max(d[x], d[y]); d[x] = tmp; }

আমি একটি উন্নতি দেখছি (যা একটি ভাল সংকলক করতে পারে):

#define SWAP(x,y) { int tmp = ((x ^ y) & -(y < x)); y ^= tmp; x ^= tmp; }

আমরা কীভাবে ন্যূনতম এবং সর্বাধিক কাজ করে তা লক্ষ্য করি এবং সাধারণ উপ-এক্সপ্রেশনটি স্পষ্টভাবে টানতে পারি। এটি সর্বনিম্ন মিনিমাম এবং সর্বাধিক ম্যাক্রোগুলি সরিয়ে দেয়।


এটি তাদের পিছনে দিকে যায়, লক্ষ্য করুন যে d [y] সর্বাধিক পায় যা x ^ (সাধারণ subexpression)।
কেভিন স্টক

আমি একই জিনিস লক্ষ্য; আমি মনে করি আপনার প্রয়োগটি সঠিক হওয়ার জন্য আপনি (একই জন্য ) d[x]পরিবর্তে চান এবং এখানে অসমতার জন্য (হ্যাঁ, মিনিট / সর্বোচ্চ কোড থেকে আলাদা)। xyd[y] < d[x]
টাইলার

আমি আপনার অদলবদল দিয়ে চেষ্টা করেছি, তবে স্থানীয় অপ্টিমাইজেশনের বড় স্তরে নেতিবাচক প্রভাব রয়েছে (আমার ধারণা এটি নির্ভরতা প্রবর্তন করে)। এবং ফলাফল অন্যান্য অদলবদলের চেয়ে ধীর। তবে আপনি প্রস্তাবিত নতুন সমাধানের সাথে দেখতে পাচ্ছেন optim
ক্রিস

12

বেঞ্চমার্কিং এবং প্রকৃত সংকলক উত্পন্ন সমাবেশটি না দেখিয়ে কখনই মিনিমাম / সর্বাধিক অনুকূলিতকরণ করবেন না। যদি আমি শর্তসাপেক্ষে সরানোর নির্দেশাবলীর সাথে জিসিসিকে মিনিট অনুকূল করতে দিই তবে আমি একটি 33% স্পিডআপ পাই:

#define SWAP(x,y) { int dx = d[x], dy = d[y], tmp; tmp = d[x] = dx < dy ? dx : dy; d[y] ^= dx ^ tmp; }

(পরীক্ষার কোডে 280 বনাম 420 চক্র)। সর্বোচ্চ দিয়ে?: কমবেশি একইরকম, প্রায় গোলমালে হারিয়ে গেছে, তবে উপরেরটি কিছুটা দ্রুত। এই সোয়্যাপটি জিসিসি এবং কলং উভয়ের সাথেই দ্রুত।

সংকলকগণও রেজিস্ট্রার বরাদ্দ এবং উপনাম বিশ্লেষণে একটি ব্যতিক্রমী কাজ করছেন, কার্যকরভাবে d [x] কে স্থানীয় ভেরিয়েবলের সম্মুখভাগে সরিয়ে নিয়েছেন এবং কেবল শেষে স্মৃতিতে অনুলিপি করছেন। বাস্তবে, তারা সম্পূর্ণরূপে স্থানীয় ভেরিয়েবলগুলি (যেমন: কাজ করে) এর চেয়ে আরও ভাল করেd0 = d[0], d1 = d[1], d2 = d[2], d3 = d[3], d4 = d[4], d5 = d[5] ) এর । আমি এটি লিখছি কারণ আপনি দৃ optim় অপ্টিমাইজেশন ধরে নিচ্ছেন এবং এখনও কমপক্ষে / সর্বাধিকের ক্ষেত্রে সংকলককে আউটসামার্ট করার চেষ্টা করছেন। :)

যাইহোক, আমি কলং এবং জিসিসি চেষ্টা করেছি। তারা একই অপটিমাইজেশন করে তবে সময়সূচী পার্থক্যের কারণে দু'জনের ফলাফলের কিছুটা ভিন্নতা থাকে, যা সত্য বা ধীরতর বলতে পারে না say সিসি নেটওয়ার্কগুলিতে জিসিসি দ্রুততর, চতুষ্কোণীয় ধরণের বাজেটে।

কেবল সম্পূর্ণতার জন্য, নিবন্ধিত বুদ্বুদ সাজানোর এবং সন্নিবেশের ধরণগুলিও সম্ভব। এখানে বুদ্বুদ সাজান:

SWAP(0,1); SWAP(1,2); SWAP(2,3); SWAP(3,4); SWAP(4,5);
SWAP(0,1); SWAP(1,2); SWAP(2,3); SWAP(3,4);
SWAP(0,1); SWAP(1,2); SWAP(2,3);
SWAP(0,1); SWAP(1,2);
SWAP(0,1);

এবং এখানে সন্নিবেশ সাজান:

//#define ITER(x) { if (t < d[x]) { d[x+1] = d[x]; d[x] = t; } }
//Faster on x86, probably slower on ARM or similar:
#define ITER(x) { d[x+1] ^= t < d[x] ? d[x] ^ d[x+1] : 0; d[x] = t < d[x] ? t : d[x]; }
static inline void sort6_insertion_sort_unrolled_v2(int * d){
    int t;
    t = d[1]; ITER(0);
    t = d[2]; ITER(1); ITER(0);
    t = d[3]; ITER(2); ITER(1); ITER(0);
    t = d[4]; ITER(3); ITER(2); ITER(1); ITER(0);
    t = d[5]; ITER(4); ITER(3); ITER(2); ITER(1); ITER(0);

এই সন্নিবেশ বাছাইটি ড্যানিয়েল স্টুটজবাচের চেয়ে দ্রুত এবং এটি একটি জিপিইউ বা ভবিষ্যদ্বাণী সহ একটি কম্পিউটারে খুব ভাল কারণ আইটিইআরটি কেবলমাত্র 3 টি নির্দেশাবলীর সাথে করা যেতে পারে (বনাম 4 সুইডাপের জন্য)। উদাহরণস্বরূপ, t = d[2]; ITER(1); ITER(0);এআরএম সমাবেশে লাইনটি এখানে রয়েছে :

    MOV    r6, r2
    CMP    r6, r1
    MOVLT  r2, r1
    MOVLT  r1, r6
    CMP    r6, r0
    MOVLT  r1, r0
    MOVLT  r0, r6

ছয় উপাদানগুলির জন্য সন্নিবেশ বাছাইটি বাছাই করা নেটওয়ার্কের সাথে প্রতিযোগিতামূলক (12 স্ব্যাপগুলি বনাম 15 পুনরাবৃত্তিগুলি 4 টি নির্দেশনা / অদলবদল বনাম 3 নির্দেশাবলী / পুনরাবৃত্তির ভারসাম্য); বুদ্বুদ সাজানোর অবশ্যই ধীর। আকারটি বড় হওয়ার পরে এটি সত্য হবে না, যেহেতু সারণি নেটওয়ার্কগুলি O (n লগ এন) বাছাই করার সময় সন্নিবেশ সাজানো O (n ^ 2) হয়।


1
কম-বেশি সম্পর্কিত: আমি জিসিসিতে একটি প্রতিবেদন জমা দিয়েছি যাতে এটি সরাসরি সংকলকটিতে অপ্টিমাইজেশন বাস্তবায়ন করতে পারে। এটি সম্পন্ন হবে তা নিশ্চিত নয়, তবে কীভাবে এটি বিকশিত হয় তা আপনি অন্তত অনুসরণ করতে পারেন।
মরউভেন

11

আমি একটি পিপিসি আর্কিটেকচার মেশিনে পরীক্ষার স্যুটটি পোর্ট করেছি আমি সনাক্ত করতে পারি না (কোডের স্পর্শ করতে হয়নি, কেবল পরীক্ষার পুনরাবৃত্তি বৃদ্ধি করতে হবে, মোডগুলির সাথে দূষণকারী ফলাফল এড়াতে 8 টি পরীক্ষার কেস ব্যবহার করুন এবং x86 নির্দিষ্ট rdtsc প্রতিস্থাপন করুন):

Qsort লাইব্রেরি ফাংশনে সরাসরি কল : 101 101

নিষ্পাপ বাস্তবায়ন (সন্নিবেশ সাজানোর) : 299

সন্নিবেশ সাজান (ড্যানিয়েল স্টুটজবাচ) : 108

সন্নিবেশ বাছাই করুন আনরোলড : ৫১

নেটওয়ার্ক বাছাই করা (ড্যানিয়েল স্টুটজবাচ) : 26

নেটওয়ার্ক বাছাই (পল আর) : 85

নেটওয়ার্কগুলি 12 দ্রুত স্বাপের মাধ্যমে বাছাই করা হচ্ছে : 117

বাছাই নেটওয়ার্ক 12 পুনরায় সাজানো সোয়াপ : 116

র‌্যাঙ্ক অর্ডার : 56


1
সত্যিই আকর্ষণীয়। দেখে মনে হচ্ছে শাখাবিহীন অদলবদলটি পিপিসিতে একটি খারাপ ধারণা। এটি একটি সংকলক সম্পর্কিত প্রভাবও হতে পারে। কোনটি ব্যবহৃত হয়েছিল?

এটি জিসিসি সংকলকের একটি শাখা - ন্যূনতম, সর্বাধিক যুক্তি সম্ভবত শাখাবিহীন নয় - আমি বিচ্ছিন্নতা পরীক্ষা করব এবং আপনাকে জানাবো, তবে কম্পাইলার যদি x <y এর মতো কিছু সহ যথেষ্ট চৌকস না হয় তবে এখনও একটি শাখা হয়ে যায় - x86 এ / x64 সিএমওভ নির্দেশনা এটি এড়াতে পারে তবে পিপিসিতে স্থির পয়েন্টের মানগুলির জন্য এমন কোনও নির্দেশ নেই, কেবলমাত্র ভাসমান। আমি আগামীকাল এটির সাথে ছিটকে পড়তে পারি এবং আপনাকে জানাতে পারি - আমার মনে আছে উইন্যাম্প এভিএস উত্সে অনেক সহজ শাখাবিহীন ন্যূনতম / সর্বোচ্চ ছিল, তবে এটি কেবল ভাসমানদের জন্যই ছিল - তবে সত্যিকারের শাখাবিহীন পদ্ধতির দিকে এটি শুরু হতে পারে।
ঝেরিকো

4
এখানে একটি branchless মিনিট / পিপিসি, সর্বোচ্চ স্বাক্ষরবিহীন ইনপুট সঙ্গে আছেন subfc r5,r4,r3; subfe r6,r6,r6; andc r6,r5,r6; add r4,r6,r4; subf r3,r6,r3। আর 3 / আর 4 ইনপুট হয়, আর 5 / আর 6 স্ক্র্যাচ রেজিস্টার হয়, আউটপুট আর 3 এ সর্বনিম্ন পায় এবং আর 4 সর্বোচ্চ হয় gets এটি হাত দিয়ে শালীনভাবে নির্ধারণযোগ্য হওয়া উচিত। আমি এটি জিএনইউ সুপারপটিমাইজারের সাথে পেয়েছি, 4-নির্দেশনা নূন্যতম এবং সর্বাধিক সিকোয়েন্স থেকে শুরু করে এবং দু'জনের জন্য ম্যানুয়ালি খুঁজছি যা সংযুক্ত হতে পারে। স্বাক্ষরিত ইনপুটগুলির জন্য, আপনি অবশ্যই শুরুতে সমস্ত উপাদানগুলিতে 0x80000000 যুক্ত করতে পারেন এবং এটিকে আবার শেষে বিয়োগ করতে পারেন এবং তারপরে সাইন ইন না করে কাজ করুন।
পাওলো বনজিণী

7

একটি এক্সওআর অদলবদল আপনার অদলবদল কার্যের ক্ষেত্রে কার্যকর হতে পারে।

void xorSwap (int *x, int *y) {
     if (*x != *y) {
         *x ^= *y;
         *y ^= *x;
         *x ^= *y;
     }
 }

যদি আপনার কোডটিতে খুব বেশি বিচ্যুতি ঘটতে পারে তবে আপনার গ্যারান্টি থাকলে আপনার সমস্ত কালি অনন্য this এটি সহজেই কার্যকর হতে পারে।


1
xor swap এছাড়াও সমান মানের জন্য কাজ করে ... x ^ = y সেট করে x থেকে 0, y ^ = x পাতা y হিসাবে y (== x), x ^ = y সেট করে x থেকে y
riেরিকো

11
যখন এটি কাজ করে না তখন কখন xএবং yএকই স্থানে নির্দেশ করা হয়।
hobbs

যাইহোক, বাছাই নেটওয়ার্কগুলির সাথে ব্যবহার করার সময় আমরা কখনই x এবং y উভয়কে একই অবস্থানটির দিকে নির্দেশ করে কল করি না। শাখাবিহীন অদলবদলের মতো একই প্রভাব পাওয়ার জন্য যাচাই বাছাইয়ের উপায় খুঁজে পাওয়া এখনও বেশি। আমি এটি অর্জন করার জন্য একটি ধারণা আছে।
kriss

5

এটিতে আমার হাতটি চেষ্টা করার এবং এই উদাহরণগুলি থেকে শিখার অপেক্ষায় রয়েছি, তবে প্রথমে আমার 1.5 গিগাহার্টজ পিপিসি পাওয়ারবুক জি 4 ডাব্লু / 1 জিবি ডিডিআর র‌্যামের কিছু সময়। (আমি পিপিসির জন্য http://www.mcs.anl.gov/~kazutomo/rdtsc.html থেকে অনুরূপ একটি rdtsc- জাতীয় টাইমার ধার নিয়েছি জন্য আমি সময় ।) আমি কয়েকবার প্রোগ্রামটি এবং নিখুঁত ফলাফলগুলি পরিবর্তিত হয়েছে তবে ধারাবাহিকভাবে দ্রুততম পরীক্ষাটি ছিল "সন্নিবেশ বাছাই (ড্যানিয়েল স্টুটজবাচ)", "সন্নিবেশ সাজান আনরোলড করা" এর নিকটবর্তী দ্বিতীয় সাথে।

এখানে সময়ের শেষ সেট:

**Direct call to qsort library function** : 164
**Naive implementation (insertion sort)** : 138
**Insertion Sort (Daniel Stutzbach)**     : 85
**Insertion Sort Unrolled**               : 97
**Sorting Networks (Daniel Stutzbach)**   : 457
**Sorting Networks (Paul R)**             : 179
**Sorting Networks 12 with Fast Swap**    : 238
**Sorting Networks 12 reordered Swap**    : 236
**Rank Order**                            : 116

4

এই থ্রেডে আমার অবদান এখানে: অনন্য মান সহ 6 সদস্যের ইনট ভেক্টর (ভাল্প) এর জন্য একটি অনুকূলিত 1, 4 গ্যাপ শেলসোর্ট।

void shellsort (int *valp)
{      
  int c,a,*cp,*ip=valp,*ep=valp+5;

  c=*valp;    a=*(valp+4);if (c>a) {*valp=    a;*(valp+4)=c;}
  c=*(valp+1);a=*(valp+5);if (c>a) {*(valp+1)=a;*(valp+5)=c;}

  cp=ip;    
  do
  {
    c=*cp;
    a=*(cp+1);
    do
    {
      if (c<a) break;

      *cp=a;
      *(cp+1)=c;
      cp-=1;
      c=*cp;
    } while (cp>=valp);
    ip+=1;
    cp=ip;
  } while (ip<ep);
}

ডুয়াল-কোর অ্যাথলন এম300 @ 2 গিগাহার্জ (ডিডিআর 2 মেমরি) সহ আমার এইচপি ডিভি 7-3010so ল্যাপটপে এটি 165 ঘড়ির চক্রটিতে সম্পাদন করে। এটি প্রতিটি অনন্য অনুক্রমের সময় নির্ধারণ থেকে গড় গণনা করা হয় (সব মিলিয়ে 6! / 720) ওপেন ওয়াটকম 1.8 ব্যবহার করে উইন 32 এ সংকলিত। লুপটি মূলত একটি সন্নিবেশ বাছাই এবং 16 টি নির্দেশনা / 37 বাইট দীর্ঘ।

সংকলনের জন্য আমার কাছে 64-বিট পরিবেশ নেই।


সুন্দর। আমি এটিকে দীর্ঘ পরীক্ষার জন্য যুক্ত করব
ক্রিস

3

যদি সন্নিবেশ সাজানোর বিষয়টি এখানে যথাযথভাবে প্রতিযোগিতামূলক হয় তবে আমি শেলসোর্ট চেষ্টা করার পরামর্শ দেব। আমি ভীত। উপাদান সম্ভবত এটির মধ্যে সেরা হওয়ার জন্য খুব সামান্য, তবে এটি চেষ্টা করার মতো হতে পারে।

উদাহরণস্বরূপ কোড, অপরিবর্তিত, Undebugged ইত্যাদি আপনি সর্বোত্তম সন্ধানের জন্য inc = 4 এবং ইনক - = 3 ক্রম টিউন করতে চান (উদাহরণস্বরূপ inc = 2, Inc - = 1 চেষ্টা করুন)।

static __inline__ int sort6(int * d) {
    char j, i;
    int tmp;
    for (inc = 4; inc > 0; inc -= 3) {
        for (i = inc; i < 5; i++) {
            tmp = a[i];
            j = i;
            while (j >= inc && a[j - inc] > tmp) {
                a[j] = a[j - inc];
                j -= inc;
            }
            a[j] = tmp;
        }
    }
}

আমি মনে করি না এটি জিতবে, তবে কেউ যদি 10 টি উপাদান বাছাই সম্পর্কে কোনও প্রশ্ন পোস্ট করেন, তবে কে জানেন ...

উইকিপিডিয়া অনুসারে এটি এমনকি বাছাই নেটওয়ার্কগুলির সাথে একত্রিত হতে পারে: প্র্যাট, ভি (1979)। শেলসোর্ট এবং বাছাই করা নেটওয়ার্কগুলি (কম্পিউটার বিজ্ঞানে বিশিষ্ট গবেষণামূলক প্রবন্ধ)। মাল্য। আইএসবিএন 0-824-04406-1


কিছু বাস্তবায়ন প্রস্তাব নির্দ্বিধায় :-)
ক্রিস

প্রস্তাব যুক্ত হয়েছে। বাগগুলি উপভোগ করুন।
gcp

3

আমি জানি যে আমি অতি দেরিতে, তবে আমি কিছু আলাদা সমাধান নিয়ে পরীক্ষা করতে আগ্রহী। প্রথমে, আমি সেই পেস্টটি পরিষ্কার করেছি, এটি সংকলন করেছি এবং এটিকে একটি ভান্ডারে রেখেছি। আমি কিছু অনাকাঙ্ক্ষিত সমাধানকে মৃতপ্রান্ত হিসাবে রেখেছি যাতে অন্যরা চেষ্টা না করে। এর মধ্যে আমার প্রথম সমাধান ছিল, যা x1> x2 একবার গণনা করা হয়েছিল তা নিশ্চিত করার চেষ্টা করেছিল। অপ্টিমাইজেশনের পরে, এটি অন্যান্য, সাধারণ সংস্করণগুলির চেয়ে দ্রুত নয়।

আমি র‌্যাঙ্ক অর্ডার সাজানোর একটি লুপিং সংস্করণ যুক্ত করেছি, যেহেতু আমার এই অধ্যয়নের নিজস্ব প্রয়োগটি 2-8 আইটেমগুলি বাছাই করার জন্য, সুতরাং যেহেতু একটি পরিবর্তনশীল সংখ্যা যুক্তিযুক্ত রয়েছে তাই একটি লুপ প্রয়োজনীয়। এই কারণেই আমি বাছাই করা নেটওয়ার্ক সমাধানগুলিকে উপেক্ষা করেছি।

পরীক্ষার কোডটি পরীক্ষা করে দেখেনি যে সদৃশগুলি সঠিকভাবে পরিচালনা করা হয়েছিল, সুতরাং বিদ্যমান সমাধানগুলি সমস্ত সঠিক ছিল, আমি নকলকে সঠিকভাবে পরিচালনা করা হয়েছিল তা নিশ্চিত করার জন্য আমি পরীক্ষার কোডে একটি বিশেষ কেস যুক্ত করেছি।

তারপরে, আমি একটি সন্নিবেশ বাছাই লিখেছিলাম যা পুরোপুরি AVX রেজিস্টারে থাকে। আমার মেশিনে এটি অন্যান্য সন্নিবেশের ধরণের চেয়ে 25% দ্রুত তবে র‌্যাঙ্ক ক্রমের চেয়ে 100% ধীর। আমি নিখুঁতভাবে পরীক্ষার জন্য এটি করেছি এবং সন্নিবেশ সাজানোর শাখার কারণে এটি আরও ভাল হওয়ার কোনও প্রত্যাশা ছিল না।

static inline void sort6_insertion_sort_avx(int* d) {
    __m256i src = _mm256_setr_epi32(d[0], d[1], d[2], d[3], d[4], d[5], 0, 0);
    __m256i index = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
    __m256i shlpermute = _mm256_setr_epi32(7, 0, 1, 2, 3, 4, 5, 6);
    __m256i sorted = _mm256_setr_epi32(d[0], INT_MAX, INT_MAX, INT_MAX,
            INT_MAX, INT_MAX, INT_MAX, INT_MAX);
    __m256i val, gt, permute;
    unsigned j;
     // 8 / 32 = 2^-2
#define ITER(I) \
        val = _mm256_permutevar8x32_epi32(src, _mm256_set1_epi32(I));\
        gt =  _mm256_cmpgt_epi32(sorted, val);\
        permute =  _mm256_blendv_epi8(index, shlpermute, gt);\
        j = ffs( _mm256_movemask_epi8(gt)) >> 2;\
        sorted = _mm256_blendv_epi8(_mm256_permutevar8x32_epi32(sorted, permute),\
                val, _mm256_cmpeq_epi32(index, _mm256_set1_epi32(j)))
    ITER(1);
    ITER(2);
    ITER(3);
    ITER(4);
    ITER(5);
    int x[8];
    _mm256_storeu_si256((__m256i*)x, sorted);
    d[0] = x[0]; d[1] = x[1]; d[2] = x[2]; d[3] = x[3]; d[4] = x[4]; d[5] = x[5];
#undef ITER
}

তারপরে, আমি এভিএক্স ব্যবহার করে র‌্যাঙ্ক অর্ডার বাছাই করেছি। এটি অন্যান্য র‌্যাঙ্ক-অর্ডার সমাধানগুলির গতির সাথে মেলে, তবে দ্রুত নয়। এখানে সমস্যাটি হ'ল আমি কেবলমাত্র AVX এর সাথে সূচকগুলি গণনা করতে পারি এবং তারপরে আমাকে সূচকের একটি সারণী তৈরি করতে হবে। এটি কারণ উত্স ভিত্তিকের চেয়ে গণনা গন্তব্য ভিত্তিক। উত্স-ভিত্তিক সূচকগুলি থেকে গন্তব্য-ভিত্তিক সূচকগুলিতে রূপান্তর দেখুন

static inline void sort6_rank_order_avx(int* d) {
    __m256i ror = _mm256_setr_epi32(5, 0, 1, 2, 3, 4, 6, 7);
    __m256i one = _mm256_set1_epi32(1);
    __m256i src = _mm256_setr_epi32(d[0], d[1], d[2], d[3], d[4], d[5], INT_MAX, INT_MAX);
    __m256i rot = src;
    __m256i index = _mm256_setzero_si256();
    __m256i gt, permute;
    __m256i shl = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 6, 6);
    __m256i dstIx = _mm256_setr_epi32(0,1,2,3,4,5,6,7);
    __m256i srcIx = dstIx;
    __m256i eq = one;
    __m256i rotIx = _mm256_setzero_si256();
#define INC(I)\
    rot = _mm256_permutevar8x32_epi32(rot, ror);\
    gt = _mm256_cmpgt_epi32(src, rot);\
    index = _mm256_add_epi32(index, _mm256_and_si256(gt, one));\
    index = _mm256_add_epi32(index, _mm256_and_si256(eq,\
                _mm256_cmpeq_epi32(src, rot)));\
    eq = _mm256_insert_epi32(eq, 0, I)
    INC(0);
    INC(1);
    INC(2);
    INC(3);
    INC(4);
    int e[6];
    e[0] = d[0]; e[1] = d[1]; e[2] = d[2]; e[3] = d[3]; e[4] = d[4]; e[5] = d[5];
    int i[8];
    _mm256_storeu_si256((__m256i*)i, index);
    d[i[0]] = e[0]; d[i[1]] = e[1]; d[i[2]] = e[2]; d[i[3]] = e[3]; d[i[4]] = e[4]; d[i[5]] = e[5];
}

রেপো এখানে পাওয়া যাবে: https://github.com/eyepatchParrot/sort6/


1
আপনি vmovmskpsবিটস্ক্যান ( ffs) ফলাফলটি ডান-শিফ্ট করার প্রয়োজনীয়তা এড়িয়ে, পূর্ণসংখ্যক ভেক্টরগুলিতে (অভ্যন্তরীণ সুখী রাখতে একটি castালাই সহ ) ব্যবহার করতে পারেন ।
পিটার কর্ডেস

1
আপনি শর্তসাপেক্ষে এটির মুখোশ পরিবর্তে বিয়োগ করে cmpgtফলাফলের ভিত্তিতে 1 যুক্ত করতে পারেন । যেমন করেset1(1)index = _mm256_sub_epi32(index, gt)index -= -1 or 0;
পিটার কর্ডেস

1
eq = _mm256_insert_epi32(eq, 0, I)কোনও উপাদানকে শূন্য করার কার্যকর উপায় নয় যদি এটি লিখিত হিসাবে সংকলিত হয় (বিশেষত নিম্ন 4 এর বাইরের উপাদানগুলির জন্য, কারণ vpinsrdএটি কেবলমাত্র একটি এক্সএমএম গন্তব্য সহ উপলব্ধ; 3 টিরও বেশি সূচকগুলি অনুকরণ করতে হবে)। পরিবর্তে, _mm256_blend_epi32( vpblendd) একটি শূন্য ভেক্টর সহ। vpblenddহ'ল একটি একক-উওপ নির্দেশ যা কোনও বন্দর চলতে পারে, বনাম একটি শিফেল যা ইন্টেল সিপিইউতে পোর্ট 5 প্রয়োজন। ( agner.org/optimize )।
পিটার কর্ডেস

1
এছাড়াও, আপনি rotএকই উত্স থেকে বিভিন্ন শ্যাফেলগুলি সহ ভেক্টরগুলি উত্পন্ন করার কথা বিবেচনা করতে পারেন , বা একটি লেন-ক্রসিং শ্যাফেল (3 চক্র ল্যাটেন্সি) এর মাধ্যমে একক ডিপ চেইনের পরিবর্তে, আপনি পর্যায়ক্রমে ব্যবহার করেন এমন সমান্তরালে কমপক্ষে 2 ডিপ চেইন চালান। এটি এক ধরণের মধ্যে আইএলপি বাড়িয়ে তুলবে। 2 ডিপ চেইন ভেক্টর ধ্রুবকের সংখ্যা যুক্তিসঙ্গত সংখ্যায় সীমাবদ্ধ করে, একটি ঘোরানোর জন্য কেবল 2: 1 এবং 2 টি ঘোরানো পদক্ষেপের জন্য একত্রিত।
পিটার কর্ডেস

2

এই প্রশ্নটি বেশ পুরানো হয়ে উঠছে, তবে আমাকে আসলে আজকের দিনে একই সমস্যাটি সমাধান করতে হয়েছিল: ছোট অ্যারেগুলিকে বাছাই করার জন্য দ্রুত অ্যাগ্রোরিদম। আমি ভেবেছিলাম আমার জ্ঞান ভাগ করে নেওয়া ভাল ধারণা হবে। আমি প্রথমে বাছাই করা নেটওয়ার্কগুলি ব্যবহার করে শুরু করার সময়, আমি শেষ পর্যন্ত অন্যান্য অ্যালগরিদমগুলি সন্ধান করতে সক্ষম হয়েছি যার জন্য values ​​টি মানের প্রতিটি অনুক্রম সাজানোর জন্য মোট তুলনা সংখ্যা বাছাই করা নেটওয়ার্কগুলির তুলনায় ছোট এবং সন্নিবেশ সাজানোর চেয়ে ছোট ছিল। আমি অদলবদলের সংখ্যা গণনা করি নি; আমি এটি প্রায় সমতুল্য (কখনও কখনও কিছুটা বেশি উচ্চতর) আশা করব expect

অ্যালগরিদমটি অ্যালগরিদম sort6ব্যবহার করে sort4যা অ্যালগরিদম ব্যবহার করে sort3। এখানে কিছু হালকা সি ++ আকারে বাস্তবায়ন করা হয়েছে (মূলটি টেমপ্লেট-ভারী যাতে এটি কোনও র্যান্ডম-অ্যাক্সেস পুনরুক্তি এবং কোনও উপযুক্ত তুলনা ফাংশন সহ কাজ করতে পারে)।

3 টি মান বাছাই করা হচ্ছে

নিম্নলিখিত অ্যালগরিদম একটি নিয়ন্ত্রিত সন্নিবেশ সাজানো। যখন দুটি অদলবদল (6 অ্যাসাইনমেন্ট) সম্পাদন করতে হয়, এটি পরিবর্তে 4 অ্যাসাইনমেন্ট ব্যবহার করে:

void sort3(int* array)
{
    if (array[1] < array[0]) {
        if (array[2] < array[0]) {
            if (array[2] < array[1]) {
                std::swap(array[0], array[2]);
            } else {
                int tmp = array[0];
                array[0] = array[1];
                array[1] = array[2];
                array[2] = tmp;
            }
        } else {
            std::swap(array[0], array[1]);
        }
    } else {
        if (array[2] < array[1]) {
            if (array[2] < array[0]) {
                int tmp = array[2];
                array[2] = array[1];
                array[1] = array[0];
                array[0] = tmp;
            } else {
                std::swap(array[1], array[2]);
            }
        }
    }
}

এটি কিছুটা জটিল বলে মনে হচ্ছে কারণ এই অ্যারেটির প্রতিটি সম্ভাব্য ক্রমান্বনের জন্য বাছাইয়ের কমপক্ষে একটি শাখা রয়েছে, তিনটি মানকে সাজানোর জন্য 2 values ​​3 তুলনা এবং সর্বাধিক 4 অ্যাসাইনমেন্ট ব্যবহার করে।

4 টি মান বাছাই করা হচ্ছে

এটির sort3পরে কলগুলি অ্যারের শেষ উপাদানটির সাথে একটি নিবন্ধিত সন্নিবেশ সাজান:

void sort4(int* array)
{
    // Sort the first 3 elements
    sort3(array);

    // Insert the 4th element with insertion sort 
    if (array[3] < array[2]) {
        std::swap(array[2], array[3]);
        if (array[2] < array[1]) {
            std::swap(array[1], array[2]);
            if (array[1] < array[0]) {
                std::swap(array[0], array[1]);
            }
        }
    }
}

এই অ্যালগরিদম 3 থেকে 6 টি তুলনা এবং সর্বাধিক 5 টি অদলবদল করে। একটি সন্নিবেশ সাজানোর তালিকাভুক্ত করা সহজ, তবে আমরা শেষ বাছাইয়ের জন্য অন্য একটি অ্যালগরিদম ব্যবহার করব ...

Values ​​টি মান বাছাই করা হচ্ছে

এইটি আমি ডাবল সন্নিবেশ সাজানোর জন্য যা বলেছি তার একটি নিবন্ধবিহীন সংস্করণ ব্যবহার করে । নামটি দুর্দান্ত নয় তবে এটি বেশ বর্ণনামূলক, এটি কীভাবে এটি কাজ করে তা এখানে:

  • অ্যারের প্রথম এবং শেষ উপাদানগুলি বাদ দিয়ে সবকিছু সাজান।
  • প্রথমটি শেষের চেয়ে বড় হলে অ্যারের উপাদানগুলিকে অদলবদল করুন।
  • সামনে থেকে সাজানো ক্রমের মধ্যে প্রথম উপাদানটি প্রবেশ করুন এবং পিছন থেকে শেষ উপাদানটি .োকান।

অদলবদলের পরে প্রথম উপাদানটি সর্বশেষের চেয়ে সর্বদা ছোট থাকে, যার অর্থ এটি বাছাই করা অনুক্রমের মধ্যে সন্নিবেশ করানোর সময় দু'টি উপাদানকে সর্বাধিক সন্নিবেশ করানোর জন্য N তুলনার চেয়ে বেশি কিছু থাকবে না: উদাহরণস্বরূপ, যদি প্রথম উপাদানটি তৃতীয় অবস্থানে sertোকানো হয়েছে, তারপরে শেষটি 4 তম অবস্থানের চেয়ে কম sertedোকানো যাবে না।

void sort6(int* array)
{
    // Sort everything but first and last elements
    sort4(array+1);

    // Switch first and last elements if needed
    if (array[5] < array[0]) {
        std::swap(array[0], array[5]);
    }

    // Insert first element from the front
    if (array[1] < array[0]) {
        std::swap(array[0], array[1]);
        if (array[2] < array[1]) {
            std::swap(array[1], array[2]);
            if (array[3] < array[2]) {
                std::swap(array[2], array[3]);
                if (array[4] < array[3]) {
                    std::swap(array[3], array[4]);
                }
            }
        }
    }

    // Insert last element from the back
    if (array[5] < array[4]) {
        std::swap(array[4], array[5]);
        if (array[4] < array[3]) {
            std::swap(array[3], array[4]);
            if (array[3] < array[2]) {
                std::swap(array[2], array[3]);
                if (array[2] < array[1]) {
                    std::swap(array[1], array[2]);
                }
            }
        }
    }
}

Values ​​টি মানের প্রতিটি ক্রমান্বয়ে আমার পরীক্ষাগুলি কখনও দেখায় যে এই অ্যালগরিদম সর্বদা and থেকে ১৩ তুলনা করে। আমি সম্পাদিত অদলবদলের সংখ্যা গণনা করি নি, তবে আমি সবচেয়ে খারাপ ক্ষেত্রে এটি 11 এর চেয়ে বেশি হওয়ার আশা করি না।

আমি আশা করি যে এটি সহায়তা করে, এমনকি যদি এই প্রশ্নটি প্রকৃত সমস্যার প্রতিনিধিত্ব নাও করে :)

সম্পাদনা: সরবরাহিত বেঞ্চমার্কে রাখার পরে, বেশিরভাগ আকর্ষণীয় বিকল্পের চেয়ে এটি ক্লিয়ার ধীর ary এটি অনিবন্ধিত সন্নিবেশ সাজানোর চেয়ে কিছুটা ভাল সঞ্চালন করতে ঝোঁক, তবে এটি এটি বেশ বেশি। মূলত, এটি পূর্ণসংখ্যার জন্য সর্বোত্তম বাছাই নয় তবে ব্যয়বহুল তুলনা অপারেশন সহ ধরণের জন্য এটি আকর্ষণীয় হতে পারে।


এগুলি দুর্দান্ত। যেহেতু সমস্যাটি সমাধান হয়েছে বহু দশক পুরানো, সম্ভবত এটি পুরানো একটি সি প্রোগ্রামিং, যে প্রশ্নটি এখন প্রায় 5 বছর ধরে তেমন প্রাসঙ্গিক বলে মনে হচ্ছে না।
ক্রিস 12

অন্যান্য উত্তরগুলি কীভাবে সময়সীম হয় সেদিকে আপনার নজর রাখা উচিত। মুল বক্তব্যটি হ'ল এই জাতীয় ছোট ডেটাसेट গণনা তুলনা বা এমনকি তুলনা এবং অদলবদল আসলেই বলে না যে একটি অ্যালগরিদম কী দ্রুত হয় (মূলত 6 ints বাছাই করা সর্বদা ও (1) কারণ ও (6 * 6) ও (1))। পূর্বের প্রস্তাবিত সমাধানগুলির বর্তমান দ্রুততমটি তাত্ক্ষণিকভাবে একটি বড় তুলনা (রেক্সেরার দ্বারা) ব্যবহার করে প্রতিটি মানের অবস্থানটি সন্ধান করছে।
ক্রিসস

@ ক্রিসস এখন এটি কি দ্রুত? ফলাফলগুলি আমার পড়া থেকে, বাছাই করার নেটওয়ার্কগুলির পদ্ধতিরটি আমার কাছে সবচেয়ে দ্রুত ছিল। এটিও সত্য যে আমার সমাধানটি আমার জেনেরিক লাইব্রেরি থেকে আসে এবং আমি সবসময় পূর্ণসংখ্যার তুলনা করি না, তুলনা করার জন্যও সর্বদা ব্যবহার করি না operator<। তুলনা এবং অদলবদলের উদ্দেশ্য গণনা ছাড়াও, আমি আমার অ্যালগোরিদমগুলিকেও যথাযথভাবে সময় দিয়েছি; এই সমাধানটি দ্রুততম জেনেরিক ছিল তবে আমি @ রেক্সকারের একটিটি মিস করেছি। এটি চেষ্টা করবে :)
মরউভেন

রেক্সকারার (অর্ডার র্যাঙ্ক) দ্বারা সমাধানটি জিসিসি সংকলক ৪.২.৩ (এবং জিসিসি ৪.৯ হিসাবে দ্বিতীয় সেরাের চেয়ে প্রায় দ্বিগুণ দ্রুততর হয়েছে) থেকে এক্স 86 আর্কিটেকচারে দ্রুততম হয়ে ওঠে। তবে এটি ভারী সংকলক অপটিমাইজেশনের উপর নির্ভরশীল এবং অন্যান্য আর্কিটেকচারের ক্ষেত্রে এটি সত্য নাও হতে পারে।
ক্রিস

@ ক্রিসস এটি জানতে আকর্ষণীয়। এবং আমি সত্যিই আবার আরও পার্থক্য করতে পারে -O3। আমার ধারণা আমি তখন আমার বাছাই করা লাইব্রেরির জন্য অন্য কৌশল গ্রহণ করব: কম সংখ্যার তুলনা, স্বল্প সংখ্যার অদলবদল বা সম্ভাব্য সেরা পারফরম্যান্সের জন্য তিন ধরণের অ্যালগরিদম সরবরাহ করা। কমপক্ষে, যা ঘটে তা পাঠকের পক্ষে স্বচ্ছ হবে। আপনার অন্তর্দৃষ্টি জন্য ধন্যবাদ :)
মরওভেন

1

আমি বিশ্বাস করি আপনার প্রশ্নের দুটি অংশ রয়েছে।

  • প্রথমটি হচ্ছে সর্বোত্তম অ্যালগরিদম নির্ধারণ করা। এটি করা হয় - কমপক্ষে এক্ষেত্রে - প্রতিটি সম্ভাব্য ক্রম দিয়ে লুপ করে (এমন অনেকগুলি নেই) যা আপনাকে তুলনা এবং অদলবদলের সঠিক ন্যূনতম, সর্বোচ্চ, গড় এবং মান বিচ্যুতি গণনা করতে দেয় to রানার-আপ বা দু'হাত কার্যকরও।
  • দ্বিতীয়টি হল অ্যালগরিদমকে অনুকূল করা। পাঠ্যপুস্তকের কোড উদাহরণগুলিকে রূপান্তর করতে অনেক কিছুই করা যায় এবং বাস্তব জীবনের অ্যালগরিদমগুলি হেলান। আপনি যদি বুঝতে পারেন যে একটি অ্যালগরিদম প্রয়োজনীয় পরিমাণে অনুকূলিত করা যায় না, তবে রানার-আপ চেষ্টা করুন।

খালি পাইপলাইনগুলি সম্পর্কে আমি খুব বেশি চিন্তা করব না (বর্তমান x86 ধরে): শাখার পূর্বাভাসটি অনেক দূর এগিয়েছে। আমি যে বিষয়ে উদ্বিগ্ন হব তা নিশ্চিত করা হয় যে কোড এবং ডেটা প্রতিটি ক্যাশে লাইনে ফিট থাকে (কোডের জন্য সম্ভবত দুটি)। একবার সেখানে আনার বিলম্বগুলি স্বাচ্ছন্দ্যে কম হয় যা কোনও স্টলের জন্য ক্ষতিপূরণ দেবে। এর অর্থ এটিও হ'ল আপনার অভ্যন্তরীণ লুপটি দশটি নির্দেশাবলীর হতে পারে বা এটি সঠিক যেখানে হওয়া উচিত (আমার বাছাইকরণ অ্যালগরিদমে দুটি পৃথক অভ্যন্তরীণ লুপ রয়েছে, সেগুলি যথাক্রমে 10 নির্দেশ / 22 বাইট এবং 9/22 দীর্ঘ)। কোডটি ধরে নিয়ে কোনও ডিভ থাকে না আপনি নিশ্চিত হয়ে যেতে পারেন যে এটি অন্ধভাবে দ্রুত হবে।


আপনার উত্তর কীভাবে বুঝতে হবে তা আমি নিশ্চিত নই। প্রথমে আমি বুঝতে পারছি না আপনি কোন অ্যালগরিদম প্রস্তাব করছেন? এবং যদি আপনার 720 টি সম্ভাব্য অর্ডিংয়ের মধ্য দিয়ে লুপ করতে হয় তবে এটি কীভাবে অনুকূল হতে পারে (বিদ্যমান উত্তরগুলি 720 চক্রের চেয়ে অনেক কম লাগে)। আপনার যদি এলোমেলো ইনপুট থাকে তবে আমি কল্পনাও করতে পারি না (এমনকি তাত্ত্বিক স্তরেও) শাখার পূর্বাভাস কীভাবে 50-50 এর চেয়ে ভাল পারফর্ম করতে পারে যদি তা যদি কোনও ইনপুট ডেটার সমস্ত বিবেচনা না করে। ইতিমধ্যে প্রস্তাবিত বেশিরভাগ ভাল সমাধান ইতিমধ্যে ক্যাশে সম্পূর্ণ ডেটা এবং কোডের সাথে কাজ করার সম্ভাবনা রয়েছে। তবে আমি আপনার উত্তরটি পুরোপুরি ভুল বুঝেছি। কিছু কোড দেখাচ্ছে মাইন্ড?
ক্রিশস

আমার অর্থ হ'ল এখানে কেবলমাত্র 720 (6!) 6 টি পূর্ণসংখ্যার বিভিন্ন সংমিশ্রণ রয়েছে এবং প্রার্থীর অ্যালগরিদমের মাধ্যমে সেগুলি চালিয়ে আপনি অনেকগুলি জিনিস নির্ধারণ করতে পারেন যেটা আমি বলেছি - এটি তাত্ত্বিক অংশ। ব্যবহারিক অংশটি অ্যালগরিদম যতটা সম্ভব কয়েকটা ঘড়ির চক্রে চালানোর জন্য সুরক্ষিত tun 6 পূর্ণসংখ্যার বাছাইয়ের জন্য আমার সূচনা পয়েন্টটি 1, 4 ফাঁক শেলসোর্ট। 4 ফাঁক 1 ফাঁক দিয়ে ভাল শাখার পূর্বাভাসের পথ সুগম করে।
অলিফ ফোর্শেল

1, 4 ফাঁক শেলসোর্ট 6 এর জন্য! অনন্য সংমিশ্রণগুলি (012345 দিয়ে শুরু হওয়া এবং 543210 দিয়ে শেষ হওয়া) 7 টি তুলনা এবং 0 এক্সচেঞ্জের সর্বোত্তম কেস এবং 14 টি তুলনা এবং 10 এক্সচেঞ্জের মধ্যে সবচেয়ে খারাপ কেস হবে। গড় কেসটি প্রায় 11.14 তুলনা এবং 6 এক্সচেঞ্জ।
অলিফ ফোর্শেল

1
আমি "নিয়মিত এলোমেলো বিতরণ" পাই না - আমি যা করছি তা প্রতিটি সম্ভাব্য সংমিশ্রণটি পরীক্ষা করে এবং ন্যূনতম / গড় / সর্বোচ্চ পরিসংখ্যান নির্ধারণ করে। শেলসোর্ট হ'ল ক্রমহ্রাসমান ক্রমগুলির অন্তর্ভুক্তকরণের একটি সিরিজ যা চূড়ান্ত বর্ধিতকরণ - 1 - এটি খাঁটি সন্নিবেশ সাজানোর মতো সমস্ত একা সঞ্চালিত হয় তার চেয়ে অনেক কম কাজ করে। ক্লক কাউন্ট হিসাবে আমার অ্যালগরিদমে গড় 406 ঘড়ি চক্র প্রয়োজন এবং এর মধ্যে পরিসংখ্যান সংগ্রহ করা এবং প্রকৃত বাছাইয়ের রুটিনে দুটি কল করা অন্তর্ভুক্ত - প্রতিটি ব্যবধানের জন্য একটি। এটি একটি অ্যাথলন এম 300 মোবাইল, সংকলক ওপেন ওয়াটকমের উপর রয়েছে।
অলিফ ফোর্শেল

1
"নিয়মিত এলোমেলো বিতরণ" এর অর্থ হল বাছাই করা আসল ডেটার প্রতিটি সংমিশ্রণ সমান সম্ভাবনা নাও থাকতে পারে। যদি প্রতিটি সংমিশ্রণের সমান সম্ভাবনা না থাকে তবে আপনার পরিসংখ্যানগুলি ভাঙা হয়েছে কারণ প্রদত্ত বিতরণ হওয়ার সম্ভাবনা কতবার গড় তা বিবেচনায় নেওয়া দরকার। ঘড়ির গণনার জন্য, আপনি যদি এই ধরণের অন্য কোনও প্রয়োগের চেষ্টা করেন (উপরে প্রদত্ত লিঙ্কগুলি) এবং এটি আপনার পরীক্ষার সিস্টেমে চালিত করেন তবে আমাদের তুলনা করার জন্য একটি ভিত্তি থাকবে এবং দেখুন যে আপনার নির্বাচিত কোনওটি কতটা ভাল সম্পাদন করে।
ক্রিস

1

আমি জানি এটি একটি পুরানো প্রশ্ন।

তবে আমি কেবল একটি আলাদা ধরণের সমাধান লিখেছি যা আমি ভাগ করতে চাই।
নেস্টেড এমআইএন ম্যাক্স ছাড়া আর কিছুই ব্যবহার করা হচ্ছে না

এটি দ্রুত নয় কারণ এটি প্রতিটি 114 ব্যবহার করে,
75-এ কমিয়ে আনতে পারে - যেমন পেস্টবিন like

তবে তারপরেও এটি আর কমপক্ষে সর্বাধিক নয়।

কী কাজ করতে পারে তা AVX এর সাথে এক সাথে একাধিক পূর্ণসংখ্যায় সর্বনিম্ন / সর্বাধিক কাজ করছে

PMINSW রেফারেন্স

#include <stdio.h>

static __inline__ int MIN(int a, int b){
int result =a;
__asm__ ("pminsw %1, %0" : "+x" (result) : "x" (b));
return result;
}
static __inline__ int MAX(int a, int b){
int result = a;
__asm__ ("pmaxsw %1, %0" : "+x" (result) : "x" (b));
return result;
}
static __inline__ unsigned long long rdtsc(void){
  unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31" :
  "=A" (x));
  return x;
}

#define MIN3(a, b, c) (MIN(MIN(a,b),c))
#define MIN4(a, b, c, d) (MIN(MIN(a,b),MIN(c,d)))

static __inline__ void sort6(int * in) {
  const int A=in[0], B=in[1], C=in[2], D=in[3], E=in[4], F=in[5];

  in[0] = MIN( MIN4(A,B,C,D),MIN(E,F) );

  const int
  AB = MAX(A, B),
  AC = MAX(A, C),
  AD = MAX(A, D),
  AE = MAX(A, E),
  AF = MAX(A, F),
  BC = MAX(B, C),
  BD = MAX(B, D),
  BE = MAX(B, E),
  BF = MAX(B, F),
  CD = MAX(C, D),
  CE = MAX(C, E),
  CF = MAX(C, F),
  DE = MAX(D, E),
  DF = MAX(D, F),
  EF = MAX(E, F);

  in[1] = MIN4 (
  MIN4( AB, AC, AD, AE ),
  MIN4( AF, BC, BD, BE ),
  MIN4( BF, CD, CE, CF ),
  MIN3( DE, DF, EF)
  );

  const int
  ABC = MAX(AB,C),
  ABD = MAX(AB,D),
  ABE = MAX(AB,E),
  ABF = MAX(AB,F),
  ACD = MAX(AC,D),
  ACE = MAX(AC,E),
  ACF = MAX(AC,F),
  ADE = MAX(AD,E),
  ADF = MAX(AD,F),
  AEF = MAX(AE,F),
  BCD = MAX(BC,D),
  BCE = MAX(BC,E),
  BCF = MAX(BC,F),
  BDE = MAX(BD,E),
  BDF = MAX(BD,F),
  BEF = MAX(BE,F),
  CDE = MAX(CD,E),
  CDF = MAX(CD,F),
  CEF = MAX(CE,F),
  DEF = MAX(DE,F);

  in[2] = MIN( MIN4 (
  MIN4( ABC, ABD, ABE, ABF ),
  MIN4( ACD, ACE, ACF, ADE ),
  MIN4( ADF, AEF, BCD, BCE ),
  MIN4( BCF, BDE, BDF, BEF )),
  MIN4( CDE, CDF, CEF, DEF )
  );


  const int
  ABCD = MAX(ABC,D),
  ABCE = MAX(ABC,E),
  ABCF = MAX(ABC,F),
  ABDE = MAX(ABD,E),
  ABDF = MAX(ABD,F),
  ABEF = MAX(ABE,F),
  ACDE = MAX(ACD,E),
  ACDF = MAX(ACD,F),
  ACEF = MAX(ACE,F),
  ADEF = MAX(ADE,F),
  BCDE = MAX(BCD,E),
  BCDF = MAX(BCD,F),
  BCEF = MAX(BCE,F),
  BDEF = MAX(BDE,F),
  CDEF = MAX(CDE,F);

  in[3] = MIN4 (
  MIN4( ABCD, ABCE, ABCF, ABDE ),
  MIN4( ABDF, ABEF, ACDE, ACDF ),
  MIN4( ACEF, ADEF, BCDE, BCDF ),
  MIN3( BCEF, BDEF, CDEF )
  );

  const int
  ABCDE= MAX(ABCD,E),
  ABCDF= MAX(ABCD,F),
  ABCEF= MAX(ABCE,F),
  ABDEF= MAX(ABDE,F),
  ACDEF= MAX(ACDE,F),
  BCDEF= MAX(BCDE,F);

  in[4]= MIN (
  MIN4( ABCDE, ABCDF, ABCEF, ABDEF ),
  MIN ( ACDEF, BCDEF )
  );

  in[5] = MAX(ABCDE,F);
}

int main(int argc, char ** argv) {
  int d[6][6] = {
    {1, 2, 3, 4, 5, 6},
    {6, 5, 4, 3, 2, 1},
    {100, 2, 300, 4, 500, 6},
    {100, 2, 3, 4, 500, 6},
    {1, 200, 3, 4, 5, 600},
    {1, 1, 2, 1, 2, 1}
  };

  unsigned long long cycles = rdtsc();
  for (int i = 0; i < 6; i++) {
    sort6(d[i]);
  }
  cycles = rdtsc() - cycles;
  printf("Time is %d\n", (unsigned)cycles);

  for (int i = 0; i < 6; i++) {
    printf("d%d : %d %d %d %d %d %d\n", i,
     d[i][0], d[i][1], d[i][2],
     d[i][3], d[i][4], d[i][5]);
  }
}

সম্পাদনা:
র‌্যাক্স কেরার দ্বারা অনুপ্রাণিত র‌্যাঙ্ক অর্ডার সমাধান, উপরের গণ্ডগোলের চেয়ে অনেক দ্রুত

static void sort6(int *o) {
const int 
A=o[0],B=o[1],C=o[2],D=o[3],E=o[4],F=o[5];
const unsigned char
AB = A>B, AC = A>C, AD = A>D, AE = A>E,
          BC = B>C, BD = B>D, BE = B>E,
                    CD = C>D, CE = C>E,
                              DE = D>E,
a =          AB + AC + AD + AE + (A>F),
b = 1 - AB      + BC + BD + BE + (B>F),
c = 2 - AC - BC      + CD + CE + (C>F),
d = 3 - AD - BD - CD      + DE + (D>F),
e = 4 - AE - BE - CE - DE      + (E>F);
o[a]=A; o[b]=B; o[c]=C; o[d]=D; o[e]=E;
o[15-a-b-c-d-e]=F;
}

1
নতুন সমাধানগুলি দেখতে সর্বদা দুর্দান্ত। দেখে মনে হচ্ছে কিছু সহজ অপ্টিমাইজেশন সম্ভব। শেষ পর্যন্ত এটি বাছাই করা নেটওয়ার্কগুলি থেকে এত আলাদা প্রমাণিত হতে পারে না।
খ্রিস্ট

হ্যাঁ এমআইএন এবং ম্যাক্সের সংখ্যা সম্ভবত হ্রাস করা যেতে পারে, উদাহরণস্বরূপ এমআইএন (এবি, সিডি) কয়েকবার পুনরাবৃত্তি করে, তবে তাদের অনেকটা হ্রাস করা আমার পক্ষে কঠিন মনে হবে। আমি আপনার পরীক্ষার কেস যুক্ত করেছি।
প্রিন্সপোলকা

পিন / ম্যাক্সডাব্লু 16-বিট স্বাক্ষরিত পূর্ণসংখ্যার ( int16_t) ব্যবহার করে। তবে আপনার সি ফাংশন দাবি করে যে এটির একটি অ্যারে বাছাই করে int(যা সি সিট্যাক্স সমর্থন করে এমন সমস্ত সি বাস্তবায়নে 32-বিট asm)। আপনি কি এটি কেবলমাত্র ছোট পজিটিভ পূর্ণসংখ্যার সাথে পরীক্ষা করেছেন যার উচ্চমাত্রায় কেবল 0 আছে? এটি কার্যকর হবে ... আপনার জন্য intএসএসই 4.1 দরকার pmin/maxsd(ডি = ডওয়ার)। felixcloutier.com/x86/pminsd:pminsq বা এর pminusdজন্য uint32_t
পিটার কর্ডেস

1

আমি দেখতে পেয়েছি যে কমপক্ষে আমার সিস্টেমে, উভয়ের নীচে বর্ণিত ফাংশনগুলি sort6_iterator()এবং sort6_iterator_local()উপরের বর্তমান রেকর্ডধারীর চেয়ে কমপক্ষে দ্রুত এবং প্রায়শই লক্ষণীয়ভাবে দ্রুত গতিতে চলেছে:

#define MIN(x, y) (x<y?x:y)
#define MAX(x, y) (x<y?y:x)

template<class IterType> 
inline void sort6_iterator(IterType it) 
{
#define SWAP(x,y) { const auto a = MIN(*(it + x), *(it + y)); \
  const auto b = MAX(*(it + x), *(it + y)); \
  *(it + x) = a; *(it + y) = b; }

  SWAP(1, 2) SWAP(4, 5)
  SWAP(0, 2) SWAP(3, 5)
  SWAP(0, 1) SWAP(3, 4)
  SWAP(1, 4) SWAP(0, 3)
  SWAP(2, 5) SWAP(1, 3)
  SWAP(2, 4)
  SWAP(2, 3)
#undef SWAP
}

আমি std::vectorআমার টাইমিং কোডটিতে এই ফাংশনটির একটি পুনরাবৃত্তিটি পাস করেছি।

আমি (মত মন্তব্য থেকে সন্দেহ এই এবং অন্যত্র) যে iterators ব্যবহার করে এবং মেমরি ঘটবে না পারে কি যে পুনরুক্তিকারীর উল্লেখ করে, যার ফলে এটি অন্যথায় হতো না এবং এটি এই নিশ্চয়তা তা সনাক্ত করতে মঞ্জুর ছ ++, হয় সম্পর্কে ছ ++, নির্দিষ্ট নিশ্চয়তা দেয় বাছাইকরণ কোডটি আরও অনুকূল করে নিন (উদাহরণস্বরূপ পয়েন্টার সহ, সংকলকটি নিশ্চিত হতে পারে না যে সমস্ত পয়েন্টার বিভিন্ন মেমরি অবস্থানগুলিতে নির্দেশ করছে)। যদ্দুর মনে পড়ে, এই হয় অংশ যুক্তির কেন যেমন যাতে অনেক Stl আলগোরিদিম,std::sort() , সাধারণত এই ধরনের obscenely ভাল পারফরম্যান্স আছে।

অধিকন্তু, sort6_iterator()হয় কিছু বার (আবার, যা প্রেক্ষাপটে ফাংশন বলা হয় উপর নির্ভর করে) ধারাবাহিকভাবে নিম্নলিখিত বাছাই ফাংশন, দ্বারা ছাপিয়ে গিয়েছিল যা তাদের বাছাই করার আগে কপি স্থানীয় ভেরিয়েবল ডেটা। 1 নোট করুন যেহেতু কেবলমাত্র 6 স্থানীয় ভেরিয়েবলগুলি সংজ্ঞায়িত করা হয়েছে, যদি এই স্থানীয় ভেরিয়েবলগুলি আদিম হয় তবে সম্ভবত এগুলি কখনই র‍্যামে সংরক্ষিত হয় না এবং ফাংশন কল শেষ না হওয়া অবধি কেবলমাত্র সিপিইউ'র রেজিস্টারে সংরক্ষণ করা হয় যা এই বাছাই করতে সহায়তা করে দ্রুত কাজ। (এটি এটিও সহায়তা করে যে সংকলকটি জানে যে স্বতন্ত্র স্থানীয় ভেরিয়েবলগুলির স্মৃতিতে স্বতন্ত্র অবস্থান রয়েছে)।

template<class IterType> 
inline void sort6_iterator_local(IterType it) 
{
#define SWAP(x,y) { const auto a = MIN(data##x, data##y); \
  const auto b = MAX(data##x, data##y); \
  data##x = a; data##y = b; }
//DD = Define Data
#define DD1(a)   auto data##a = *(it + a);
#define DD2(a,b) auto data##a = *(it + a), data##b = *(it + b);
//CB = Copy Back
#define CB(a) *(it + a) = data##a;

  DD2(1,2)    SWAP(1, 2)
  DD2(4,5)    SWAP(4, 5)
  DD1(0)      SWAP(0, 2)
  DD1(3)      SWAP(3, 5)
  SWAP(0, 1)  SWAP(3, 4)
  SWAP(1, 4)  SWAP(0, 3)   CB(0)
  SWAP(2, 5)  CB(5)
  SWAP(1, 3)  CB(1)
  SWAP(2, 4)  CB(4)
  SWAP(2, 3)  CB(2)        CB(3)
#undef CB
#undef DD2
#undef DD1
#undef SWAP
}

লক্ষ্য করুন সংজ্ঞা SWAP()নিম্নরূপ কিছু সামান্য ভাল পারফরম্যান্স মধ্যে বার ফলাফল যদিও সময় এটি সামান্য খারাপ পারফরম্যান্স বা কর্মক্ষমতা একটি তুচ্ছ পার্থক্য ফলাফল অধিকাংশ।

#define SWAP(x,y) { const auto a = MIN(data##x, data##y); \
  data##y = MAX(data##x, data##y); \
  data##x = a; }

আপনি যদি কেবল বাছাই করা অ্যালগরিদম চান যে আদিম তথ্য প্রকারের উপর, সিসিটি-ফাংশনটিতে কলটি 1 এর পরে কোন প্রসঙ্গটি প্রদর্শিত হয় তা বিবেচনা করে নিখরচায় ধারাবাহিকভাবে ভাল হয় , আপনি কীভাবে ইনপুটটি পাস করবেন তার উপর নির্ভর করে নিম্নলিখিত দুটিগুলির মধ্যে একটি ব্যবহার করে দেখুন আলগোরিদিম:

template<class T> inline void sort6(T it) {
#define SORT2(x,y) {if(data##x>data##y){auto a=std::move(data##y);data##y=std::move(data##x);data##x=std::move(a);}}
#define DD1(a)   register auto data##a=*(it+a);
#define DD2(a,b) register auto data##a=*(it+a);register auto data##b=*(it+b);
#define CB1(a)   *(it+a)=data##a;
#define CB2(a,b) *(it+a)=data##a;*(it+b)=data##b;
  DD2(1,2) SORT2(1,2)
  DD2(4,5) SORT2(4,5)
  DD1(0)   SORT2(0,2)
  DD1(3)   SORT2(3,5)
  SORT2(0,1) SORT2(3,4) SORT2(2,5) CB1(5)
  SORT2(1,4) SORT2(0,3) CB1(0)
  SORT2(2,4) CB1(4)
  SORT2(1,3) CB1(1)
  SORT2(2,3) CB2(2,3)
#undef CB1
#undef CB2
#undef DD1
#undef DD2
#undef SORT2
}

অথবা আপনি যদি রেফারেন্সের মাধ্যমে ভেরিয়েবলগুলি পাস করতে চান তবে এটি ব্যবহার করুন (নীচের ফাংশনটি তার প্রথম 5 লাইনে উপরের থেকে আলাদা):

template<class T> inline void sort6(T& e0, T& e1, T& e2, T& e3, T& e4, T& e5) {
#define SORT2(x,y) {if(data##x>data##y)std::swap(data##x,data##y);}
#define DD1(a)   register auto data##a=e##a;
#define DD2(a,b) register auto data##a=e##a;register auto data##b=e##b;
#define CB1(a)   e##a=data##a;
#define CB2(a,b) e##a=data##a;e##b=data##b;
  DD2(1,2) SORT2(1,2)
  DD2(4,5) SORT2(4,5)
  DD1(0)   SORT2(0,2)
  DD1(3)   SORT2(3,5)
  SORT2(0,1) SORT2(3,4) SORT2(2,5) CB1(5)
  SORT2(1,4) SORT2(0,3) CB1(0)
  SORT2(2,4) CB1(4)
  SORT2(1,3) CB1(1)
  SORT2(2,3) CB2(2,3)
#undef CB1
#undef CB2
#undef DD1
#undef DD2
#undef SORT2
}

মূলশব্দটি ব্যবহারের registerকারণ হ'ল কারণ আপনি জানেন যে আপনি রেজিস্টারগুলিতে এই মানগুলি চান তা কয়েকবার। সংকলকটি registerবেশিরভাগ সময় এটি সন্ধান করে তবে কখনও কখনও তা হয় না। registerকীওয়ার্ড ব্যবহার করা এই সমস্যাটি সমাধান করতে সহায়তা করে। সাধারণত, তবে registerকীওয়ার্ডটি ব্যবহার করবেন না কারণ এটি আপনার কোডটি গতি বাড়ানোর চেয়ে ধীর করবে।

এছাড়াও, টেমপ্লেটগুলির ব্যবহার নোট করুন। এটি উদ্দেশ্য হিসাবে করা হয়, এমনকি inlineকীওয়ার্ড সহ, টেমপ্লেট ফাংশনগুলি সাধারণত ভ্যানিলা সি ফাংশনগুলির তুলনায় জিসিসি দ্বারা আরও আক্রমণাত্মকভাবে অনুকূলিত হয় (এটি ভিসিলা সি ফাংশনগুলির জন্য ফাংশন পয়েন্টারগুলি মোকাবেলা করার জন্য জিসিসি প্রয়োজন তবে টেমপ্লেট ফাংশনগুলির সাথে নয়)।

  1. বিভিন্ন বাছাইয়ের ক্রিয়াকলাপগুলির সময় নির্ধারণ করার সময় আমি লক্ষ্য করেছি যে প্রসঙ্গটি (যেমন আশেপাশের কোড) বাছাইয়ের ফাংশনটিতে কল করা হয়েছিল তার কার্যকারিতাটিতে একটি উল্লেখযোগ্য প্রভাব পড়েছিল, এটি সম্ভবত ফাংশনটি অন্তর্ভুক্ত হওয়ার পরে এবং অনুকূলিত হওয়ার কারণে। উদাহরণস্বরূপ, যদি প্রোগ্রামটি যথেষ্ট সরল ছিল তবে সাধারণত বাছাই ফাংশনটি পয়েন্টার বনাম এটির পুনঃপ্রবাহকারী পাস করার মধ্যে পারফরম্যান্সের মধ্যে খুব একটা পার্থক্য ছিল না; অন্যথায় পুনরাবৃত্তকারী ব্যবহার করার ফলে সাধারণত আরও ভাল পারফরম্যান্স হয় এবং কখনই (আমার অভিজ্ঞতায় কমপক্ষে) কোনও খারাপ লক্ষণীয় পারফরম্যান্স হয় না। আমি সন্দেহ করি যে এটি হতে পারে কারণ g ++ যথেষ্ট সহজ কোডটি বিশ্বব্যাপী অনুকূলিত করতে পারে।

0

'সাজানো তালিকাটি সাজানো' সাজানোর চেষ্টা করুন। :) দুটি অ্যারে ব্যবহার করুন। ছোট এবং বড় অ্যারের জন্য দ্রুততম।
যদি আপনি সিদ্ধান্ত নিচ্ছেন তবে আপনি কেবল কোথায় সন্নিবেশ করান তা পরীক্ষা করে দেখুন। অন্যান্য বড় মানগুলির তুলনা করার দরকার নেই (cmp = ab> 0)।
৪ টি সংখ্যার জন্য, আপনি সিস্টেমটি 4-5 সেন্টিমিটার (~ 4.6) বা 3-6 সেন্টিমিটার (~ 4.9) ব্যবহার করতে পারেন। বুদ্বুদ সাজানোর জন্য 6 সিএমপি (6) ব্যবহার করুন। বড় সংখ্যার ধীর কোডের জন্য প্রচুর সিএমপি।
এই কোডটি 5 সিএমপি ব্যবহার করে (এমএসএল বাছাই নয়):
if (cmp(arr[n][i+0],arr[n][i+1])>0) {swap(n,i+0,i+1);} if (cmp(arr[n][i+2],arr[n][i+3])>0) {swap(n,i+2,i+3);} if (cmp(arr[n][i+0],arr[n][i+2])>0) {swap(n,i+0,i+2);} if (cmp(arr[n][i+1],arr[n][i+3])>0) {swap(n,i+1,i+3);} if (cmp(arr[n][i+1],arr[n][i+2])>0) {swap(n,i+1,i+2);}

প্রিন্সিপাল এমএসএল 9 8 7 6 5 4 3 2 1 0 89 67 45 23 01 ... concat two sorted lists, list length = 1 6789 2345 01 ... concat two sorted lists, list length = 2 23456789 01 ... concat two sorted lists, list length = 4 0123456789 ... concat two sorted lists, list length = 8

জেএস কোড

function sortListMerge_2a(cmp)	
{
var step, stepmax, tmp, a,b,c, i,j,k, m,n, cycles;
var start = 0;
var end   = arr_count;
//var str = '';
cycles = 0;
if (end>3)
	{
	stepmax = ((end - start + 1) >> 1) << 1;
	m = 1;
	n = 2;
	for (step=1;step<stepmax;step<<=1)	//bounds 1-1, 2-2, 4-4, 8-8...
		{
		a = start;
		while (a<end)
			{
			b = a + step;
			c = a + step + step;
			b = b<end ? b : end;
			c = c<end ? c : end;
			i = a;
			j = b;
			k = i;
			while (i<b && j<c)
				{
				if (cmp(arr[m][i],arr[m][j])>0)
					{arr[n][k] = arr[m][j]; j++; k++;}
				else	{arr[n][k] = arr[m][i]; i++; k++;}
				}
			while (i<b)
				{arr[n][k] = arr[m][i]; i++; k++;
}
			while (j<c)
				{arr[n][k] = arr[m][j]; j++; k++;
}
			a = c;
			}
		tmp = m; m = n; n = tmp;
		}
	return m;
	}
else
	{
	// sort 3 items
	sort10(cmp);
	return m;
	}
}


0

সিএমপি == 0 ব্যবহারের সাথে 4 টি আইটেম বাছাই করুন। সিএমপি নম্বরগুলি ~ 4.34 (এফএফ নেটিভের ~ 4.52 থাকে) তবে তালিকাটি মার্জ করার চেয়ে 3x সময় নেয়। তবে আরও ভাল সিএমপি ক্রিয়াকলাপ, আপনার যদি বড় সংখ্যা বা বড় পাঠ্য থাকে। সম্পাদনা করুন: বাগ মেরামত করা হয়েছে

অনলাইন পরীক্ষা http://mlich.zam.slu.cz/js-sort/x-sort-x2.htm

function sort4DG(cmp,start,end,n) // sort 4
{
var n     = typeof(n)    !=='undefined' ? n   : 1;
var cmp   = typeof(cmp)  !=='undefined' ? cmp   : sortCompare2;
var start = typeof(start)!=='undefined' ? start : 0;
var end   = typeof(end)  !=='undefined' ? end   : arr[n].length;
var count = end - start;
var pos = -1;
var i = start;
var cc = [];
// stabilni?
cc[01] = cmp(arr[n][i+0],arr[n][i+1]);
cc[23] = cmp(arr[n][i+2],arr[n][i+3]);
if (cc[01]>0) {swap(n,i+0,i+1);}
if (cc[23]>0) {swap(n,i+2,i+3);}
cc[12] = cmp(arr[n][i+1],arr[n][i+2]);
if (!(cc[12]>0)) {return n;}
cc[02] = cc[01]==0 ? cc[12] : cmp(arr[n][i+0],arr[n][i+2]);
if (cc[02]>0)
    {
    swap(n,i+1,i+2); swap(n,i+0,i+1); // bubble last to top
    cc[13] = cc[23]==0 ? cc[12] : cmp(arr[n][i+1],arr[n][i+3]);
    if (cc[13]>0)
        {
        swap(n,i+2,i+3); swap(n,i+1,i+2); // bubble
        return n;
        }
    else    {
    cc[23] = cc[23]==0 ? cc[12] : (cc[01]==0 ? cc[30] : cmp(arr[n][i+2],arr[n][i+3]));  // new cc23 | c03 //repaired
        if (cc[23]>0)
            {
            swap(n,i+2,i+3);
            return n;
            }
        return n;
        }
    }
else    {
    if (cc[12]>0)
        {
        swap(n,i+1,i+2);
        cc[23] = cc[23]==0 ? cc[12] : cmp(arr[n][i+2],arr[n][i+3]); // new cc23
        if (cc[23]>0)
            {
            swap(n,i+2,i+3);
            return n;
            }
        return n;
        }
    else    {
        return n;
        }
    }
return n;
}

1
ব্যবহারের ক্ষেত্রে প্রশ্নের প্রাথমিক প্রেক্ষাপট থেকে কিছুটা আলাদা। নির্দিষ্ট দৈর্ঘ্যের সাথে বিশদ বিবরণযুক্ত এবং সিম্পের অদলবদল গণনা যথেষ্ট নয়। এমনকি আমি যদি অবাক হই না যে এটি যদি সত্যই বাছাই না করে যে সময়টি গ্রাহ্য করে তবে ডিআইডি তে সম্পূর্ণ আলাদা আলাদা আলোক কলিং টাইপ () রয়েছে। জাভাস্ক্রিপ্ট ব্যবহার করে কীভাবে আসল ক্লক টাইম মেসর করা যায় তা আমি জানি না। নোডের সাথে হতে পারে?
ক্রিস করুন

0

হয়তো আমি নই পক্ষের কাছে দেরী, কিন্তু অন্তত আমার অবদান একটি হল নতুন পদ্ধতির।

  • কোডটি সত্যই ইনলাইন করা উচিত
  • এমনকি যদি ইনলাইন করা থাকে তবে অনেকগুলি শাখা রয়েছে
  • বিশ্লেষণকারী অংশটি মূলত O (N (N-1)) যা এন = 6 এর জন্য ঠিক আছে বলে মনে হয়
  • কোডটি আরও কার্যকর হতে পারে যদি খরচswap বেশি হয় (মূল্যের দাম compare)
  • আমি স্থিতিশীল ফাংশনগুলি অন্তর্ভুক্ত হওয়ার উপর বিশ্বাস করি।
  • পদ্ধতিটি র‌্যাঙ্ক-বাছাইয়ের সাথে সম্পর্কিত
    • র‌্যাঙ্কগুলির পরিবর্তে, আপেক্ষিক র‌্যাঙ্কগুলি (অফসেট) ব্যবহৃত হয়।
    • যে কোনও অনুক্রমের গ্রুপে প্রতিটি চক্রের জন্য র‌্যাঙ্কের যোগফল শূন্য ।
    • SWAP()দুটি উপাদান যুক্ত করার পরিবর্তে , চক্রগুলি তাড়া করা হয়, কেবল একটি টেম্পের প্রয়োজন হয় এবং একটিতে (রেজিস্ট্রেশন> রেজিস্টার) অদলবদল (নতুন <- পুরাতন)।

আপডেট: কোডটি কিছুটা পরিবর্তন করেছে, কিছু লোক সি কোডটি সংকলন করতে সি ++ সংকলক ব্যবহার করে ...

#include <stdio.h>

#if WANT_CHAR
typedef signed char Dif;
#else
typedef signed int Dif;
#endif

static int walksort (int *arr, int cnt);
static void countdifs (int *arr, Dif *dif, int cnt);
static void calcranks(int *arr, Dif *dif);

int wsort6(int *arr);

void do_print_a(char *msg, int *arr, unsigned cnt)
{
fprintf(stderr,"%s:", msg);
for (; cnt--; arr++) {
        fprintf(stderr, " %3d", *arr);
        }
fprintf(stderr,"\n");
}

void do_print_d(char *msg, Dif *arr, unsigned cnt)
{
fprintf(stderr,"%s:", msg);
for (; cnt--; arr++) {
        fprintf(stderr, " %3d", (int) *arr);
        }
fprintf(stderr,"\n");
}

static void inline countdifs (int *arr, Dif *dif, int cnt)
{
int top, bot;

for (top = 0; top < cnt; top++ ) {
        for (bot = 0; bot < top; bot++ ) {
                if (arr[top] < arr[bot]) { dif[top]--; dif[bot]++; }
                }
        }
return ;
}
        /* Copied from RexKerr ... */
static void inline calcranks(int *arr, Dif *dif){

dif[0] =     (arr[0]>arr[1])+(arr[0]>arr[2])+(arr[0]>arr[3])+(arr[0]>arr[4])+(arr[0]>arr[5]);
dif[1] = -1+ (arr[1]>=arr[0])+(arr[1]>arr[2])+(arr[1]>arr[3])+(arr[1]>arr[4])+(arr[1]>arr[5]);
dif[2] = -2+ (arr[2]>=arr[0])+(arr[2]>=arr[1])+(arr[2]>arr[3])+(arr[2]>arr[4])+(arr[2]>arr[5]);
dif[3] = -3+ (arr[3]>=arr[0])+(arr[3]>=arr[1])+(arr[3]>=arr[2])+(arr[3]>arr[4])+(arr[3]>arr[5]);
dif[4] = -4+ (arr[4]>=arr[0])+(arr[4]>=arr[1])+(arr[4]>=arr[2])+(arr[4]>=arr[3])+(arr[4]>arr[5]);
dif[5] = -(dif[0]+dif[1]+dif[2]+dif[3]+dif[4]);
}

static int walksort (int *arr, int cnt)
{
int idx, src,dst, nswap;

Dif difs[cnt];

#if WANT_REXK
calcranks(arr, difs);
#else
for (idx=0; idx < cnt; idx++) difs[idx] =0;
countdifs(arr, difs, cnt);
#endif
calcranks(arr, difs);

#define DUMP_IT 0
#if DUMP_IT
do_print_d("ISteps ", difs, cnt);
#endif

nswap = 0;
for (idx=0; idx < cnt; idx++) {
        int newval;
        int step,cyc;
        if ( !difs[idx] ) continue;
        newval = arr[idx];
        cyc = 0;
        src = idx;
        do      {
                int oldval;
                step = difs[src];
                difs[src] =0;
                dst = src + step;
                cyc += step ;
                if(dst == idx+1)idx=dst;
                oldval = arr[dst];
#if (DUMP_IT&1)
                fprintf(stderr, "[Nswap=%d] Cyc=%d Step=%2d Idx=%d  Old=%2d New=%2d #### Src=%d Dst=%d[%2d]->%2d <-- %d\n##\n"
                        , nswap, cyc, step, idx, oldval, newval
                        , src, dst, difs[dst], arr[dst]
                        , newval  );
                do_print_a("Array ", arr, cnt);
                do_print_d("Steps ", difs, cnt);
#endif

                arr[dst] = newval;
                newval = oldval;
                nswap++;
                src = dst;
                } while( cyc);
        }

return nswap;
}
/*************/
int wsort6(int *arr)
{
return walksort(arr, 6);
}

বুদ্বুদ সাজানোর মতো দেখাচ্ছে। ধীরে ধীরে বাস্তবায়নের পক্ষে সম্ভাব্য একটি ভাল প্রতিযোগী, তবে কোডটিতে কাজ করা এতটা তাত্পর্যপূর্ণ কিনা তা জানা এখনও কিছুটা আগ্রহী হতে পারে। আপনার কোডটি অন্যদের মতো একই ফর্ম্যাটে রাখুন, সুতরাং আমরা এটিতে মাপদণ্ড চালাতে পারি।
ক্রিস

@kriss en.wikipedia.org/wiki/Permutation_group এটা অবশ্যই না সাজানোর বুদ্বুদ: কোড দেওয়া বিন্যাস মধ্যে চক্র সনাক্ত করে, এবং এই চক্র পদচারনা, তার চূড়ান্ত স্থানে প্রতিটি উপাদান নির্বাণ। চূড়ান্ত wsort6()ফাংশন সঠিক ইন্টারফেস আছে।
Joop

@ জুপ: আমার খারাপ, কোনও বুদবুদ প্রকৃতপক্ষে নয়। প্রসঙ্গে বলা হচ্ছে আমি এখনও কোডটি অন্য যে কোনও বাস্তবায়নের চেয়ে অনেক খারাপ হওয়ার প্রত্যাশা করছি। যাইহোক র‌্যাঙ্ক অর্ডার সমাধানটি প্রতিটি আইটেমের চূড়ান্ত অবস্থানটি সরাসরি খুঁজে পাওয়ার সাথে সাথে অদলবদলের সংখ্যা সম্পর্কে সর্বোত্তম। এটিও অস্পষ্ট নয় যে ওয়াকসোর্ট এমনকি যদি কাজ করে তখনও আমরা এই অনুমানটি সরিয়ে ফেলি যে সমস্ত সাজানো সংখ্যা এখানে আলাদা। কোডটি বেঞ্চমার্ক করার জন্য আমাদের কোডটি ট্রেস করা উচিত। এছাড়াও আমি সাধারণত একটি সি ++ সংকলক সংকলন করার পরে, কোডটি কাজ করবে না কারণ ওপি একটি ভেরিয়েবল "নতুন" বলে ডাকে (এবং এটি সিনট্যাক্স হাইলাইটিং ব্রেক করে)।
ক্রিস

পদ্ধতি, খুব পদক্রম পাসে হবে শুধুমাত্র চূড়ান্ত বরাদ্দকরণ করা হয় জায়গায় । র‌্যাঙ্কগুলি বাদে o1..o5দ্বিতীয় টেম্প e[6]অ্যারের প্রয়োজন নেই । এবং: একটি সি ++ কম্পাইলারে সি কোডটি সংকলন করে, এবং কোডকে দোষ দিচ্ছেন?
Joop

@ গ্রেইবার্ড: আপনাকে ধন্যবাদ, আমি এর আগেও একটি জায়গা যুক্ত করেছি #include। স্থির
ওয়াইল্ডপ্লাজার

0
//Bruteforce compute unrolled count dumbsort(min to 0-index)
void bcudc_sort6(int* a)
{
    int t[6] = {0};
    int r1,r2;

    r1=0;
    r1 += (a[0] > a[1]);
    r1 += (a[0] > a[2]);
    r1 += (a[0] > a[3]);
    r1 += (a[0] > a[4]);
    r1 += (a[0] > a[5]);
    while(t[r1]){r1++;}
    t[r1] = a[0];

    r2=0;
    r2 += (a[1] > a[0]);
    r2 += (a[1] > a[2]);
    r2 += (a[1] > a[3]);
    r2 += (a[1] > a[4]);
    r2 += (a[1] > a[5]);
    while(t[r2]){r2++;} 
    t[r2] = a[1];

    r1=0;
    r1 += (a[2] > a[0]);
    r1 += (a[2] > a[1]);
    r1 += (a[2] > a[3]);
    r1 += (a[2] > a[4]);
    r1 += (a[2] > a[5]);
    while(t[r1]){r1++;}
    t[r1] = a[2];

    r2=0;
    r2 += (a[3] > a[0]);
    r2 += (a[3] > a[1]);
    r2 += (a[3] > a[2]);
    r2 += (a[3] > a[4]);
    r2 += (a[3] > a[5]);
    while(t[r2]){r2++;} 
    t[r2] = a[3];

    r1=0;
    r1 += (a[4] > a[0]);
    r1 += (a[4] > a[1]);
    r1 += (a[4] > a[2]);
    r1 += (a[4] > a[3]);
    r1 += (a[4] > a[5]);
    while(t[r1]){r1++;}
    t[r1] = a[4];

    r2=0;
    r2 += (a[5] > a[0]);
    r2 += (a[5] > a[1]);
    r2 += (a[5] > a[2]);
    r2 += (a[5] > a[3]);
    r2 += (a[5] > a[4]);
    while(t[r2]){r2++;} 
    t[r2] = a[5];

    a[0]=t[0];
    a[1]=t[1];
    a[2]=t[2];
    a[3]=t[3];
    a[4]=t[4];
    a[5]=t[5];
}

static __inline__ void sort6(int* a)
{
    #define wire(x,y); t = a[x] ^ a[y] ^ ( (a[x] ^ a[y]) & -(a[x] < a[y]) ); a[x] = a[x] ^ t; a[y] = a[y] ^ t;
    register int t;

    wire( 0, 1); wire( 2, 3); wire( 4, 5);
    wire( 3, 5); wire( 0, 2); wire( 1, 4);
    wire( 4, 5); wire( 2, 3); wire( 0, 1); 
    wire( 3, 4); wire( 1, 2); 
    wire( 2, 3);

    #undef wire
}

গতি নির্বিশেষে আপনি কি নিশ্চিত যে এটি কাজ করে? ব্রুটফোর্স সাজানোর ক্ষেত্রে আপনার লুপগুলি সন্দেহজনক। আমার কাছে মনে হয় তারা বাছাই করা মানগুলিতে শূন্য থাকলে তারা কাজ করবে না।
ক্রিস

1
t [6] অ্যারে 0x0 এ আরম্ভ করা হয়। সুতরাং যেখানে 0x0 মূল্যের কী লেখা হবে তাতে কিছু যায় আসে না।
ফ্রাঙ্ক

-1

ঠিক আছে, যদি এটি মাত্র 6 টি উপাদান হয় এবং আপনি সমান্তরালতা অর্জন করতে পারেন, শর্তাধীন শাখা প্রশাখাকে হ্রাস করতে চান ইত্যাদি আপনি কেন সমস্ত সংমিশ্রণ তৈরি করেন না এবং আদেশের জন্য পরীক্ষা করেন? আমি উদ্যোগ নেব যে কোনও কিছু স্থাপত্যে এটি দ্রুত গতিময় হতে পারে (যতক্ষণ না আপনি স্মৃতিটি পূর্বনির্ধারিত রেখেছেন)


9
এখানে 720 টি অর্ডারিং রয়েছে এবং দ্রুততম সংস্করণগুলি 100 চক্রের অধীনে ভাল। এমনকি যদি বৃহত্তর সমান্তরালতা লাভজনক হতে পারে তবে এ জাতীয় একটি ছোট সময় স্কেলগুলি থ্রেডগুলি তৈরি এবং সিঙ্ক্রোনাইজেশনের ব্যয় সম্ভবত কেবলমাত্র একটি মূলে অ্যারে বাছাইয়ের ব্যয়কে ছাড়িয়ে যাবে।
কেভিন স্টক

-3

এখানে তিনটি সাধারণ বাছাই পদ্ধতি রয়েছে যা অ্যালগোরিদমকে বাছাই করার জন্য তিনটি পৃথক শ্রেণির প্রতিনিধিত্ব করে:

Insertion Sort: Θ(n^2)

Heap Sort: Θ(n log n)

Count Sort: Θ(3n)

তবে দ্রুততম বাছাই করা অ্যালগরিদম সম্পর্কে স্টেফান নেলসন আলোচনা দেখুন? যেখানে তিনি এমন একটি সমাধান নিয়ে আলোচনা করেন যা নীচে চলে যায় O(n log log n).. সিটিতে এর বাস্তবায়ন পরীক্ষা করে দেখুন

এই আধা-লিনিয়ার বাছাই অ্যালগরিদম 1995 সালে একটি কাগজ দ্বারা উপস্থাপিত হয়েছিল:

এ। অ্যান্ডারসন, টি। হ্যাগ্রুপ, এস। নীলসন, এবং আর। রামন। রৈখিক সময়ে বাছাই? থিওরি অফ কম্পিউটারিংয়ের 27 তম বার্ষিক এসিএম সিম্পোজিয়ামের কার্যক্রমে, পৃষ্ঠা 427-436, 1995।


8
এটি আকর্ষণীয় তবে বিন্দুর পাশে। বড়-লক্ষ্য ধ্রুবক কারণগুলি আড়াল করা এবং সমস্যার আকার (এন) বড় হলে প্রবণতা দেখাতে to এখানে সমস্যাটি একটি স্থির সমস্যার আকার (n = 6) সম্পর্কে এবং ধ্রুবক উপাদানগুলি বিবেচনায় নেওয়া সম্পর্কে পুরোপুরি।
ক্রিশ করুন

@ ক্রিসস আপনি ঠিক বলেছেন, আমার তুলনা অ্যাসিপটোটিক, সুতরাং ব্যবহারিক তুলনাটি দ্রুত তা না সে ক্ষেত্রে এটি দেখাতে পারে
খালেদ.কে।

4
আপনি উপসংহারে পৌঁছাতে পারবেন না, কারণ প্রতিটি পৃথক অ্যালগোরিদম একটি আলাদা কে গুণিতক ধ্রুবক (এবং একটি সি অ্যাডিটিভ ধ্রুবক) আড়াল করে। উদাহরণস্বরূপ: সন্নিবেশ বাছাইয়ের জন্য কে 0, সি 0, হিপ সাজানোর জন্য কে 1, সি 1 এবং আরও কিছু on এই সমস্ত ধ্রুবকগুলি আসলে আলাদা আলাদা (আপনি শারীরিক টার্মগুলিতে বলতে পারেন যে প্রতিটি অ্যালগরিদমের নিজস্ব "ঘর্ষণ সহগ" রয়েছে) আপনি এই সিদ্ধান্তে (বা কোনও স্থির এন ক্ষেত্রে) খুব দ্রুততর কোনও অ্যালগোরিদম উপসংহার করতে পারবেন না।
ক্রিশ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.