সি ++ এ বিজ্ঞপ্তি শিফট (ঘোরানো) ক্রিয়াকলাপের জন্য সেরা অনুশীলন


96

বাম এবং ডান শিফট অপারেটর (<< এবং >>) ইতিমধ্যে সি ++ এ উপলব্ধ। তবে আমি কীভাবে বিজ্ঞপ্তি শিফট বা ঘোরানো অপারেশন সম্পাদন করতে পারি তা জানতে পারি না।

"ঘোরান বাম" এবং "রোটেট ডান" এর মতো ক্রিয়াকলাপ কীভাবে সম্পাদন করা যায়?

ডানদিকে এখানে আবার ঘোরানো

Initial --> 1000 0011 0100 0010

ফলাফল হওয়া উচিত:

Final   --> 1010 0000 1101 0000

একটি উদাহরণ সহায়ক হবে।

(সম্পাদকের দ্রষ্টব্য: সিতে আবর্তিত প্রকাশের প্রচলিত সাধারণ পদ্ধতিগুলি অনির্ধারিত আচরণে ভোগে যদি ঘোরান গণনাটি শূন্য হয়, বা কেবল একটি একক ঘোরানো মেশিনের নির্দেশের চেয়ে বেশি সংকলন করে।



4
এটি সি ++ ২০ এ এসে পৌঁছেছে! stackoverflow.com/a/57285854/895245
সিরো Santilli郝海东冠状病六四事件法轮功

উত্তর:


106

X86 এর জন্য কীভাবে asm gcc / clang উত্পাদন করে সে সম্পর্কে আরও কিছু বিশদ সহ আরও একটি ঘোরানো প্রশ্নের এই উত্তরটির পূর্ববর্তী সংস্করণটিও দেখুন ।

সি এবং সি ++ এ কোনও ঘূর্ণন প্রকাশের সবচেয়ে সংকলক-বান্ধব উপায় যা কোনও পূর্বনির্ধারিত আচরণ এড়ানো যায় বলে মনে হয় জন রেগারের বাস্তবায়ন । আমি এটিকে প্রস্থের (যেমন স্থির-প্রস্থের ধরণের ব্যবহার করে uint32_t) প্রস্থের সাথে ঘোরানোর জন্য অভিযোজিত করেছি ।

#include <stdint.h>   // for uint32_t
#include <limits.h>   // for CHAR_BIT
// #define NDEBUG
#include <assert.h>

static inline uint32_t rotl32 (uint32_t n, unsigned int c)
{
  const unsigned int mask = (CHAR_BIT*sizeof(n) - 1);  // assumes width is a power of 2.

  // assert ( (c<=mask) &&"rotate by type width or more");
  c &= mask;
  return (n<<c) | (n>>( (-c)&mask ));
}

static inline uint32_t rotr32 (uint32_t n, unsigned int c)
{
  const unsigned int mask = (CHAR_BIT*sizeof(n) - 1);

  // assert ( (c<=mask) &&"rotate by type width or more");
  c &= mask;
  return (n>>c) | (n<<( (-c)&mask ));
}

কোনও স্বাক্ষরবিহীন পূর্ণসংখ্যার জন্য কাজ করে, কেবল uint32_tতাই নয় , যাতে আপনি অন্যান্য আকারের জন্য সংস্করণ তৈরি করতে পারেন।

দেখুন একটি সি ++ 11 টেমপ্লেট সংস্করণ নিরাপত্তা চেক প্রচুর সঙ্গে (সহ একটি static_assertযে টাইপ প্রস্থ 2 একটি ক্ষমতা হয়) , যা কিছু 24-বিট DSPs বা 36-বিট কারুরই, উদাহরণস্বরূপ উপর ঘটনা না।

আমি কেবলমাত্র টেমপ্লেটটি এমন নামের সাথে মোড়কের জন্য ব্যাক-এন্ড হিসাবে ব্যবহার করার পরামর্শ দেব যা স্পষ্টভাবে ঘোরানো প্রস্থকে অন্তর্ভুক্ত করে। পূর্ণসংখ্যা-প্রচারের নিয়মের মানে rotl_template(u16 & 0x11UL, 7)হল একটি 16 বা নয় ( 32 এর প্রস্থের উপর নির্ভর করে unsigned long) 32 বা 64-বিট ঘোরানো হবে । এমনকি uint16_t & uint16_tউন্নীত করা হয় signed intসি ++ এর পূর্ণসংখ্যা প্রচার বিধি দ্বারা, প্লাটফর্ম যেখানে উপর ব্যতীত intচেয়ে ব্যাপকতর হয় uint16_t


এক্স 86 উপর , এই সংস্করণে একটি একক থেকে inlinesrol r32, cl (অথবা rol r32, imm8কম্পাইলার সহ) এটি grok, কারণ কম্পাইলার জানে যে এক্স 86 ঘোরান এবং শিফট নির্দেশাবলী মাস্ক একই ভাবে সি উৎস নেই Shift-গণনা।

X86-এ এই ইউবি-এড়ানো এডিয়োম, uint32_t xএবং unsigned int nভেরিয়েবল-কাউন্ট শিফটগুলির জন্য সংকলক সমর্থন

  • ঝাঁকুনি: চলক-গণনার জন্য স্বীকৃত ক্ল্যাং 3.5, একাধিক শিফট + বা তার আগে ইনসান থেকে আবর্তিত।
  • জিসিসি: ভেরিয়েবল-কাউন্টের জন্য স্বীকৃত জিসিসি ৪.৯ থেকে একাধিক শিফট + বা তার আগে ইনসন হয়। জিসিসি 5 এবং পরে উইকিপিডিয়া সংস্করণে শাখাটি এবং মুখোশটি অপ্টিমাইজ করে, ভেরিয়েবল গণনাগুলির জন্য কেবল একটি rorবা rolনির্দেশ ব্যবহার করে।
  • আইসিসি: আইসিসি 13 বা তার আগের থেকে পরিবর্তনশীল-গণনা ঘোরার জন্য সমর্থিত । কনস্ট্যান্ট-কাউন্ট ব্যবহার ঘোরান shld edi,edi,7যা ধীরে ধীরে এবং rol edi,7কিছু সিপিইউ (বিশেষত এএমডি, তবে কিছু ইনটেল) এর চেয়ে বেশি বাইট নেয় , যখন বিএমআই 2 এমওভিকে rorx eax,edi,25সংরক্ষণ করার জন্য উপলব্ধ না থাকে ।
  • এমএসভিসি: x86-64 সিলে 19: কেবল ধ্রুবক-গণনা ঘোরার জন্য স্বীকৃত। (উইকিপিডিয়া আইডিয়ামটি স্বীকৃত, তবে শাখা এবং এ্যান্ডটি অপ্টিমাইজ করা হয়নি)। X86 থেকে x _rotl/ ( _rotrঅন্তর্গত <intrin.h>x86-64) ব্যবহার করুন intr

এআরএম জন্য জিসিসি একটি ব্যবহার and r1, r1, #31পরিবর্তনশীল গোনা rotates জন্য, কিন্তু এখনও একটি একক নির্দেশ সঙ্গে প্রকৃত ঘোরান না : ror r0, r0, r1। সুতরাং জিসিসি বুঝতে পারে না যে ঘোরানো গণনাগুলি সহজাতভাবে মডিউলার। এআরএম ডক্স যেমন বলেছে, "শিফটের দৈর্ঘ্যের সাথে আরওআর n, 32-রও বেশি শিফটের দৈর্ঘ্যের সাথে আরওর হিসাবে সমান n-32" । আমি মনে করি জিসিসি এখানে বিভ্রান্ত হয়ে পড়েছে কারণ এআরএম-এ বাম / ডান স্থানান্তরগুলি গণনাটি পূরণ করে, তাই 32 বা তার বেশি একটি শিফট রেজিস্টার সাফ করবে। (X86 এর বিপরীতে যেখানে শিফটগুলি গণনাগুলি ঘোরার মতোই মাস্ক করে)। ঘোরানো আইডিয়ামটি স্বীকৃতি দেওয়ার আগে এটির একটি এবং নির্দেশের দরকার সম্ভবত এটি স্থির করে, কারণ লক্ষ্যবস্তুতে নন-সার্কুলার শিফ্টগুলি কীভাবে কাজ করে।

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

বিটিডাব্লু, পরিবর্তনশীল-গণনা ঘোরার জন্য ঘোরানো-ডান পছন্দ করুন, সংকলকটিকে 32-nএআরএম এবং এমআইপিএসের মতো আর্কিটেকচারগুলিতে বাম ঘোরানো বাস্তবায়ন করতে এড়াতে কেবলমাত্র একটি ঘোরানো-ডান সরবরাহ করে। (এটি সংকলন-সময়-ধ্রুবক গণনাগুলি ছাড়িয়ে যায়))

