একটি পূর্ণসংখ্যার সংখ্যা 2 দিয়ে ভাগ করার জন্য কোনটি ভাল বিকল্প?


406

2 দিয়ে পূর্ণসংখ্যা ভাগ করার জন্য নিম্নলিখিত কৌশলগুলির মধ্যে কোনটি সর্বোত্তম বিকল্প এবং কেন?

কৌশল 1:

x = x >> 1;

কৌশল 2:

x = x / 2;

এখানে xএকটি পূর্ণসংখ্যা


75
আপনি কি আসলেই ফলাফলের দায়িত্ব অর্পণ করতে চান, xএটা করা উচিত হয় আবার, তন্ন তন্ন এই ভাবে উপযুক্ত x >>= 1বা x /= 2কি অপারেশন সঙ্গে প্রকাশ করার মনস্থ করা উপর নির্ভর করে। এটি দ্রুত নয় কারণ (যে কোনও আধুনিক সংকলক যেভাবেই হোক, সমান তাত্ক্ষণিকভাবে সমস্ত সমতুল্য রূপগুলি সংকলন করবে) তবে এটি কম বিভ্রান্তিকর কারণ।
বাম দিকের বাইরে

33
বামদিকের সাথে আমি একমত নই - তবে আমি এটি উল্লেখযোগ্য বলে মনে করি যে অনেক প্রোগ্রামিং ভাষায় পাটিগণিত শিফট নামে একটি অপারেশন রয়েছে যা সাইনকে কিছুটা স্থানে রাখে এবং এর জন্য প্রত্যাশার মতো স্বাক্ষরিত মানগুলির জন্য কাজ করে। বাক্য গঠনটিও এর মতো হতে পারে x = x >>> 1। এছাড়াও নোট করুন যে প্ল্যাটফর্ম এবং সংকলকের উপর নির্ভর করে শিফটগুলি ব্যবহার করে বিভাগ এবং গুণগুলি ম্যানুয়ালি অপ্টিমাইজ করা বেশ যুক্তিসঙ্গত হতে পারে। - উদাহরণস্বরূপ, মাইক্রো কন্ট্রোলারদের চিন্তাভাবনা ডাব্লু / ও গুণিতকরণের জন্য সরাসরি ALU সমর্থন করে।
জিমিবি

36
আমি পছন্দ করি x /= 2কারণ x >>= 1দেখতে অনেকটা
মনাদিক

19
@ বামফ্রন্টাবাদ - আমি এটি লেখার x = x / 2পরিবর্তে আরও অনেক বেশি পাঠযোগ্য বলে মনে করি x /= 2
বিষয়গত

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

উত্তর:


847

আপনি যা করার চেষ্টা করছেন তার সর্বোত্তমভাবে বর্ণনা করে এমন অপারেশনটি ব্যবহার করুন।

  • আপনি যদি নম্বরটিকে বিটের ক্রম হিসাবে চিকিত্সা করে থাকেন তবে বিটশিফ্টটি ব্যবহার করুন।
  • আপনি যদি এটি একটি সংখ্যাসূচক মান হিসাবে বিবেচনা করে থাকেন তবে বিভাগটি ব্যবহার করুন।

মনে রাখবেন যে এগুলি ঠিক সমতুল্য নয়। তারা নেতিবাচক পূর্ণসংখ্যার জন্য বিভিন্ন ফলাফল দিতে পারে। উদাহরণ স্বরূপ:

-5 / 2  = -2
-5 >> 1 = -3

(Ideone)


20
মূল প্রশ্নটি 'সেরা' শব্দটি সম্পর্কেও অস্পষ্ট ছিল। 'সেরা' গতি, পাঠযোগ্যতা, শিক্ষার্থীদের চালিত করার পরীক্ষার প্রশ্ন ইত্যাদির ক্ষেত্রে ... 'সেরা' অর্থ কী তা ব্যাখ্যা করার অভাবে, এটি সবচেয়ে সঠিক উত্তর বলে মনে হয়।
রায়

47
C ++ 03 এ উভয়ই নেতিবাচক সংখ্যার জন্য সংজ্ঞা প্রয়োগ করা হয়েছে এবং একই ফলাফল দিতে পারে । সি ++ 11 এ বিভাগটি নেতিবাচক সংখ্যার জন্য ভালভাবে সংজ্ঞায়িত হয়েছে, তবে স্থানান্তর এখনও বাস্তবায়ন সংজ্ঞায়িত।
জেমস কানজে

