একটি সি অ্যারেতে একটি মান উপস্থিত রয়েছে কিনা তাড়াতাড়ি সন্ধান করুন?


124

আমার কাছে একটি সময়-সমালোচনামূলক আইএসআর সহ এম্বেড থাকা অ্যাপ্লিকেশন রয়েছে যা 256 আকারের অগ্রাধিকারের মাধ্যমে অগ্রাধিকার করতে হবে (অগ্রাধিকার হিসাবে 1024, তবে 256 সর্বনিম্ন) এবং পরীক্ষা করে মানটি অ্যারের সামগ্রীর সাথে মেলে কিনা। একজনbool সত্য সেট করা হবে এই ক্ষেত্রে।

মাইক্রোকন্ট্রোলারটি একটি এনএক্সপি এলপিসি 44357, এআরএম কর্টেক্স এম 4 কোর এবং সংকলকটি জিসিসি। আমি ইতিমধ্যে সম্মিলিত অপ্টিমাইজেশন স্তর 2 (3 ধীর গতি) এবং ফ্ল্যাশের পরিবর্তে র‌্যামে ফাংশনটি রেখেছি। আমি পয়েন্টার গাণিতিক এবং একটি forলুপও ব্যবহার করি , যা আপের পরিবর্তে ডাউন-কাউন্টিং করে (চেক করার i!=0চেয়ে দ্রুত কিনা তা পরীক্ষা করা হয় i<256)। সব মিলিয়ে, আমি 12.5 a এর সময়কালের সাথে শেষ করছি যা সম্ভবপর হতে মারাত্মকভাবে হ্রাস করতে হবে। এটি আমি এখন ব্যবহার করি (সিউডো) কোড:

uint32_t i;
uint32_t *array_ptr = &theArray[0];
uint32_t compareVal = 0x1234ABCD;
bool validFlag = false;

for (i=256; i!=0; i--)
{
    if (compareVal == *array_ptr++)
    {
         validFlag = true;
         break;
     }
}

এটি করার পরম দ্রুততম উপায় কী হবে? ইনলাইন সমাবেশ ব্যবহারের অনুমতি দেওয়া হয়। অন্যান্য 'কম মার্জিত' কৌশলগুলিও অনুমোদিত।


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

20
@ বিটব্যাঙ্ক: আপনি গত তিন দশকে সংকলকগুলির কতটা উন্নতি করেছে তা লক্ষ্য করা যায়। এআরএম স্পষ্টতই বেশ সংকলক-বান্ধব। এবং আমি এই বাস্তবতার জন্য জানি যে
জিসিসিতে

8
দুর্দান্ত প্রশ্ন, লোকেরা ভুলে যায় এমন বাস্তব বিশ্বের কেস রয়েছে যেখানে কর্মক্ষমতা গুরুত্বপূর্ণ matters অনেক বার এর মতো প্রশ্নের উত্তর দেওয়া হয় "just use stl"
কিক

14
"... একটি অ্যারের মাধ্যমে পুনরাবৃত্তি" শিরোনামটি বিভ্রান্তিকর কারণ যেহেতু আপনি কেবলমাত্র একটি নির্দিষ্ট মান অনুসন্ধান করছেন। একটি অ্যারের উপর পুনরাবৃত্তি বোঝা প্রতিটি এন্ট্রি কিছু করা উচিত। বাছাই করা, যদি ব্যয়টি অনেকগুলি অনুসন্ধানের উপরে সজ্জিত করা যায় তবে ভাষা বাস্তবায়নের বিষয়গুলির থেকে পৃথক হয়ে ওঠার পক্ষে একটি দক্ষ পদ্ধতি।
হার্ডম্যাথ

8
আপনি কি নিশ্চিত যে আপনি কেবল বাইনারি অনুসন্ধান বা হ্যাশ টেবিলটি ব্যবহার করতে পারবেন না? 256 আইটেমের জন্য একটি বাইনারি অনুসন্ধান == 8 তুলনা। একটি হ্যাশ টেবিল == গড়ে 1 লাফ (বা আপনার যদি একটি সঠিক হ্যাশ থাকে তবে 1 টি জাম্প সর্বাধিক )। আপনার 1) একটি সন্ধানের শালীন অ্যালগরিদম ( O(1)বা এর O(logN)সাথে তুলনা করে O(N)) পাওয়ার পরে কেবল অ্যাসেম্বলি অপ্টিমাইজেশনের অবলম্বন করা উচিত এবং 2) আপনি এটিকে বাধা হিসাবে চিহ্নিত করেছেন।
গ্রো

উত্তর:


105

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

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