মজার বিষয়: এআরএম সত্যিই ডেডিকেটেড শিফট / ঘোরান নির্দেশাবলী নেই, এটা দিয়ে শুধু যে MOV এর উৎস প্রতীক ROR মোডে পিপা কর্মচারী মধ্য দিয়ে যাচ্ছে : mov r0, r0, ror r1। সুতরাং একটি ঘোরানো কোনও EOR নির্দেশ বা কোনও কিছুর জন্য একটি নিবন্ধ-উত্স অপারেন্ডে ভাঁজ করতে পারে।


নিশ্চিত করুন যে আপনি স্বাক্ষরবিহীন প্রকারের জন্য nএবং ফেরতের মানটি ব্যবহার করেছেন, অন্যথায় এটি কোনও ঘোরানো হবে না । (x86 টার্গেটের জন্য জিসিসি পাটিগণিতের ডান শিফটগুলি করে, শূন্যের পরিবর্তে সাইন-বিটের অনুলিপিগুলিতে স্থানান্তরিত করে, যখন আপনি ORদু'টি স্থানান্তরিত মানগুলি এক সাথে করে তখন একটি সমস্যার সৃষ্টি করে negative

এছাড়াও, শিফট গণনাটি একটি স্বাক্ষরবিহীন প্রকারের তা নিশ্চিত করুন , কারণ (-n)&31একটি স্বাক্ষরিত প্রকারের সাথে কারওর পরিপূরক বা চিহ্ন / মাত্রা হতে পারে, এবং সাইনড বা দু'জনের পরিপূরক সহ আপনি যে মডুলার 2 get n পেয়েছেন তার মতো নয়। (রেগারের ব্লগ পোস্টে মন্তব্যগুলি দেখুন)। unsigned intআমি যে প্রতিটি সংকলক দেখেছি তার প্রতি প্রস্থের জন্য ভাল করে x। কিছু অন্যান্য প্রকার আসলে কিছু সংকলকগুলির জন্য আইডিয়াম-স্বীকৃতিটিকে পরাস্ত করে, তাই কেবল একই ধরণের ব্যবহার করবেন না x


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

  • ইন্টেল ডকুমেন্টস যা <immintrin.h>সরবরাহ করে _rotlএবং _rotl64আন্তঃব্যবস্থা করে এবং ডান শিফ্টের জন্য একই। এমএসভিসি প্রয়োজন <intrin.h>, যখন জিসিসির প্রয়োজন <x86intrin.h>। একটি #ifdefজিসিসি বনাম আইসিসি যত্ন নেয়, কিন্তু ঝনঝন, যেকোনো স্থানে সেগুলি প্রদান বলে মনে হচ্ছে না সঙ্গে MSVC উপযুক্ততা মোড ছাড়া-fms-extensions -fms-compatibility -fms-compatibility-version=17.00 । এবং তাদের জন্য যে asmটি বের হয় তা সফল হয় (অতিরিক্ত মাস্কিং এবং একটি সিএমওভি)।
  • এমএসভিসি: _rotr8এবং_rotr16
  • জিসিসি এবং আইসিসি (ঝনঝন না): <x86intrin.h>এছাড়াও উপলব্ধ __rolb/ __rorbজন্য 8 বিট বামদিকে ঘোরান / ডান, __rolw/ __rorw(16-বিট), __rold/ __rord(32-বিট), __rolq/ __rorq(64-বিট, শুধুমাত্র 64-বিট লক্ষ্যমাত্রা জন্য সংজ্ঞায়িত)। সংকীর্ণ ঘোরার জন্য, বাস্তবায়নটি ব্যবহার করে __builtin_ia32_rolhiবা ...qi, তবে 32 এবং 64-বিট ঘোরানো শিফট / বা (ইউবির বিরুদ্ধে কোনও সুরক্ষা ছাড়াই) ব্যবহার করে সংজ্ঞায়িত করা হয়েছে, কারণ কেবলমাত্র কোডটি ia32intrin.hx86 এর জন্য জিসিসি-তে কাজ করতে হবে)। জিএনইউ সি এর কোনও ক্রস-প্ল্যাটফর্মের __builtin_rotateকাজটি করে না বলে মনে হয় __builtin_popcount(এটি লক্ষ্য প্ল্যাটফর্মের সর্বোত্তম যা কিছুতে প্রসারিত হয়, এমনকি এটি একক নির্দেশনা না হলেও)। বেশিরভাগ সময় আপনি আইডিয়ম-স্বীকৃতি থেকে ভাল কোড পান।