2
যখন / এর সংজ্ঞাটি কার্যকর হয় (নেতিবাচক সংখ্যার জন্য বৃত্তাকার বা নিচে হয়) প্রারম্ভিক সি স্ট্যান্ডার্ডগুলিতে সংজ্ঞায়িত হয়। এটি সর্বদা% (মডুলো / বাকী অপারেটর) এর সাথে সামঞ্জস্য থাকতে হবে।
ctrl-alt-delor

7
"বাস্তবায়ন সংজ্ঞায়িত" এর অর্থ হ'ল সংকলকটির প্রয়োগকারী সাধারণত বেশ কয়েকটি বাস্তবায়নের পছন্দগুলির মধ্যে সাধারণত যথেষ্ট পরিমাণে বাধা সহ চয়ন করতে পেরেছিলেন। এখানে, এক বাধ্যতা যে %এবং /অপারেটরদের ইতিবাচক ও নেতিবাচক উভয় operands জন্য সামঞ্জস্যপূর্ণ, যাতে হওয়া আবশ্যক (a/b)*b+(a%b)==aলক্ষণ নির্বিশেষে সত্য aএবং b। সাধারণত, লেখক সিপিইউ থেকে সেরা সম্ভাব্য পারফরম্যান্স পাবেন এমন পছন্দগুলি করবেন।
আরবেরটিগ

6
সুতরাং যে কেউ "সংকলক এটিকে যে কোনও উপায়ে শিফটে রূপান্তরিত করবে" ভুল, তাইনা? সংকলক যদি গ্যারান্টি দিতে না পারে যে আপনি অ-নেতিবাচক পূর্ণসংখ্যার সাথে व्यवहार করছেন (তা এটি একটি ধ্রুবক বা এটি স্বাক্ষরযুক্ত স্বাক্ষরযুক্ত), এটি এটিকে স্থানান্তরিত করতে পারে না
কিপ

225

প্রথমটি কি ভাগ করার মতো দেখাচ্ছে? না। যদি আপনি ভাগ করতে চান, ব্যবহার করুন x / 2। সংকলক সম্ভব হলে বিট-শিফট ব্যবহার করতে এটি অনুকূল করতে পারে (এটিকে শক্তি হ্রাস বলা হয়), এটি যদি আপনি নিজেরাই করেন তবে এটি অকেজো মাইক্রো-অপ্টিমাইজেশন করে তোলে makes


15
অনেক সংকলক দু'জনের পাওয়ার দ্বারা বিটশিটে রূপান্তর করবেন না। এটি স্বাক্ষরিত পূর্ণসংখ্যার জন্য একটি ভুল অনুকূলকরণ হবে। আপনার নিজের সংকলক থেকে সমাবেশ আউটপুট দেখার চেষ্টা করা উচিত এবং নিজের জন্য দেখুন।
exDM69

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

9
@ exDM69: অনেক সংকলক এমনকি স্বাক্ষরিত পূর্ণসংখ্যার জন্যও এটি করবে এবং স্বাক্ষর অনুসারে এগুলি সামঞ্জস্য করবে। : এই জিনিস সাথে খেলতে একটি সুন্দর টুল এই হল tinyurl.com/6uww253
PlasmaHH

19
@ এক্সডিএম 69: এবং এটি প্রাসঙ্গিক, কীভাবে? আমি বললাম "সম্ভব হলে", "সর্বদা" না। যদি অপ্টিমাইজেশনটি ভুল হয় তবে ম্যানুয়ালি এটি করা এটি সঠিক করে না (প্লাস হিসাবে উল্লিখিত, স্বাক্ষরিত পূর্ণসংখ্যার জন্য যথাযথ প্রতিস্থাপনের জন্য জিসিসি যথেষ্ট স্মার্ট)।
ক্যাট প্লাস প্লাস

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

189