; r0 = count, r1 = source ptr, r2 = comparison value

   stmfd sp!,{r4-r11}   ; save non-volatile registers
   mov r3,r0,LSR #3     ; loop count = total count / 8
   pld [r1,#128]
   ldmia r1!,{r4-r7}    ; pre load first set
loop_top:
   pld [r1,#128]
   ldmia r1!,{r8-r11}   ; pre load second set
   cmp r4,r2            ; search for match
   cmpne r5,r2          ; use conditional execution to avoid extra branch instructions
   cmpne r6,r2
   cmpne r7,r2
   beq found_it
   ldmia r1!,{r4-r7}    ; use 2 sets of registers to hide load delays
   cmp r8,r2
   cmpne r9,r2
   cmpne r10,r2
   cmpne r11,r2
   beq found_it
   subs r3,r3,#1        ; decrement loop count
   bne loop_top
   mov r0,#0            ; return value = false (not found)
   ldmia sp!,{r4-r11}   ; restore non-volatile registers
   bx lr                ; return
found_it:
   mov r0,#1            ; return true
   ldmia sp!,{r4-r11}
   bx lr

আপডেট: মন্তব্যগুলিতে প্রচুর সংশয়ী আছেন যারা মনে করেন যে আমার অভিজ্ঞতাটি বিবৃত / মূল্যহীন এবং প্রমাণ প্রয়োজন require অপ্টিমাইজেশন -O2 ( লুপ আন্রোলিং সহ সমস্ত অপ্টিমাইজেশন চালু হয়েছে) দিয়ে নিম্নলিখিত আউটপুট তৈরি করতে আমি জিসিসি 4.8 (অ্যান্ড্রয়েড এনডিকে 9 সি থেকে ) ব্যবহার করেছি। আমি উপরের প্রশ্নে উপস্থাপিত মূল সি কোডটি সংকলিত করেছি। জিসিসি যা তৈরি করেছিল তা এখানে:

.L9: cmp r3, r0
     beq .L8
.L3: ldr r2, [r3, #4]!
     cmp r2, r1
     bne .L9
     mov r0, #1
.L2: add sp, sp, #1024
     bx  lr
.L8: mov r0, #0
     b .L2

জিসিসির আউটপুট কেবল লুপটি আনারোল করে না, তবে এলডিআরের পরে স্টলে একটি ঘড়িও অপচয় করে। এটিতে অ্যারে উপাদানগুলির জন্য কমপক্ষে 8 টি ঘড়ি প্রয়োজন। লুপটি কখন প্রস্থান করতে হবে তা জানার জন্য এটি ঠিকানাটি ব্যবহার করার একটি ভাল কাজ করে তবে জাদুকরী জিনিসগুলির সমস্ত সংকলকরা এই কোডটিতে খুঁজে পাওয়া যায় না। আমি লক্ষ্য প্ল্যাটফর্মে কোডটি চালাচ্ছি না (আমার নিজস্ব নেই) তবে এআরএম কোড পারফরম্যান্সে যে কেউ অভিজ্ঞ সে দেখতে পাবে যে আমার কোডটি দ্রুত is

আপডেট 2: আমি মাইক্রোসফ্টের ভিজ্যুয়াল স্টুডিও 2013 এসপি 2- কে কোড দিয়ে আরও ভাল করার সুযোগ দিয়েছি। এটি আমার অ্যারে প্রারম্ভিকরণটিকে ভেক্টরাইজ করার জন্য নিওন নির্দেশাবলী ব্যবহার করতে সক্ষম হয়েছিল, তবে ওপি দ্বারা লিখিত রৈখিক মান অনুসন্ধান জিসিসি যা তৈরি করেছিল তার সাথে মিল খুঁজে পেয়েছিল (আমি এটিকে আরও পঠনযোগ্য করার জন্য লেবেলের নামকরণ করেছি):

loop_top:
   ldr  r3,[r1],#4  
   cmp  r3,r2  
   beq  true_exit
   subs r0,r0,#1 
   bne  loop_top
false_exit: xxx
   bx   lr
true_exit: xxx
   bx   lr

যেমনটি আমি বলেছি, আমি ওপি-র সঠিক হার্ডওয়্যারটির মালিক নই, তবে আমি একটি এনভিডিয়া টেগ্রা 3 এবং টেগড়া 4 3 টি বিভিন্ন সংস্করণে পারফরম্যান্সটি পরীক্ষা করব এবং শীঘ্রই ফলাফলগুলি এখানে পোস্ট করব।

আপডেট 3: আমি আমার কোড এবং মাইক্রোসফ্টের সংকলিত এআরএম কোডটি একটি টেগ্রা 3 এবং টেগ্রা 4 (সারফেস আরটি, সারফেস আরটি 2) তে চালিত করেছি। আমি একটি লুপের 1000000 পুনরাবৃত্তি চালিয়েছি যা কোনও মিল খুঁজে পেতে ব্যর্থ হয় যাতে সবকিছু ক্যাশে থাকে এবং এটি পরিমাপ করা সহজ।

             My Code       MS Code
Surface RT    297ns         562ns
Surface RT 2  172ns         296ns  

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


13
@ লুভানহফ্যাক - এটি সাধারণত সত্য তবে টাইট আইএসআর হ'ল অন্যতম ব্যতিক্রম, এতে আপনি প্রায়শই কম্পাইলারের চেয়ে অনেক বেশি জানেন।
সাপি

47
শয়তানের উকিল: এই কোডটি দ্রুত হওয়ার কোনও পরিমাণগত প্রমাণ আছে কি?
অলিভার চার্লসওয়ার্থ

11
@ বিটব্যাঙ্ক: এটি যথেষ্ট ভাল নয়। আপনাকে প্রমাণ সহ আপনার দাবির ব্যাক আপ করতে হবে ।
bit

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

14
"মন্তব্যগুলিতে সংশয়ীরা যারা মনে করেন যে আমার অভিজ্ঞতাটি বিবরণী / মূল্যহীন এবং প্রমাণ প্রয়োজন require" তাদের মন্তব্য অতিরিক্ত নেতিবাচক গ্রহণ করবেন না। প্রমাণ দেখানো আপনার দুর্দান্ত উত্তরটিকে আরও অনেক ভাল করে তোলে।
কোডি গ্রে

87

এটি অনুকূলকরণের জন্য একটি কৌশল আছে (আমাকে একবার এই কাজের জন্য একটি সাক্ষাত্কারে জিজ্ঞাসা করা হয়েছিল):

  • অ্যারেতে সর্বশেষ এন্ট্রি যদি আপনি যে মানটি খুঁজছেন তা ধরে রাখে, তবে সত্যটিতে ফিরে আসুন
  • অ্যারের শেষ প্রবেশের জন্য আপনি যে মানটি সন্ধান করছেন তা লিখুন
  • আপনি যে মানটির সন্ধান করছেন তাতে আপনার মুখোমুখি না হওয়া অবধি অ্যারেটি আটকান
  • অ্যারেতে প্রবেশের আগে যদি আপনি এটির মুখোমুখি হয়ে থাকেন তবে সত্য ফিরে আসুন
  • মিথ্যা প্রত্যাবর্তন

bool check(uint32_t theArray[], uint32_t compareVal)
{
    uint32_t i;
    uint32_t x = theArray[SIZE-1];
    if (x == compareVal)
        return true;
    theArray[SIZE-1] = compareVal;
    for (i = 0; theArray[i] != compareVal; i++);
    theArray[SIZE-1] = x;
    return i != SIZE-1;
}

এটি পুনরাবৃত্তির জন্য দুটি শাখার পরিবর্তে পুনরাবৃত্তির জন্য একটি শাখা দেয়।


হালনাগাদ:

যদি আপনাকে অ্যারে বরাদ্দ করার অনুমতি দেওয়া হয় SIZE+1তবে আপনি "শেষ প্রবেশের অদলবদল" অংশটি থেকে মুক্তি পেতে পারেন:

bool check(uint32_t theArray[], uint32_t compareVal)
{
    uint32_t i;
    theArray[SIZE] = compareVal;
    for (i = 0; theArray[i] != compareVal; i++);
    return i != SIZE;
}

আপনি এর theArray[i]পরিবর্তে নিম্নলিখিত ব্যবহার করে এম্বেড করা অতিরিক্ত পাটিগণিত থেকে মুক্তি পেতে পারেন :

bool check(uint32_t theArray[], uint32_t compareVal)
{
    uint32_t *arrayPtr;
    theArray[SIZE] = compareVal;
    for (arrayPtr = theArray; *arrayPtr != compareVal; arrayPtr++);
    return arrayPtr != theArray+SIZE;
}

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


2
@ratchetfreak: এই অ্যারে কীভাবে, কোথায় এবং কখন বরাদ্দ করা হয় এবং কীভাবে শুরু করা হয় সে সম্পর্কে কোনও বিবরণ সরবরাহ করে না, তাই আমি একটি উত্তর দিয়েছি যা তার উপর নির্ভর করে না।
বারাক মানোস

3
অ্যারে র‌্যামে রয়েছে, যদিও লেখার অনুমতি নেই।
wlamers 14

1
দুর্দান্ত, তবে অ্যারে আর নেই const, যা এটি থ্রেড-নিরাপদ করে না। দাম দেওয়ার মতো মনে হয় price
ইওএফ

2
@ ইওএফ: constপ্রশ্নটিতে কখন উল্লেখ করা হয়েছিল?
বারাক মানোস

4
@ বরাকমানোস: আমি যদি আপনাকে একটি অ্যারে এবং একটি মান পাস করি এবং মানটি অ্যারেতে রয়েছে কিনা তা আপনাকে জিজ্ঞাসা করি, তবে আমি সাধারণত ধরে নিই না যে আপনি অ্যারেটি সংশোধন করছেন। মূল প্রশ্নে constনা থ্রেডের কথা উল্লেখ করা হয়েছে তবে আমি মনে করি এই সতর্কতার কথা উল্লেখ করা মোটেই উপযুক্ত।
ইওএফ

62

আপনি আপনার অ্যালগরিদমকে অনুকূল করে তোলার জন্য সহায়তা চাইছেন, যা আপনাকে এসেম্বলারের দিকে চাপ দিতে পারে। তবে আপনার অ্যালগরিদম (একটি লিনিয়ার সন্ধান) এত চালাক নয়, তাই আপনার অ্যালগরিদম পরিবর্তন করার বিষয়টি বিবেচনা করা উচিত। উদাহরণ:

পারফেক্ট হ্যাশ ফাংশন

যদি আপনার 256 "বৈধ" মানগুলি স্থির হয় এবং সংকলনের সময় পরিচিত হয়, তবে আপনি একটি নিখুঁত হ্যাশ ফাংশন ব্যবহার করতে পারেন । আপনাকে একটি হ্যাশ ফাংশনটি সন্ধান করতে হবে যা আপনার ইনপুট মানকে 0 .. n রেঞ্জের মান হিসাবে মানচিত্র করে , যেখানে আপনার যত্ন নেওয়া সমস্ত বৈধ মানগুলির জন্য কোনও সংঘর্ষ নেই । এটি হ'ল একই আউটপুট মানের দুটি "বৈধ" মান হ্যাশ। একটি ভাল হ্যাশ ফাংশন অনুসন্ধান করার সময়, আপনি লক্ষ্য:

  • হ্যাশ ফাংশনটি যুক্তিসঙ্গতভাবে দ্রুত রাখুন।
  • ছোট করা n । আপনি যে ক্ষুদ্রতমটি পেতে পারেন তা হ'ল 256 (সর্বনিম্ন নিখুঁত হ্যাশ ফাংশন), তবে এটি সম্ভবত ডেটাগুলির উপর নির্ভর করে অর্জন করা শক্ত।

দক্ষ হ্যাশ ফাংশনগুলির জন্য নোট, এন প্রায়শই 2 এর শক্তি, যা কম বিটগুলির একটি বিটওয়াস্ক মাস্কের সমান (এবং অপারেশন)। হ্যাশ ফাংশন উদাহরণ:

  • ইনপুট বাইটের সিআরসি, মডুলো এন
  • ((x << i) ^ (x >> j) ^ (x << k) ^ ...) % n(অনেক হিসাবে অবচয় i, j, k, ... প্রয়োজন মতো বাম বা ডান বদল আনতে সঙ্গে)

তারপর আপনি একটি নির্দিষ্ট টেবিল তৈরী এন এন্ট্রি, যেখানে হ্যাশ একটি সূচক ইনপুট মান মানচিত্র আমি টেবিল মধ্যে। বৈধ মানগুলির জন্য, সারণি এন্ট্রি i তে মান মান থাকে। অন্য সব টেবিল এন্ট্রি জন্য, নিশ্চিত করুন যে সূচক প্রতিটি প্রবেশ আমি অন্য কিছু অবৈধ মান যা হ্যাশ না ধারণ করে আমি

তারপরে আপনার বাধা রুটিনে, ইনপুট এক্স সহ :

  1. সূচক i থেকে হ্যাশ এক্স (যা 0..n এর মধ্যে রয়েছে)
  2. এন্ট্রি দেখুন আমি টেবিলে করুন এবং দেখুন এটি মান রয়েছে এক্স

এটি 256 বা 1024 মানের লিনিয়ার অনুসন্ধানের চেয়ে অনেক দ্রুত হবে।

যুক্তিসঙ্গত হ্যাশ ফাংশনগুলি খুঁজে পেতে আমি পাইথন কোডটি লিখেছি

বাইনারি অনুসন্ধান

আপনি যদি 256 "বৈধ" মানগুলির অ্যারেটি সাজান, তবে আপনি রৈখিক অনুসন্ধানের পরিবর্তে বাইনারি অনুসন্ধান করতে পারেন । এর অর্থ আপনার কেবলমাত্র 8 টি ধাপে 256-প্রবেশের টেবিল log2(256)বা 10 ধাপে 1024-এন্ট্রি টেবিলটি সন্ধান করতে সক্ষম হওয়া উচিত । আবার, এটি 256 বা 1024 মানের একটি লিনিয়ার অনুসন্ধানের চেয়ে অনেক দ্রুত হবে।


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

11
প্রকৃতপক্ষে, আপনার কোডটি (যেমন সমাবেশ বা অন্যান্য কৌশল ব্যবহার করে) অপ্টিমাইজ করার চেষ্টা করার আগে আপনার অবশ্যই দেখা উচিত যে আপনি অ্যালগরিদমিক জটিলতা হ্রাস করতে পারেন কিনা। সাধারণত অ্যালগরিদমিক জটিলতা হ্রাস করা কয়েকটি চক্র বাদ দেওয়ার চেষ্টা করার চেয়ে একই অ্যালগরিদমিক জটিলতা রাখার চেয়ে বেশি দক্ষ হবে।
ysdx

3
বাইনারি অনুসন্ধানের জন্য +1। অ্যালগরিদমিক পুনঃ-নকশাটি অনুকূলিত করার সর্বোত্তম উপায় best
রকেটম্যাগনেট

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

60

সাজানো ক্রমে টেবিলটি রাখুন এবং বেন্টলির অনিবন্ধিত বাইনারি অনুসন্ধান ব্যবহার করুন:

i = 0;
if (key >= a[i+512]) i += 512;
if (key >= a[i+256]) i += 256;
if (key >= a[i+128]) i += 128;
if (key >= a[i+ 64]) i +=  64;
if (key >= a[i+ 32]) i +=  32;
if (key >= a[i+ 16]) i +=  16;
if (key >= a[i+  8]) i +=   8;
if (key >= a[i+  4]) i +=   4;
if (key >= a[i+  2]) i +=   2;
if (key >= a[i+  1]) i +=   1;
return (key == a[i]);

এই পয়েন্ট টি,

  • আপনি যদি টেবিলটি কত বড় তা জানেন তবে কতগুলি পুনরাবৃত্তি ঘটবে তা আপনি জানেন, তাই আপনি এটি সম্পূর্ণরূপে আনআরোল করতে পারবেন।
  • তারপরে, ==প্রতিটি পুনরাবৃত্তির ক্ষেত্রে কেসটির কোনও বিন্দু পরীক্ষা নেই কারণ শেষ পুনরাবৃত্তিকে বাদ দিয়ে, এই মামলার সম্ভাবনা খুব কম এটির জন্য সময় ব্যয় করার সময়কে ন্যায়সঙ্গত করতে পারে না * **
  • শেষ অবধি, টেবিলটিকে 2 পাওয়ার হিসাবে প্রসারিত করে আপনি সর্বাধিক একটি তুলনা এবং দুটি সঞ্চয়স্থানের একটি ফ্যাক্টর যুক্ত করুন।

** আপনি যদি সম্ভাবনার দিক থেকে চিন্তা করতে অভ্যস্ত না হন তবে প্রতিটি সিদ্ধান্ত পয়েন্টের একটি এনট্রপি থাকে যা এটি সম্পাদন করে আপনি যে গড় গড় তথ্য শিখেন। জন্য >=পরীক্ষা, প্রতিটি শাখার সম্ভাবনা, 0.5, এবং -log2 (0.5) 1 সম্পর্কে তাই মানে আপনি এক শাখা নিতে আপনি 1 বিট শিখতে, এবং যদি আপনি অন্যান্য শাখা নিতে আপনি এক বিট, এবং গড় জানতে পারি যে, প্রতিটি শাখায় আপনি যা শিখেন তার যোগফল এটি সেই শাখার সম্ভাবনার সময়। সুতরাং 1*0.5 + 1*0.5 = 1, >=পরীক্ষার এনট্রপিটি 1। যেহেতু আপনার কাছে 10 টি বিট শিখতে হবে তাই এটি 10 ​​টি শাখা নেয়। যে কারণে এটি দ্রুত!

অন্যদিকে, যদি আপনার প্রথম পরীক্ষা হয় if (key == a[i+512)? সত্য হওয়ার সম্ভাবনাটি 1/1024, এবং মিথ্যাটির সম্ভাবনা 1023/1024 হয়। সুতরাং যদি এটি সত্য হয় তবে আপনি সমস্ত 10 বিট শিখবেন! তবে এটি মিথ্যা হলে আপনি -log2 (1023/1024) = .00141 বিট শিখেন, কার্যত কিছুই নয়! সুতরাং আপনি যে পরীক্ষাটি থেকে গড় পরিমাণ শিখেন তা হ'ল 10/1024 + .00141*1023/1024 = .0098 + .00141 = .0112বিট। প্রায় এক শততম। সেই পরীক্ষায় তার ওজন বহন হচ্ছে না!


4
আমি এই সমাধানটি সত্যিই পছন্দ করি। যদি মানটির অবস্থানটি সংবেদনশীল তথ্য থাকে তবে সময় ভিত্তিক ফরেনসিক এড়ানোর জন্য একটি নির্দিষ্ট সংখ্যক চক্রটি চালানোর জন্য এটি পরিবর্তন করা যেতে পারে।
অরেগন ট্রেইল

1
@ অরেগন ট্রেইল: সময় ভিত্তিক ফরেনসিক? মজাদার সমস্যা, তবে দুঃখজনক মন্তব্য।
মাইক ডুনলাভে

16
টাইমিং অ্যাটাকগুলি en.wikedia.org/wiki/Timing_attack রোধ করতে আপনি ক্রিপ্টো লাইব্রেরিতে এ জাতীয় অনিয়ন্ত্রিত লুপগুলি দেখতে পান । এখানে github.com/jedisct1/libsium/blob/… একটি ভাল উদাহরণ দেওয়া আছে এক্ষেত্রে আমরা কোনও আক্রমণকারীকে স্ট্রিংয়ের দৈর্ঘ্য অনুমান করা থেকে বিরত করছি। সাধারণত আক্রমণকারী একটি সময় আক্রমণ করার জন্য একটি ফাংশন অনুরোধের কয়েক মিলিয়ন নমুনা নেবে।
ওরেগনট্রাইল

3
+1 দুর্দান্ত! দুর্দান্ত সামান্য নিবন্ধিত অনুসন্ধান আমি এর আগে দেখিনি। আমি এটি ব্যবহার করতে পারে।
রকেটম্যাগনেট

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

16

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

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

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

অন্য একটি ভাবনা: যদি আপনার প্রসেসরটি অত্যন্ত দ্রুত হয় তবে নিখুঁত হ্যাশ থেকে মেমরির জন্য একটি তদন্ত সম্ভবত মৃত্যুদন্ডের সময়কে প্রাধান্য দেয়। প্রসেসরটি যদি খুব দ্রুত না হয় তবে কে> 1 টি প্রোব ব্যবহারিক হতে পারে।


1
একটি কর্টেক্স-এম অত্যন্ত দ্রুতগতির কাছাকাছি কোথাও নেই ।
এমসাল্টারস

2
আসলে এই ক্ষেত্রে তার কোনও হ্যাশ টেবিলের দরকার নেই। সে কেবলমাত্র একটি নির্দিষ্ট কীটি সেটে রয়েছে কিনা তা জানতে চায়, সে এটির কোনও মানচিত্র মানচিত করতে চায় না। সুতরাং এটি যথেষ্ট যদি নিখুঁত হ্যাশ ফাংশনটি প্রতিটি 32 বিটের মান 0 বা 1 তে মানচিত্র করে যেখানে "1" "সেটটিতে রয়েছে" হিসাবে সংজ্ঞায়িত হতে পারে।
ডেভিড ওঙ্গারো

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

@ ডেভিডওঙ্গারো table[PerfectHash(value)] == value1 টি মান দেয় যদি মানটি সেটে থাকে এবং 0 না থাকলে, এবং পারফেক্টহ্যাশ ফাংশনটি তৈরি করার জন্য সুপরিচিত উপায় রয়েছে (দেখুন, উদাহরণস্বরূপ, বার্লটবার্টটনেট / বব / হ্যাশ / স্পেক.এইচটিএমএল )। একটি হ্যাশ ফাংশন সন্ধান করার চেষ্টা করা যা সেটটিতে সমস্ত মানকে 1 এ সরাসরি মানচিত্র করে এবং 0 তে সেট না করে সমস্ত মানকে বোকা বানানো কাজ।
জিম বাল্টার

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

14

একটি হ্যাশ সেট ব্যবহার করুন। এটি ও (1) দেখার সময় দেবে।

নিম্নলিখিত কোডটি ধরে নিয়েছে যে আপনি 0একটি 'খালি' মান হিসাবে মান সংরক্ষণ করতে পারবেন , অর্থাত্ প্রকৃত ডেটাতে ঘটে না। সমাধানটি এমন পরিস্থিতির জন্য প্রসারিত করা যেতে পারে যেখানে এটি নয়।

#define HASH(x) (((x >> 16) ^ x) & 1023)
#define HASH_LEN 1024
uint32_t my_hash[HASH_LEN];

int lookup(uint32_t value)
{
    int i = HASH(value);
    while (my_hash[i] != 0 && my_hash[i] != value) i = (i + 1) % HASH_LEN;
    return i;
}

void store(uint32_t value)
{
    int i = lookup(value);
    if (my_hash[i] == 0)
       my_hash[i] = value;
}

bool contains(uint32_t value)
{
    return (my_hash[lookup(value)] == value);
}

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


3
এটি কার্যকর হওয়ার জন্য এই অনুসন্ধান কতবার করতে হবে তার উপর নির্ভর করে।
maxywb

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

@ জিমবাল্টার সত্য, নিখুঁত কোড নয়। আরও সাধারণ ধারণা মত; স্রেফ বিদ্যমান হ্যাশ সেট কোডের দিকে ইঙ্গিত করতে পারে। তবে এটি একটি বিঘ্নিত পরিষেবার রুটিন হিসাবে বিবেচনা করে দেখাতে কার্যকর হতে পারে যে চেহারা খুব জটিল কোড নয়।
jpa

আপনার ঠিক ঠিক করা উচিত যাতে এটি আমার চারপাশে জড়িয়ে যায়।
জিম বাল্টার

একটি নিখুঁত হ্যাশ ফাংশনটির বিন্দুটি হ'ল এটি একটি প্রোব করে। সময়কাল।
ইরা

10

এই ক্ষেত্রে, এটি ব্লুম ফিল্টারগুলি তদন্ত করা সার্থক হতে পারে । তারা দ্রুত এটি স্থাপনে সক্ষম হয় যে কোনও মান উপস্থিত নেই, যা খুব ভাল যেহেতু বেশিরভাগ 2 ^ 32 সম্ভাব্য মান 1024 উপাদান অ্যারেতে নেই। তবে, কিছু মিথ্যা ইতিবাচক রয়েছে যাগুলির জন্য একটি অতিরিক্ত চেক প্রয়োজন need

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


1
মজার বিষয়, এর আগে আমি ব্লুম ফিল্টারগুলি দেখিনি।
রকেটম্যাগনেট

8

আপনার প্রসেসরটি 204 মেগাহার্টজ এ চলেছে যা LPC4357 এর পক্ষে সর্বাধিক বলে মনে হচ্ছে এবং আপনার সময়সীমার ফলাফলটি গড় কেসটিকে প্রতিফলিত করে (অ্যারে পেরিয়ে যাওয়া অর্ধেক), আমরা পেয়েছি:

  • সিপিইউ ফ্রিকোয়েন্সি: 204 মেগাহার্টজ
  • চক্র সময়কাল: 4.9 এনএস
  • চক্রের সময়কাল: 12.5 /s / 4.9 এনএস = 2551 চক্র
  • পুনরাবৃত্তি প্রতি চক্র: 2551/128 = 19.9

সুতরাং, আপনার অনুসন্ধান লুপটি পুনরাবৃত্তির জন্য প্রায় 20 চক্র ব্যয় করে। এটি ভয়াবহ শোনায় না, তবে আমি অনুমান করি যে এটি দ্রুততর করার জন্য আপনার সমাবেশটি তাকাতে হবে।

আমি সূচিটি বাদ দেওয়ার পরিবর্তে একটি পয়েন্টার তুলনা এবং সমস্ত পয়েন্টার তৈরি করার পরামর্শ দেব const

bool arrayContains(const uint32_t *array, size_t length)
{
  const uint32_t * const end = array + length;
  while(array != end)
  {
    if(*array++ == 0x1234ABCD)
      return true;
  }
  return false;
}

এটি অন্তত পরীক্ষার জন্য মূল্যবান।


1
-1, এআরএমের একটি সূচিযুক্ত ঠিকানা মোড রয়েছে তাই এটি অর্থহীন। পয়েন্টার তৈরির জন্য const, জিসিসি ইতিমধ্যে দাগী যে এটি পরিবর্তন হয় না। না constহয় কিছু যোগ হয় না।
এমসাল্টারস

11
@MSalters ঠিক আছে, আমি কোডটি সঙ্গে যাচাই করা হয়নি, পয়েন্ট কিছু যে এটা সি পর্যায়ে সহজ করে তোলে প্রকাশ করার ছিল, এবং আমি শুধু একটি পয়েন্টার পরিবর্তে পয়েন্টার পরিচালনার মনে করি এবং একটি সূচক হয় সহজ। আমি কেবল একমত নই যে " const" কিছু যুক্ত করে না ": এটি খুব স্পষ্টভাবে পাঠককে বলে যে মান পরিবর্তন হবে না। এটি দুর্দান্ত তথ্য।
বিনোদন

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

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

6

অন্যান্য ব্যক্তিরা আপনার টেবিলটিকে পুনর্গঠিত করার জন্য, শেষে একটি সেন্ডিনেল মান যুক্ত করতে বা বাইনারি অনুসন্ধান সরবরাহ করার জন্য এটি বাছাই করার পরামর্শ দিয়েছেন।

আপনি উল্লেখ করেছেন "আমি পয়েন্টার গাণিতিক এবং লুপের জন্য একটিও ব্যবহার করি, যা উপরের পরিবর্তে ডাউন-কাউন্টিং করে (চেক করার i != 0চেয়ে দ্রুত কিনা তা পরীক্ষা করা হয় i < 256)"।

আমার প্রথম পরামর্শটি হ'ল: পয়েন্টার গাণিতিক এবং ডাউনকাউন্টিং থেকে মুক্তি পান। স্টাফ পছন্দ

for (i=0; i<256; i++)
{
    if (compareVal == the_array[i])
    {
       [...]
    }
}

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

উদাহরণস্বরূপ, উপরের কোডটি সূচক বন্ধ -256বা -255শূন্য থেকে চলমান লুপে সংকলিত হতে পারে &the_array[256]। সম্ভবত এমন স্টাফ যা বৈধ সি তেও প্রকাশযোগ্য নয় তবে আপনি যে মেশিনটি তৈরি করছেন তার আর্কিটেকচারের সাথে মেলে।

তাই মাইক্রোপটিমাইজ করবেন না । আপনি কেবল নিজের অপ্টিমাইজারের কাজগুলিতে স্প্যানার ফেলে দিচ্ছেন। আপনি যদি চালাক হতে চান, ডেটা স্ট্রাকচার এবং অ্যালগরিদমে কাজ করুন তবে তাদের এক্সপ্রেশনটি মাইক্রোপটিমাইজ করবেন না। এটি কেবল আপনাকে কাটাতে ফিরে আসবে, যদি বর্তমান সংকলক / আর্কিটেকচারে না থাকে তবে তার পরের দিকে।

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


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

3

ভেক্টরাইজেশন এখানে ব্যবহার করা যেতে পারে, কারণ এটি প্রায়শই মেমচারের প্রয়োগে হয়। আপনি নিম্নলিখিত অ্যালগরিদম ব্যবহার:

  1. আপনার ওএস'র বিট গণনা (-৪-বিট, ৩২-বিট, ইত্যাদি) এর সমান দৈর্ঘ্যে আপনার ক্যোয়ারির পুনরাবৃত্তি করার একটি মাস্ক তৈরি করুন। একটি 64-বিট সিস্টেমে আপনি 32-বিট ক্যোরিয়াকে দু'বার পুনরাবৃত্তি করবেন।

  2. একাধিক ডেটা একাধিক টুকরো তালিকা হিসাবে তালিকাটি প্রক্রিয়া করুন, কেবলমাত্র বৃহত্তর ডেটা টাইপের একটি তালিকাতে তালিকাটি কাস্ট করে এবং মানগুলি টেনে বের করে। প্রতিটি অংশের জন্য, এটি মাস্কের সাহায্যে XOR, তারপরে 0b0111 ... 1 দিয়ে এক্সওআর, তারপরে 1 যোগ করুন, তারপরে এবং 0b1000 ... 0 পুনরাবৃত্তি সহ একটি মুখোশ দিয়ে। ফলাফল যদি 0 হয় তবে অবশ্যই কোনও মিল নেই। অন্যথায়, (সাধারণত খুব উচ্চ সম্ভাবনার সাথে) মিল থাকতে পারে, তাই খণ্ডটি সাধারণত অনুসন্ধান করুন।

উদাহরণ প্রয়োগ: https://sourceware.org/cgi-bin/cvsweb.cgi/src/newlib/libc/string/memchr.c?rev=1.3&content-type=text/x-cvsweb-markup&cvsroot=src


3

আপনি যদি আপনার অ্যাপ্লিকেশনে উপলব্ধ মেমরির পরিমাণের সাথে যদি আপনার মানগুলির ডোমেনকে সমন্বিত করতে পারেন তবে দ্রুততম সমাধানটি হ'ল বিটের অ্যারে হিসাবে আপনার অ্যারের প্রতিনিধিত্ব করা:

bool theArray[MAX_VALUE]; // of which 1024 values are true, the rest false
uint32_t compareVal = 0x1234ABCD;
bool validFlag = theArray[compareVal];

সম্পাদনা

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

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


8
এটি কীভাবে 4 টি upvotes পায়? প্রশ্নটি বলে যে এটি একটি কর্টেক্স এম 4। জিনিসটির 266.144 কেবি নয়, 136 কেবি র‌্যাম রয়েছে।
এমসাল্টারস

1
এটি অবাক করে দেয় যে কতগুলি আপোভেট প্রকাশ্যে ভুল উত্তর দেওয়ার জন্য দেওয়া হয়েছিল কারণ উত্তরদাতারা গাছের জন্য বনটি মিস করেছেন। ওপির বৃহত্তম মামলার জন্য ও (লগ এন) << ও (এন)।
এমএসডাব্লু

3
আমি এমন প্রোগ্রামারদের কাছে খুব কৃপণ হয়ে উঠি যারা হাস্যকর পরিমাণে মেমরি পোড়ায়, যখন আরও ভাল সমাধান পাওয়া যায়। প্রতি 5 বছর পরে মনে হয় যে আমার পিসি স্মৃতিশক্তি থেকে চলেছে, যেখানে 5 বছর আগে সেই পরিমাণ ছিল প্রচুর।
ক্রেগ ম্যাককুইন

1
আজকাল ক্রেইগএমসিউইউন বাচ্চাগুলি স্মৃতি নষ্ট করছে। অগণিত! আমার দিনগুলিতে, আমাদের কাছে 1 এমআইবি মেমরি এবং 16-বিটের শব্দের আকার ছিল। / s
কোল জনসন

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

1

নিশ্চিত করুন যে নির্দেশাবলী ("সিউডো কোড") এবং ডেটা ("দ্য অ্যারে") আলাদা (র‌্যাম) স্মৃতিতে রয়েছে যাতে সিএম 4 হার্ভার্ড আর্কিটেকচারটি তার সম্পূর্ণ সম্ভাবনার জন্য ব্যবহার হয়। ব্যবহারকারীর ম্যানুয়াল থেকে:

এখানে চিত্র বর্ণনা লিখুন

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


আকর্ষণীয়, কর্টেক্স-এম 7 এর alচ্ছিক নির্দেশনা / ডেটা ক্যাশে রয়েছে তবে এর আগে অবশ্যই তা হয় নি। en.wikedia.org/wiki/ARM_Cortex-M#Silicon_customization
পিটার কর্ডেস

0

আমার উত্তরটি ইতিমধ্যে উত্তর দেওয়া থাকলে আমি দুঃখিত - কেবল আমি একটি অলস পাঠক। তখন আপনাকে ডাউনটাতে নির্দ্বিধায় অনুভব করুন))

1) আপনি কাউন্টার 'i' কে একেবারে মুছে ফেলতে পারেন - কেবল পয়েন্টারগুলির সাথে তুলনা করুন, অর্থাত্‍

for (ptr = &the_array[0]; ptr < the_array+1024; ptr++)
{
    if (compareVal == *ptr)
    {
       break;
    }
}
... compare ptr and the_array+1024 here - you do not need validFlag at all.

সমস্ত কিছু যদিও কোনও উল্লেখযোগ্য উন্নতি দেয় না, এই ধরনের অপ্টিমাইজেশন সম্ভবত সংকলক নিজেই অর্জন করতে পারেন।

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

if (compareVal == the_array[0]) { validFlag = true; goto end_of_compare; }
if (compareVal == the_array[1]) { validFlag = true; goto end_of_compare; }
...and so on...
end_of_compare:

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

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

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

আপনি যদি মনে করেন যে 1024 উপাদানের অ্যারের জন্য রোলব্যাকটি আপনার ক্ষেত্রে খুব বড় ত্যাগ স্বরূপ, আপনি 'আংশিক রোলব্যাক' বিবেচনা করতে পারেন, উদাহরণস্বরূপ, অ্যারেটিকে 512 আইটেমের 2 অংশে বিভক্ত করা, বা 4x256 ইত্যাদি so

3) আধুনিক সিপিইউ প্রায়শই সিমডি অপ্সকে সমর্থন করে, উদাহরণস্বরূপ এআরএম নিওন নির্দেশিকা সেট - এটি সমান্তরালভাবে একই অপ্সকে সম্পাদন করতে দেয়। খোলামেলা কথা বললে আমি মনে করি না এটি তুলনা অপেশনের জন্য উপযুক্ত কিনা তবে আমার মনে হয় এটি হতে পারে, আপনার এটি পরীক্ষা করা উচিত। গুগলিং দেখায় যে সর্বাধিক গতি পেতে কিছু কৌশলও থাকতে পারে, https://stackoverflow.com/a/5734019/1028256 দেখুন