// For real use, probably use a rotate intrinsic for MSVC, or this idiom for other compilers.  This pattern of #ifdefs may be helpful
#if defined(__x86_64__) || defined(__i386__)

#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>  // Not just <immintrin.h> for compilers other than icc
#endif

uint32_t rotl32_x86_intrinsic(rotwidth_t x, unsigned n) {
  //return __builtin_ia32_rorhi(x, 7);  // 16-bit rotate, GNU C
  return _rotl(x, n);  // gcc, icc, msvc.  Intel-defined.
  //return __rold(x, n);  // gcc, icc.
  // can't find anything for clang
}
#endif

সম্ভবত কিছু নন- x86 সংকলকের অন্তর্ভুক্ত রয়েছে তবে সেগুলি অন্তর্ভুক্ত করার জন্য এই সম্প্রদায়-উইকির উত্তরটি প্রসারিত করা যাক। (সম্ভবত অভ্যন্তরীণ সম্পর্কে বিদ্যমান উত্তরে এটি করুন )।


(এই উত্তরের পুরানো সংস্করণটি এমএসভিসি-নির্দিষ্ট ইনলাইন asm (যা কেবল 32 বিবিট x86 কোডের জন্য কাজ করে) বা সি সংস্করণের জন্য http://www.devx.com/tips/Tip/14043 প্রস্তাব দিয়েছে The মন্তব্যগুলি তার জবাব দিচ্ছে ।)

ইনলাইন asm অনেকগুলি অপ্টিমাইজেশানকে হারায় , বিশেষত এমএসভিসি-স্টাইল কারণ এটি ইনপুটগুলিকে স্টোর / পুনরায় লোড করতে বাধ্য করে । একটি সাবধানে-লিখিত GNU সি ইনলাইন-এসএম আবর্তিত গণনাটিকে সংকলন-সময়-ধ্রুবক শিফট গণনাগুলির জন্য তাত্ক্ষণিকভাবে কাজ করার অনুমতি দেবে, তবে মানটি স্থানান্তরিত করতে যদি এটি একটি সংকলন-সময় ধ্রুবক হয় তবে এটি সম্পূর্ণরূপে অপ্টিমাইজ করতে পারে না ইনলাইনিং পরে। https://gcc.gnu.org/wiki/DontUseInlineAsm


4
অদ্ভুত, কেন না bits = CHAR_BIT * sizeof(n);এবং c &= bits - 1;এবং return ((n >> c) | (n << (bits - c))), যা আমি যা ব্যবহার করতে চাই?
মিরাবিলোস

@ মিরাবিলোস: আপনার সংস্করণে বিট = 32, গণনা = 32, bits - c= সহ শিফটে ইউবি রয়েছে 32 - 0। (আমি এ থেকে পিং পাইনি কারণ আমি কেবল উইকি সম্পাদনা করেছি, এটি প্রথম স্থানে লিখছি না))
পিটার কর্ডস