গাদা করতে: ব্যবহার করার পক্ষে অনেকগুলি কারণ রয়েছে x = x / 2; এখানে কয়েকটি:

  • এটি আপনার অভিপ্রায়টি আরও স্পষ্টভাবে প্রকাশ করে (ধরে নিবেন আপনি বিট টুইডলিং রেজিস্ট্রার বিট বা অন্য কিছু নিয়ে কাজ করছেন না)

  • সংকলক যেকোন উপায়ে শিফট অপারেশনে এটি হ্রাস করবে

  • এমনকি সংকলকটি এটি হ্রাস না করে এবং শিফ্টের চেয়ে ধীরে ধীরে অপারেশন বেছে নিয়েছে, এটি আপনার প্রোগ্রামের পরিমাপযোগ্য উপায়ে প্রভাবিত হওয়ার সম্ভাবনাটি নিজেই অদৃশ্যভাবে ছোট (এবং এটি যদি পরিমাপকভাবে এটি প্রভাবিত করে) তবে আপনার কাছে একটি বাস্তব আছে শিফট ব্যবহারের কারণ)

  • বিভাগটি যদি একটি বৃহত্তর অভিব্যক্তির অংশ হতে চলেছে, আপনি বিভাগ অপারেটরটি ব্যবহার করেন তবে আপনি ঠিক অগ্রাধিকার পাওয়ার সম্ভাবনা বেশি পাবেন:

    x = x / 2 + 5;
    x = x >> 1 + 5;  // not the same as above
  • স্বাক্ষরিত গাণিতিকগুলি উপরে বর্ণিত অগ্রাধিকার সমস্যার চেয়ে জিনিসগুলিকে আরও জটিল করে তুলতে পারে

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

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


5
এটি আরও যোগ করার মতো যে এখানে অগ্রাধিকারের নিয়ম থাকা সত্ত্বেও, প্রথম বন্ধনী ব্যবহারের ক্ষেত্রে কোন খারাপ জিনিস নেই। কিছু উত্পাদনের কোডটি পুনর্নির্মাণের সময়, আমি প্রকৃতপক্ষে ফর্মের কিছু দেখতে পেলাম a/b/c*d(যেখানে a..dসংখ্যার ভেরিয়েবলগুলি বোঝানো হয়েছে) তার চেয়ে বেশি পঠনযোগ্য (a*d)/(b*c)

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

4
@ জ্যাকমনে, যদি কোনও সম্ভাবনা থাকে a*dবা b*cএকটি ওভারফ্লো উত্পাদন করে তবে কম পাঠযোগ্য ফর্মটি সমতুল্য নয় এবং এর সুস্পষ্ট সুবিধা রয়েছে has পিএস আমি সম্মত হই যে বন্ধনীগুলি আপনার সেরা বন্ধু are
মার্ক রান্সম

@ মার্করানসাম - একটি ন্যায্য পয়েন্ট (যদিও আমি a/b/c*dআর কোডে চলেছি - এমন একটি প্রসঙ্গে যেখানে উপচে পড়ার অর্থ এই যে ডেটার সাথে কিছু গুরুতর ভুল ছিল - এবং সি কোডের একটি কার্য সম্পাদন-সমালোচনামূলক ব্লক নয়)।