আমি আশা করি এটি আপনাকে কিছু নতুন ধারণা দিতে পারে।


ওপি লিনিয়ার লুপগুলি অনুকূলকরণের উপর দৃষ্টি নিবদ্ধ করে সমস্ত মূর্খ উত্তরগুলিকে বাইপাস করে এবং এর পরিবর্তে অ্যারেটি প্রেরণ করে এবং বাইনারি অনুসন্ধান করে।
জিম বাল্টার

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

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

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

0

আমি হ্যাশিংয়ের দুর্দান্ত অনুরাগী। অবশ্যই সমস্যাটি হ'ল একটি কার্যকর অ্যালগরিদম যা দ্রুত উভয়ই হয় এবং সর্বনিম্ন পরিমাণের মেমরি ব্যবহার করে (বিশেষত একটি এমবেডেড প্রসেসরের উপর)।

যদি আপনি আগে থেকেই মানগুলি জেনে থাকেন তবে আপনি এমন একটি প্রোগ্রাম তৈরি করতে পারেন যা প্রচুর পরিমাণে অ্যালগরিদমের মধ্য দিয়ে চলতে পারে - যা আপনার ডেটার জন্য সেরা পরামিতিগুলি সন্ধান করে।

আমি এমন একটি প্রোগ্রাম তৈরি করেছি যা আপনি এই পোস্টে পড়তে পারেন এবং খুব দ্রুত ফলাফল অর্জন করেছেন। বাইনারি অনুসন্ধান ব্যবহার করে মানটি খুঁজে পেতে 16000 এন্ট্রি মোটামুটি 2 ^ 14 বা 14 টি তুলনাতে অনুবাদ করে। আমি খুব দ্রুত অনুসন্ধানের জন্য স্পষ্টভাবে লক্ষ্য রেখেছি - গড়ে <= 1.5 লুপআপে মান খুঁজে পাওয়া - যার ফলে আরও বেশি র্যামের প্রয়োজনীয়তা দেখা দেয়। আমি বিশ্বাস করি যে আরও রক্ষণশীল গড় মান দিয়ে (বলুন <= 3) প্রচুর স্মৃতি সঞ্চয় করা যেতে পারে। তুলনা করে আপনার 256 বা 1024 এন্ট্রিগুলিতে বাইনারি অনুসন্ধানের গড় কেসটি যথাক্রমে 8 এবং 10 এর গড় সংখ্যার তুলনা করবে।