@ পিটারকর্ডস 0 < count < bitsপ্রায় সমস্ত সিপিইউ এবং প্রোগ্রামিং ভাষার ঘূর্ণন বাস্তবায়নের নিয়মিত প্রয়োজনীয়তা (কখনও কখনও 0 ≤ count < bits, তবে বিটগুলির সঠিক পরিমাণে স্থানান্তর কার্যত সর্বদা হয় হয় না মান নির্ধারণের পরিবর্তে, এবং ঘূর্ণনকারী, ভালভাবে সংজ্ঞায়িত হয় না বা গোল হয়ে যায়) to
মীরাবিলোস

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

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

33

এটি সি ++ হওয়ায় একটি ইনলাইন ফাংশন ব্যবহার করুন:

template <typename INT> 
INT rol(INT val) {
    return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
}

সি ++ 11 বৈকল্পিক:

template <typename INT> 
constexpr INT rol(INT val) {
    static_assert(std::is_unsigned<INT>::value,
                  "Rotate Left only makes sense for unsigned types");
    return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
}

4
সতর্কতা: INTএকটি স্বাক্ষরিত পূর্ণসংখ্যা হলে এবং এই চিহ্নটি সেট করা থাকলে এই কোডটি ভেঙে গেছে ! উদাহরণস্বরূপ পরীক্ষা করুন rol<std::int32_t>(1 << 31)যা 1-এ ফ্লপ হওয়া উচিত তবে আসলে হয়ে যায় -1(কারণ সাইনটি ধরে রাখা হয়েছে)।
এসই