কোডটি x=x/2;কেবলমাত্র "স্পষ্ট" এর চেয়ে বেশি x>>=1তবে xকখনই বিজোড় negativeণাত্মক সংখ্যা হবে না বা কেউ একের পর এক ত্রুটি সম্পর্কে চিন্তা করে না। অন্যথায় x=x/2;এবং x>>=1;বিভিন্ন অর্থ আছে। যদি একটির যা প্রয়োজন তার দ্বারা গুণনকৃত মানটি x>>=1আমি বিবেচনা করি x = (x & ~1)/2বা তার চেয়ে পরিষ্কার হিসাবে বিবেচনা করব x = (x < 0) ? (x-1)/2 : x/2বা অন্য যে কোনও সূত্রকে আমি দুটি দ্বারা বিভাজনটি ব্যবহার করার কথা ভাবতে পারি। তেমনিভাবে যদি কারও দ্বারা গুণনের মান প্রয়োজন হয় তবে x/=2এটি এর চেয়ে পরিষ্কার ((x + ((unsigned)x>>31)>>1)
সুপারক্যাট

62

কোনটি সর্বোত্তম বিকল্প এবং কেন পূর্ণসংখ্যার সংখ্যা 2 দিয়ে ভাগ করার জন্য?

আপনার দ্বারা গড় উপর নির্ভরশীল সেরা

আপনি যদি চান যে আপনার সহকর্মীরা আপনাকে ঘৃণা করতে পারে, বা আপনার কোডটি পড়া শক্ত করে তুলবে, আমি অবশ্যই প্রথম বিকল্পটি সহ যাব।

আপনি যদি একটি সংখ্যা 2 দিয়ে ভাগ করতে চান তবে দ্বিতীয়টির সাথে যান।

দুটি সমতুল্য নয়, সংখ্যাটি নেতিবাচক বা বৃহত্তর এক্সপ্রেশনগুলির মধ্যে থাকলে তারা একই রকম আচরণ করে না - বিটশিফ্টের চেয়ে কম প্রাধান্য থাকে +বা -, বিভাগের অগ্রাধিকার থাকে।

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


58

/এটি স্পষ্ট মনে করে কেবল বিভাজন ( ) ব্যবহার করুন । সংকলক সেই অনুসারে অনুকূলিত হবে।


34
কম্পাইলার উচিত সেই অনুযায়ী নিখুত।
নোকটিস স্কাইটিওয়ার

12
সংকলক যদি সেই অনুযায়ী অনুকূলিত না হয় তবে আপনার আরও ভাল সংকলক ব্যবহার করা উচিত
ডেভিড স্টোন

3
@DavidStone: চালু কি প্রসেসর করতে কোন 1 ছাড়া অন্য ধ্রুবক দ্বারা একটি সম্ভবত-নেগেটিভ স্বাক্ষরিত পূর্ণসংখ্যা একটি কম্পাইলার অপ্টিমাইজ বিভাজন একটি স্থানান্তর দক্ষ হিসাবে হতে?
সুপারক্যাট

1
@ সুপের্যাট: এটি একটি ভাল বিষয়। আপনি অবশ্যই কোনও স্বাক্ষরযুক্ত পূর্ণসংখ্যায় মানটি সঞ্চয় করতে পারেন (যা আমি স্বাক্ষরিত / স্বাক্ষরিত / স্বাক্ষরিত মিলহীন সতর্কতাগুলির সাথে মিলিত হওয়ার তুলনায় তাদের তুলনায় আরও খারাপ খ্যাতি অর্জন করতে পারে বলে মনে করি), এবং বেশিরভাগ সংকলককেও কিছু অনুমান করার জন্য সত্য বলার উপায় রয়েছে । আমি যে মোড়ানো পছন্দ করেন একটি সামঞ্জস্য ম্যাক্রো এবং মত কিছু আছে ASSUME(x >= 0); x /= 2;উপর x >>= 1;, কিন্তু যে এখনও পর্যন্ত আনতে একটি গুরুত্বপূর্ণ পয়েন্ট।
ডেভিড স্টোন

39

আমি অন্যান্য উত্তরের সাথে একমত যে আপনার পক্ষে উচিত উচিত x / 2কারণ এর উদ্দেশ্যটি আরও স্পষ্ট, এবং সংকলকটি এটি আপনার জন্য অনুকূলিত করা উচিত।

তবে ওভারকে x / 2প্রাধান্য দেওয়ার আরেকটি কারণ হ'ল স্বাক্ষরিত এবং নেতিবাচক হলে এর x >> 1ব্যবহার >>বাস্তবায়ন-নির্ভর ।xint

6.5.7 বিভাগ থেকে, আইএসও সি 99 এর বুলেট 5:

ফল E1 >> E2হল E1ডান-স্থানান্তরিত E2বিট অবস্থান। যদি E1স্বাক্ষরযুক্ত স্বাক্ষরিত টাইপ থাকে বা E1স্বাক্ষরিত প্রকার এবং একটি ননজিগেটেভ মান থাকে তবে ফলাফলের মানটি E1/ 2 এর ভাগফলের অবিচ্ছেদ্য অংশ E2। যদি E1একটি স্বাক্ষরিত ধরণ এবং negativeণাত্মক মান থাকে তবে ফলাফল মান বাস্তবায়ন-সংজ্ঞায়িত হয়।


3
এটি লক্ষণীয় যে, অনেকগুলি বাস্তবায়ন x>>scalepowerনেতিবাচক সংখ্যার জন্য যে আচরণটি সংজ্ঞায়িত করে তা হ'ল স্ক্রিন রেন্ডারিংয়ের মতো উদ্দেশ্যে দুটি দ্বারা একটি শক্তির দ্বারা মূল্যকে বিভাজন করার সময় প্রয়োজনীয়ভাবে প্রয়োজন, যখন x/scalefactorনা কেউ নেতিবাচক মানগুলিতে সংশোধন প্রয়োগ করে তবে ব্যবহার ভুল হবে।
সুপারক্যাট

32

x / 2পরিষ্কার হয়, এবং x >> 1খুব দ্রুত হয় না (একটি মাইক্রো-বেঞ্চমার্ক অনুসারে, জাভা জেভিএমের জন্য প্রায় 30% দ্রুত)। অন্যরা যেমন বলেছে, নেতিবাচক সংখ্যার জন্য বৃত্তাকারটি কিছুটা আলাদা, তাই আপনি নেতিবাচক সংখ্যাগুলি প্রক্রিয়া করতে চাইলে আপনাকে এটি বিবেচনা করতে হবে। কিছু সংকলক স্বয়ংক্রিয়ভাবে রূপান্তর x / 2করতে পারে x >> 1যদি তারা জানে যে নম্বরটি নেতিবাচক হতে পারে না (এমনকি আমি ভেবেছি এটি আমি যাচাই করতে পারি না)।

এমনকি x / 2(ধীর) বিভাগের সিপিইউ নির্দেশনা ব্যবহার নাও করতে পারে, কারণ কিছু শর্টকাট সম্ভব , তবে এটি এখনও তুলনায় ধীর x >> 1

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


1
সংঘটিত সংঘটিত সংঘটিত ক্ষেত্রে রূপান্তর x/2করতে পারে না। যদি কেউ চায় এমন মান হয় যা গণনা করবে তবে এটি অবশ্যই একই মানটিকে গণনা করে এমন কোনও অভিব্যক্তির চেয়ে প্রায় দ্রুত হবে । x>>1xx>>1x/2
সুপারক্যাট

তুমি ঠিক. কোনও সংকলক কেবল তখনই রূপান্তর x/2করতে পারে x>>1যদি সে জানে যে মানটি নেতিবাচক নয়। আমি আমার উত্তর আপডেট করার চেষ্টা করব।
টমাস মোলার

সংকলকরা এখনও কোনও divনির্দেশ এড়াতে পারবেন না , রূপান্তর x/2করে (x + (x<0?1:0)) >> 1(যেখানে >> একটি গাণিতিক ডান-শিফট, যা সাইন বিটগুলিতে স্থানান্তরিত হয়)। এটির জন্য 4 টি নির্দেশনা রয়েছে: মানটি কপি করুন, একটি সংখ্যায় সাইন বিট পেতে, যোগ করুন, স্যার। goo.gl/4F8Ms4
পিটার

প্রশ্নটি সি এবং সি ++ হিসাবে ট্যাগ করা আছে।
জোশ সানফোর্ড

22

নাথ বলেছেন:

অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের মূল।

তাই আমি ব্যবহার করার পরামর্শ দিই x /= 2;

এইভাবে কোডটি বোঝা সহজ এবং আমিও মনে করি যে এই ফর্মটিতে এই অপারেশনটির অপ্টিমাইজেশন, প্রসেসরের জন্য কোনও বড় পার্থক্য বোঝায় না।


4
দুইটি শক্তির দ্বারা সংখ্যাকে কমিয়ে দেওয়ার পছন্দের পদ্ধতিটি আপনি কী বিবেচনা করবেন যদি কেউ যদি পূর্ণসংখ্যার (প্রাকৃতিক সংখ্যা এবং আসল সংখ্যার ক্ষেত্রে প্রযোজ্য) অক্ষুণ্ন রাখতে চায় তবে (এন + ডি) / ডি = (এন / ডি) + 1? গ্রাফিক্স স্কেলিংয়ের সময় অ্যাক্সিয়ম লঙ্ঘন ফলাফলের মধ্যে দৃশ্যমান "seams" সৃষ্টি করবে। যদি কেউ এমন কিছু চায় যা সমান এবং প্রায় শূন্য সম্পর্কে প্রতিসাম্যপূর্ণ হয় তবে দুর্দান্তভাবে (n+8)>>4কাজ করে। আপনি কি এমন কোনও পদ্ধতির প্রস্তাব করতে পারেন যা স্বাক্ষরিত ডান শিফটটি ব্যবহার না করেই পরিষ্কার বা দক্ষ হিসাবে কার্যকর?
সুপারক্যাট

19

আপনাকে সিদ্ধান্ত নিতে সহায়তা করতে সংকলক আউটপুটটি একবার দেখুন। আমি এই পরীক্ষাটি
জিসিসি (জিসিসি) 4.2.1 20070719 [ফ্রিবিএসডি] সহ x86-64 এ চালিয়েছি

গডবোল্টে অনলাইনে সংকলক আউটপুটগুলি দেখুন ।

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

সমাবেশ আউটপুট সহ সি কোড:

বিভাজনের জন্য, আপনার ইনপুট হবে

int div2signed(int a) {
  return a / 2;
}

এবং এটি সংকলন

    movl    %edi, %eax
    shrl    $31, %eax
    addl    %edi, %eax
    sarl    %eax
    ret

শিফট জন্য একইভাবে

int shr2signed(int a) {
  return a >> 1;
}

আউটপুট সহ:

    sarl    %edi
    movl    %edi, %eax
    ret

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

আপনার যদি কোনও মেঝে প্রয়োজন হয়, তবে আপনি "2 দিয়ে বিভাজক" হিসাবে যা চান তা বর্ণনা করার সম্ভাবনা নেই
মাইকেল ডোনহিউ

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

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

Sh2sided এর জন্য আপনার সংকলক আউটপুটটি ভুল। x86-তে জিসিসি গাণিতিক শিফট ( sar) সহ স্বাক্ষরিত পূর্ণসংখ্যার প্রয়োগ করতে নির্বাচন করে । goo.gl/KRgIkb । এই মেইলিং তালিকার পোস্টটি ( gcc.gnu.org/ML/gcc/2000-04/msg00152.html ) নিশ্চিত করে যে জিসিসি historতিহাসিকভাবে স্বাক্ষরিত ইনটগুলির জন্য পাটিগণিত শিফট ব্যবহার করে, সুতরাং এটি ফ্রিবিএসডি জিসিসি ৪.২.১ স্বাক্ষরবিহীন শিফ্ট ব্যবহার করার সম্ভাবনা খুব বেশি নয়। এটি ঠিক করার জন্য আমি আপনার পোস্টটি আপডেট করেছি এবং প্রথম অনুচ্ছেদে উভয়ই শ্র ব্যবহার করেছে, যখন এটি সত্যই তারা উভয়ই ব্যবহার করে। এসএইচআর হ'ল কীভাবে এটি /মামলার জন্য সাইন বিটটি বের করে । একটি গডবোল্ট লিঙ্কও অন্তর্ভুক্ত।
পিটার কর্ডস

15

কেবলমাত্র একটি যুক্ত নোট -

এক্স * = 0.5 প্রায়শই কিছু ভিএম-ভিত্তিক ভাষায় দ্রুততর হবে - উল্লেখযোগ্যভাবে ক্রিয়া স্ক্রিপ্ট, কারণ ভেরিয়েবল 0 দ্বারা বিভাজনের জন্য পরীক্ষা করতে হবে না।


2
@ এমনিটেক: এটি খুব খারাপ পরীক্ষা। পরীক্ষার সমস্ত কোড ধ্রুবক। কোডটি এমনকি জেআইটিড হওয়ার আগে এটি সমস্ত প্রতিবন্ধকতাগুলি সরিয়ে ফেলবে।

@ এম 28: আমি নিশ্চিত যে জেসফিউমের ইন্টার্নালগুলি (অর্থাত্ eval) প্রতিটি বার নতুন করে ঘটেছে। নির্বিশেষে, হ্যাঁ, এটি একটি খুব খারাপ পরীক্ষা, কারণ এটি একটি অত্যন্ত নির্বোধ অপ্টিমাইজেশন।
রাই-

13

x = x / 2; OR ব্যবহার করুন x /= 2;কারণ ভবিষ্যতে কোনও নতুন প্রোগ্রামার এতে কাজ করতে পারে। সুতরাং কোড লাইনে কী চলছে তা খুঁজে পাওয়া তার পক্ষে সহজ হবে। এই ধরনের অপ্টিমাইজেশন সম্পর্কে সবাই সচেতন নাও হতে পারে।


12

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

x >> 1 এক্স / 2 এর চেয়ে ভাল হবে। আমি আইডোন ডটকমকে একটি প্রোগ্রাম চালিয়ে পরীক্ষা করেছিলাম যেখানে 2 টি অপারেশন দ্বারা 10 ^ 10 এরও বেশি বিভাগ হয়েছিল। x / 2 প্রায় 5.5 সেকেন্ড নিয়েছে যখন x >> 1 একই প্রোগ্রামের জন্য প্রায় 2.6 সেকেন্ড নিয়েছে।


1
স্বাক্ষরবিহীন মানগুলির জন্য, একটি সংকলককে অনুকূলিত x/2করা উচিত x>>1। স্বাক্ষরিত মানগুলির জন্য, প্রায় সমস্ত বাস্তবায়ন x>>1একটি অর্থের সংজ্ঞা দেয় যা সমান হয় x/2তবে xইতিবাচক হলে দ্রুত গণনা করা যায় , এবং x/2কখন xনেতিবাচক হয় তার থেকে কার্যকরভাবে আলাদা ।
সুপারক্যাট

12

আমি বলব এখানে বেশ কয়েকটি বিষয় বিবেচনা করা উচিত।

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

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

  3. অন্তর্নিহিত হার্ডওয়ারের উপর নির্ভর করে অপারেশনের বিভিন্ন গতি থাকতে পারে। আমডালের আইন হ'ল সাধারণ কেসটিকে দ্রুত করা। সুতরাং আপনার কাছে এমন হার্ডওয়্যার থাকতে পারে যা অন্যদের চেয়ে দ্রুত বিভিন্ন ক্রিয়াকলাপ সম্পাদন করতে পারে। উদাহরণস্বরূপ, ০.৫ দিয়ে গুণন করা ২ দ্বারা ভাগ করার চেয়ে দ্রুত হতে পারে (মঞ্জুর হলে আপনি সংখ্যার বিভাগ প্রয়োগ করতে চান তবে আপনাকে গুণনের তল নিতে হবে)।

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


2
"বিটশিফ্টটি দ্রুত হওয়া উচিত"। সংকলকগণ বিটিশফিটগুলিতে বিভাগগুলি অনুকূল করে তুলবেন
ট্রেভর হিকি

আমি তাদের আশা করি, তবে আপনি যদি সংকলকের উত্সটিতে অ্যাক্সেস না পান তবে আপনি নিশ্চিত হতে পারবেন না :)
জেমস ওরাভেক