আমার গড় অনুসন্ধানের জন্য জেনেরিক অ্যালগরিদম (একটি ভেরিয়েবল দ্বারা একটি বিভাগকে ব্যবহার করে) এবং একটি বিশেষজ্ঞের (সম্ভবত কোনও গুণটি ব্যবহার করে) সঙ্গে 40-45 চক্র সহ প্রায় 60 টি চক্র (একটি ইনটেল আই 5 সহ একটি ল্যাপটপে) প্রয়োজন। এটি অবশ্যই আপনার এমসিইউতে উপ-মাইক্রোসেকেন্ড সন্ধানের সময়গুলিতে অনুবাদ করা উচিত, এটি নির্ভর করে ঘড়ির ফ্রিকোয়েন্সি অনুযায়ী।

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


0

এটি উত্তরের চেয়ে সংযোজনের মতো।

আমি অতীতেও একই রকম ঘটনা পেয়েছি, তবে আমার অ্যারে যথেষ্ট সংখ্যক অনুসন্ধানে স্থির ছিল।

তার অর্ধেকের মধ্যে, অনুসন্ধান করা মান অ্যারেতে উপস্থিত ছিল না। তখন আমি বুঝতে পারি যে কোনও অনুসন্ধান করার আগে আমি একটি "ফিল্টার" প্রয়োগ করতে পারি।

এই "ফিল্টার" কেবলমাত্র একটি সাধারণ পূর্ণসংখ্যার সংখ্যা, ওএনএসসি গণনা করা হয় এবং প্রতিটি অনুসন্ধানে ব্যবহৃত হয়।

এটি জাভাতে, তবে এটি বেশ সহজ:

binaryfilter = 0;
for (int i = 0; i < array.length; i++)
{
    // just apply "Binary OR Operator" over values.
    binaryfilter = binaryfilter | array[i];
}

সুতরাং, বাইনারি অনুসন্ধান করার আগে, আমি বাইনারিফিল্টার পরীক্ষা করি:

// Check binaryfilter vs value with a "Binary AND Operator"
if ((binaryfilter & valuetosearch) != valuetosearch)
{
    // valuetosearch is not in the array!
    return false;
}
else
{
    // valuetosearch MAYBE in the array, so let's check it out
    // ... do binary search stuff ...

}

আপনি একটি 'আরও ভাল' হ্যাশ অ্যালগরিদম ব্যবহার করতে পারেন, তবে এটি খুব দ্রুত হতে পারে, বিশেষত বৃহত সংখ্যার জন্য। এটি হতে পারে আপনাকে আরও চক্র বাঁচাতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.