9
@ নোবডি: আমি ইতিমধ্যে 5 বছর আগে মন্তব্য করেছিলাম যে আপনি স্বাক্ষরিত পূর্ণসংখ্যার প্রকারটি ব্যবহার করবেন না। ঘোরানো কোনওভাবে স্বাক্ষরিত পূর্ণসংখ্যার প্রকারের জন্য অর্থবোধ করে না।
MSalters

4
আপনি std::numeric_limits<INT>::digitsপরিবর্তে ব্যবহার করতে পারেন CHAR_BIT * sizeof। আমি ভুলে গেছি যদি স্বাক্ষরযুক্ত প্রকারগুলিকে অব্যবহৃত প্যাডিংয়ের অনুমতি দেওয়া হয় (যেমন 24 বিট পূর্ণসংখ্যা 32 বিটের মধ্যে সঞ্চিত থাকে) তবে তা যদি digitsআরও ভাল হয় তবে। ভেরিয়েবল-কাউন্ট শিফটটির জন্য আরও চেক সহ একটি সংস্করণে gist.github.com/pabigot/7550454 দেখুন ।
পিটার কর্ডস

4
@ পিটারকর্ডস: তারা হ'ল আমি মনে করি ক্রে এর কাজ করেছে (ব্যবহৃত ভাসমান পয়েন্টগুলি প্যাডিং সহ রেজিস্টারগুলি যেখানে ক্ষতিকারক ক্ষেত্র হবে)।
MSalters

4
@ নকল-নাম '> সুতরাং উইন্ডোজে সি ++ 11 সংস্করণ কাজ করবে না যতক্ষণ না আপনি এটিকে অন্য কিছুতে পরিবর্তন করেন ...' হ্যাঁ, এটি লিনাক্সে পরিবর্তন করুন। :)
স্লাভা

21

বেশিরভাগ সংকলক এর জন্য অন্তর্নিহিত রয়েছে। উদাহরণস্বরূপ ভিজুয়াল স্টুডিও _ _rr8, _rotr16


কি দারুন! উপায় সহজ তারপর গৃহীত উত্তর। বিটিডব্লিউ, একটি ডিডাব্লর্ডের জন্য (32-বিট) _rotr এবং _rotl ব্যবহার করুন।
গাবে হালসমার

16

সি ++ 20 std::rotlএবংstd::rotr

এটা এসে গেছে! http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html এবং এটি <bit>হেডারে যুক্ত করা উচিত ।

cppreferences বলে যে ব্যবহারটি এর মতো হবে:

#include <bit>
#include <bitset>
#include <cstdint>
#include <iostream>

int main()
{
    std::uint8_t i = 0b00011101;
    std::cout << "i          = " << std::bitset<8>(i) << '\n';
    std::cout << "rotl(i,0)  = " << std::bitset<8>(std::rotl(i,0)) << '\n';
    std::cout << "rotl(i,1)  = " << std::bitset<8>(std::rotl(i,1)) << '\n';
    std::cout << "rotl(i,4)  = " << std::bitset<8>(std::rotl(i,4)) << '\n';
    std::cout << "rotl(i,9)  = " << std::bitset<8>(std::rotl(i,9)) << '\n';
    std::cout << "rotl(i,-1) = " << std::bitset<8>(std::rotl(i,-1)) << '\n';
}

আউটপুট প্রদান:

i          = 00011101
rotl(i,0)  = 00011101
rotl(i,1)  = 00111010
rotl(i,4)  = 11010001
rotl(i,9)  = 00111010
rotl(i,-1) = 10001110

সমর্থনটি জিসিসি, জিসিসি 9.1.0 এ পৌঁছানোর g++-9 -std=c++2aপরেও এটি ব্যবহার না করে চেষ্টা করব।

প্রস্তাবে বলা হয়েছে:

শিরোনাম:

namespace std {
  // 25.5.5, rotating   
  template<class T>
    [[nodiscard]] constexpr T rotl(T x, int s) noexcept;
  template<class T>
    [[nodiscard]] constexpr T rotr(T x, int s) noexcept;

এবং:

25.5.5 ঘুরছে [বিটপস.রোট]

নিম্নলিখিত বিবরণগুলিতে এন বোঝাতে দিন std::numeric_limits<T>::digits

template<class T>
  [[nodiscard]] constexpr T rotl(T x, int s) noexcept;

সীমাবদ্ধতা: টি একটি স্বাক্ষরবিহীন পূর্ণসংখ্যার প্রকার (3.9.1 [বেসিক.ফান্ডামেন্টাল])।

আসুন s% N হতে দিন

আয়: r যদি 0 হয়, x; যদি r ইতিবাচক হয় (x << r) | (x >> (N - r)); যদি আর নেতিবাচক হয় rotr(x, -r),।

template<class T>
  [[nodiscard]] constexpr T rotr(T x, int s) noexcept;

সীমাবদ্ধতা: টি একটি স্বাক্ষরবিহীন পূর্ণসংখ্যার প্রকার (3.9.1 [বেসিক.ফান্ডামেন্টাল])। আসুন s% N হতে দিন

আয়: r যদি 0 হয়, x; যদি r ইতিবাচক হয় (x >> r) | (x << (N - r)); যদি আর নেতিবাচক হয় rotl(x, -r),।

std::popcount1 টি বিটের সংখ্যা গণনা করতে A কে যুক্ত করা হয়েছিল: 32-বিট পূর্ণসংখ্যায় সেট বিটের সংখ্যা কীভাবে গণনা করতে হবে?


কীভাবে বিট রোটেশনগুলি আধুনিক সি ++ এ অবতরণ করতে এত দীর্ঘ সময় নিয়েছে? এমনকি এলএলভিএম ঝনঝনিতে, কয়েক বছর আগে কেবল অন্তঃসত্ত্বা রয়েছে => পর্যালোচনা. llvm.org/D21457 আমার ধারণা ছিল যে ২০১০ সালের আগে এআরএমের ঘোরানো পথ ছিল, সুতরাং সি ++ ১১ এর পরে তাদের সেখানে থাকা উচিত ছিল।

15

অবশ্যই:

template<class T>
T ror(T x, unsigned int moves)
{
  return (x >> moves) | (x << sizeof(T)*8 - moves);
}

6
এটি কি 8কোনও ভুল বানান CHAR_BIT(যা ঠিক 8 হওয়ার দরকার নেই)?
টবির স্পিড

4
যেহেতু এটি আমার মতো একই উত্তর (বাম দিকে ডানদিকে অদলবদল করা), আমার উত্তর সম্পর্কে পিটার কর্ডেসের মন্তব্যটি এখানেও প্রযোজ্য: ব্যবহার করুন std::numeric_limits<T>::digits
এমসাল্টাররা

7

স্ট্যান্ডার্ড বিটসেট ব্যবহার করে কীভাবে এ জাতীয় কিছু করা যায় ...

#include <bitset> 
#include <iostream> 

template <std::size_t N> 
inline void 
rotate(std::bitset<N>& b, unsigned m) 
{ 
   b = b << m | b >> (N-m); 
} 

int main() 
{ 
   std::bitset<8> b(15); 
   std::cout << b << '\n'; 
   rotate(b, 2); 
   std::cout << b << '\n'; 

   return 0;
}

এইচটিএইচ,


বিটসেটের দৈর্ঘ্যের চেয়ে বেশি শিফটের জন্য অ্যাকাউন্টে এটি সংশোধন করা দরকার।
এইচ। সবুজ

m %= N;শিফ্টের জন্য অ্যাকাউন্টে যুক্ত করা হয়েছে >= N
মিলানিয়া


6

বিশদ বিবরণে আপনি নিম্নলিখিত যুক্তি প্রয়োগ করতে পারেন।

বিট প্যাটার্নটি যদি পূর্ণসংখ্যায় 33602 হয়

1000 0011 0100 0010

এবং তারপরে আপনাকে 2 টি ডান শিফ দিয়ে রোল করতে হবে: প্রথমে বিট প্যাটার্নের একটি অনুলিপি তৈরি করুন এবং তারপরে এটি বাম শিফট করুন: দৈর্ঘ্য - রাইট শিফট অর্থাৎ দৈর্ঘ্য 16 ডান শিফটের মান 2 16 - 2 = 14

14 বারের স্থান পরিবর্তন করার পরে আপনি পান।

1000 0000 0000 0000

এখন ডান স্থানান্তর করুন 33602, প্রয়োজন হিসাবে 2 বার। তুমি পাও

0010 0000 1101 0000

এখন 14 বার বাম স্থানান্তরিত মান এবং 2 বার ডান স্থানান্তরিত মানের মধ্যে একটি OR নিন।

1000 0000 0000 0000
0010 0000 1101 0000
=====================
1010 0000 1101 0000
=====================

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


4
উপরের সাবরুটাইনগুলির অনুরূপ ... b = b << মি | b >> (এনএম);
এসএম কামরান

এটি কি XOR হওয়া উচিত নয়, না? 1 ^ 0 = 1, 0 ^ 0 = 0, ইত্যাদি যদি বা এটা একচেটিয়া নয়, এইভাবে এটা সবসময় 1. হবেন
বি কে

5

ধরে নিচ্ছি আপনি Lবিট দিয়ে ডানদিক বদল করতে চান , এবং ইনপুটটি বিট xসহ একটি নম্বর N:

unsigned ror(unsigned x, int L, int N) 
{
    unsigned lsbs = x & ((1 << L) - 1);
    return (x >> L) | (lsbs << (N-L));
}

4

সঠিক উত্তরটি নিম্নলিখিত:

#define BitsCount( val ) ( sizeof( val ) * CHAR_BIT )
#define Shift( val, steps ) ( steps % BitsCount( val ) )
#define ROL( val, steps ) ( ( val << Shift( val, steps ) ) | ( val >> ( BitsCount( val ) - Shift( val, steps ) ) ) )
#define ROR( val, steps ) ( ( val >> Shift( val, steps ) ) | ( val << ( BitsCount( val ) - Shift( val, steps ) ) ) )

valস্বাক্ষরিত হলে সম্ভবত দুর্ব্যবহার করবে ।
সাম হোচেভার

0

উত্স কোড এক্স বিট নম্বর

int x =8;
data =15; //input
unsigned char tmp;
for(int i =0;i<x;i++)
{
printf("Data & 1    %d\n",data&1);
printf("Data Shifted value %d\n",data>>1^(data&1)<<(x-1));
tmp = data>>1|(data&1)<<(x-1);
data = tmp;  
}

0

আরেকটি পরামর্শ

template<class T>
inline T rotl(T x, unsigned char moves){
    unsigned char temp;
    __asm{
        mov temp, CL
        mov CL, moves
        rol x, CL
        mov CL, temp
    };
    return x;
}

0

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