1
আমিও bitshift সুপারিশ করবে যদি এক বাস্তবায়ন সবচেয়ে সাধারণ ফ্যাশন এবং পথ এক হ্যান্ডলগুলি এটা কি দিয়ে ঋণাত্মক সংখ্যা ম্যাচ পরিচালনা করতে চায় >>করে এবং সাথে মিলছে না কি /আছে।
সুপারক্যাট

12

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


11

x = x / 2; ব্যবহারের জন্য উপযুক্ত কোড .. তবে একটি ক্রিয়াকলাপ কীভাবে আউটপুট আপনি উত্পাদন করতে চেয়েছিলেন তার নিজের প্রোগ্রামের উপর নির্ভর করে।


11

আপনার উদ্দেশ্যগুলি আরও সুস্পষ্ট করুন ... উদাহরণস্বরূপ, আপনি যদি বিভাজন করতে চান, এক্স / 2 ব্যবহার করুন এবং সংকলকটিকে এটিকে অপারেটর (বা অন্য কোনও কিছু) স্থানান্তর করতে অনুকূলিত করতে দিন।

আজকের প্রসেসরগুলি এই অপ্টিমাইজেশানগুলি আপনার প্রোগ্রামগুলির কার্যকারিতায় কোনও প্রভাব ফেলতে দেবে না।


10

এর উত্তর আপনি যে পরিবেশের অধীনে কাজ করছেন তার উপর নির্ভর করবে।

  • যদি আপনি 8-বিট মাইক্রোকন্ট্রোলার বা কোনও গুণমানের জন্য হার্ডওয়্যার সমর্থন ছাড়াই কিছুতে কাজ করে থাকেন তবে বিট স্থানান্তরিত হওয়া প্রত্যাশিত এবং সাধারণ, এবং সংকলকটি অবশ্যই অবশ্যই রূপান্তরিত x /= 2হবেx >>= 1 , বিভাগের প্রতীকের উপস্থিতি সেই পরিবেশে আরও ভ্রু বাড়িয়ে তুলবে একটি বিভাগ কার্যকর করার জন্য একটি শিফট ব্যবহার।
  • আপনি যদি কোনও পারফরম্যান্স-সমালোচনামূলক পরিবেশ বা কোডের বিভাগে কাজ করছেন বা আপনার কোডটি সংকলক অপ্টিমাইজেশন বন্ধ করে সংকলিত হতে পারে, x >>= 1তার যুক্তির ব্যাখ্যা দিয়ে একটি মন্তব্য সম্ভবত উদ্দেশ্যটির স্পষ্টতার জন্য সম্ভবত সেরা।
  • যদি আপনি উপরের শর্তগুলির একটির অধীনে না হন তবে কেবল কোডটি ব্যবহার করে আপনার কোডটি আরও পঠনযোগ্য করে তুলুন x /= 2। পরের প্রোগ্রামার যিনি আপনার কোডটি দেখেন সেটিকে সংরক্ষণ করা ভাল যা আপনার কোডটি আপনার শিফট অপারেশনটিতে 10 সেকেন্ডের দ্বিগুণ-গ্রহণের প্রয়োজন তা অকারণে প্রমাণ করার আগেই আপনি জানতেন যে শিফ্টটি আরও কার্যকর সানস সংকলক অপ্টিমাইজেশান ছিল।

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