  1. ফাংশন সংকলক অপ্টিমাইজেশনের জন্য অন্তর্ভুক্ত করা হয়
  2. আমি cout << +valueস্বাক্ষরিত স্বাক্ষরিত চরকে সংখ্যাগতভাবে আউটপুট দেওয়ার জন্য একটি কৌশল ব্যবহার করেছি যেটি আমি এখানে পেয়েছি: https://stackoverflow.com/a/28414758/1599699
  3. আমি <put the type here>স্পষ্টতা এবং সুরক্ষার জন্য সুস্পষ্ট বাক্য গঠন ব্যবহার করার পরামর্শ দিচ্ছি ।
  4. আমি অতিরিক্ত তথ্য বিভাগে এখানে কী পেয়েছি তার কারণে আমি শিফটনাম প্যারামিটারের জন্য স্বাক্ষরবিহীন চরটি ব্যবহার করেছি :

অ্যাডিটিভ-এক্সপ্রেশনটি নেতিবাচক হলে বা অ্যাডেটিভ-এক্সপ্রেশনটি (প্রচারিত) শিফ্ট-এক্সপ্রেশন- এর বিটের সংখ্যার চেয়ে বেশি বা সমান হলে শিফট অপারেশনের ফলাফলটি সংজ্ঞায়িত ।

আমি যে কোডটি ব্যবহার করছি তা এখানে:

#include <iostream>

using namespace std;

template <typename T>
inline T rotateAndCarryLeft(T rotateMe, unsigned char shiftNum)
{
    static const unsigned char TBitCount = sizeof(T) * 8U;

    return (rotateMe << shiftNum) | (rotateMe >> (TBitCount - shiftNum));
}

template <typename T>
inline T rotateAndCarryRight(T rotateMe, unsigned char shiftNum)
{
    static const unsigned char TBitCount = sizeof(T) * 8U;

    return (rotateMe >> shiftNum) | (rotateMe << (TBitCount - shiftNum));
}

void main()
{
    //00010100 == (unsigned char)20U
    //00000101 == (unsigned char)5U == rotateAndCarryLeft(20U, 6U)
    //01010000 == (unsigned char)80U == rotateAndCarryRight(20U, 6U)

    cout << "unsigned char " << 20U << " rotated left by 6 bits == " << +rotateAndCarryLeft<unsigned char>(20U, 6U) << "\n";
    cout << "unsigned char " << 20U << " rotated right by 6 bits == " << +rotateAndCarryRight<unsigned char>(20U, 6U) << "\n";

    cout << "\n";


    for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned char) * 8U; ++shiftNum)
    {
        cout << "unsigned char " << 21U << " rotated left by " << +shiftNum << " bit(s) == " << +rotateAndCarryLeft<unsigned char>(21U, shiftNum) << "\n";
    }

    cout << "\n";

    for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned char) * 8U; ++shiftNum)
    {
        cout << "unsigned char " << 21U << " rotated right by " << +shiftNum << " bit(s) == " << +rotateAndCarryRight<unsigned char>(21U, shiftNum) << "\n";
    }


    cout << "\n";

    for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned long long) * 8U; ++shiftNum)
    {
        cout << "unsigned long long " << 3457347ULL << " rotated left by " << +shiftNum << " bit(s) == " << rotateAndCarryLeft<unsigned long long>(3457347ULL, shiftNum) << "\n";
    }

    cout << "\n";

    for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned long long) * 8U; ++shiftNum)
    {
        cout << "unsigned long long " << 3457347ULL << " rotated right by " << +shiftNum << " bit(s) == " << rotateAndCarryRight<unsigned long long>(3457347ULL, shiftNum) << "\n";
    }

    cout << "\n\n";
    system("pause");
}

0
--- Substituting RLC in 8051 C for speed --- Rotate left carry
Here is an example using RLC to update a serial 8 bit DAC msb first:
                               (r=DACVAL, P1.4= SDO, P1.5= SCLK)
MOV     A, r
?1:
MOV     B, #8
RLC     A
MOV     P1.4, C
CLR     P1.5
SETB    P1.5
DJNZ    B, ?1

Here is the code in 8051 C at its fastest:
sbit ACC_7  = ACC ^ 7 ; //define this at the top to access bit 7 of ACC
ACC     =   r;
B       =   8;  
do  {
P1_4    =   ACC_7;  // this assembles into mov c, acc.7  mov P1.4, c 
ACC     <<= 1;
P1_5    =   0;
P1_5    =   1;
B       --  ; 
    } while ( B!=0 );
The keil compiler will use DJNZ when a loop is written this way.
I am cheating here by using registers ACC and B in c code.
If you cannot cheat then substitute with:
P1_4    =   ( r & 128 ) ? 1 : 0 ;
r     <<=   1;
This only takes a few extra instructions.
Also, changing B for a local var char n is the same.
Keil does rotate ACC left by ADD A, ACC which is the same as multiply 2.
It only takes one extra opcode i think.
Keeping code entirely in C keeps things simpler sometimes.


-1
#define ROTATE_RIGHT(x) ( (x>>1) | (x&1?0x8000:0) )

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

4
মানটি যদি 16-বিট না হয় তবে আপনি নিঃশব্দে আজেবাজে কথা বলুন
জেমস হপকিন

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