8

মোড 2, পরীক্ষার জন্য = 1. সিঙ্ক এ সিনট্যাক্স dunno। তবে এটি সবচেয়ে দ্রুত হতে পারে।


7

উত্পন্নভাবে ডান শিফট বিভক্ত:

q = i >> n; is the same as: q = i / 2**n;

এটি কখনও কখনও স্বচ্ছতার ব্যয়ে প্রোগ্রামগুলি গতিতে ব্যবহৃত হয়। আমার মনে হয় না তোমার এটা করা উচিত। সংকলক স্বয়ংক্রিয়ভাবে গতি সম্পন্ন করতে যথেষ্ট স্মার্ট। এর অর্থ হল যে স্থানান্তরিত হওয়া আপনার স্পষ্টতা ব্যয় করে কিছুই লাভ করে না

প্রাকটিক্যাল সি ++ প্রোগ্রামিং থেকে এই পৃষ্ঠাটি একবার দেখুন


যদি কেউ এমন মানটি গণনা করতে চায় যে, উদাহরণস্বরূপ সর্বাধিকের নিকটে নয় এমন (x+128)>>8মানগুলির গণনা xকরতে পারে, তবে কীভাবে সংক্ষেপে শিফট ছাড়াই এটি করা যায়? নোট করুন যে (x+128)/256কাজ করবে না। আপনি যে কোনও চমৎকার অভিব্যক্তি জানেন যে জানেন?
সুপারক্যাট

7

স্পষ্টতই, আপনি যদি পরের লোকটি পড়ে এটির জন্য আপনার কোড লিখছেন তবে "x / 2" এর স্পষ্টতার জন্য যান।

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

আমি যখন উভয় উপায়েই সময়সীমা বেঁধেছিলাম তখন আমি আমার অবাক করে আবিষ্কার করি যে x / 2 এক্স >> 1 এর চেয়ে দ্রুত ছিল

এটি মাইক্রোসফ্ট VS2008 সি ++ ব্যবহার করে ডিফল্ট অপ্টিমাইজেশন চালু হয়েছিল।


4

পারফরম্যান্সের ক্ষেত্রে। সিপিইউয়ের শিফট অপারেশনগুলি বিভক্ত অপ-কোডগুলির চেয়ে উল্লেখযোগ্যভাবে দ্রুত। সুতরাং দুটি দ্বারা ভাগ করা বা 2 দ্বারা গুণিত করা ইত্যাদি শিফট ক্রিয়াকলাপ থেকে সমস্ত উপকার করে।

চেহারা এবং অনুভূতি হিসাবে। প্রকৌশলী হিসাবে কখন আমরা প্রসাধনীগুলির সাথে এতটা সংযুক্ত হয়ে পড়েছিলাম যে এমনকি সুন্দরী মহিলারাও ব্যবহার করেন না! :)


3

এক্স / ওয়াই হ'ল একটি সঠিক ... এবং ">>" শিফটিং অপারেটর .. যদি আমরা দুটি ভাগের একটি পূর্ণসংখ্যার চাই তবে আমরা (/) লভ্যাংশ অপারেটরটি ব্যবহার করতে পারি। শিফট অপারেটর বিট শিফট করতে ব্যবহৃত হয় ..

এক্স = এক্স / 2; এক্স / = 2; আমরা এটি ব্যবহার করতে পারি ..


0

যদিও x >> 1 এক্স / 2 এর চেয়ে দ্রুত, তবে নেতিবাচক মানগুলির সাথে লেনদেন করার সময় এর সঠিক ব্যবহার কিছুটা জটিল। এটি নিম্নলিখিত কিছু অনুরূপ প্রয়োজন:

// Extension Method
public static class Global {
    public static int ShiftDivBy2(this int x) {
        return (x < 0 ? x + 1 : x) >> 1;
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.