C ++ में सर्कुलर शिफ्ट (रोटेट) संचालन के लिए सर्वोत्तम अभ्यास


93

बाएं और दाएं शिफ्ट ऑपरेटर (<< और >>) पहले से ही C ++ में उपलब्ध हैं। हालाँकि, मुझे यह पता नहीं चल पाया कि मैं कैसे सर्कुलर शिफ्ट या रोटेट ऑपरेशन कर सकता हूँ।

"रोटेट लेफ्ट" और "रोटेट राइट" जैसे ऑपरेशन कैसे किए जा सकते हैं?

यहां दो बार दाईं ओर घूमना

Initial --> 1000 0011 0100 0010

परिणाम में होना चाहिए:

Final   --> 1010 0000 1101 0000

एक उदाहरण सहायक होगा।

(संपादक का ध्यान दें: C को घुमाए जाने के कई सामान्य तरीके अपरिभाषित व्यवहार से ग्रस्त हैं यदि रोटेट काउंट शून्य है, या केवल एक रोटेट मशीन निर्देश से अधिक के लिए संकलित है। इस प्रश्न का उत्तर सर्वोत्तम प्रथाओं का दस्तावेज होना चाहिए।)



जवाबों:


104

X86 के लिए asm gcc / clang का क्या उत्पादन होता है, इस बारे में कुछ और विवरणों के साथ एक अन्य घुमाएँ प्रश्न पर इस उत्तर के पहले संस्करण को भी देखें ।

C और C ++ में घुमाव को व्यक्त करने का सबसे संकलक-अनुकूल तरीका जो किसी भी अपरिभाषित व्यवहार से बचा जाता है, जॉन रेगर का कार्यान्वयन प्रतीत होता है । मैंने इसे प्रकार की चौड़ाई (जैसे निश्चित-चौड़ाई प्रकार का उपयोग करके 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इसलिए, आप अन्य आकारों के लिए संस्करण बना सकते हैं।

बहुत सारे सुरक्षा जांचों के साथ C ++ 11 टेम्पलेट संस्करण भी देखें (जिसमें static_assertकि प्रकार चौड़ाई 2 की शक्ति है) , जो कि उदाहरण के लिए, कुछ 24-बिट डीएसपी या 36-बिट मेनफ्रेम पर मामला नहीं है।

मैं केवल नाम के साथ रैपर के लिए बैक-एंड के रूप में टेम्पलेट का उपयोग करने की सलाह दूंगा जिसमें स्पष्ट रूप से रोटेट चौड़ाई शामिल है। पूर्णांक-पदोन्नति नियमों का मतलब है कि rotl_template(u16 & 0x11UL, 7)एक 32 या 64-बिट घुमाव, 16 नहीं (चौड़ाई के आधार पर unsigned long) होगा। यहां तक ​​कि C ++ के पूर्णांक-प्रचार नियमों द्वारा uint16_t & uint16_tप्रचारित किया signed intजाता है, उन प्लेटफार्मों को छोड़कर, जहां intसे अधिक व्यापक नहीं है uint16_t


X86 पर , यह संस्करण संकलक के साथ एकलrol r32, cl (या rol r32, imm8) में इनलाइन करता है, क्योंकि यह संकलक है, क्योंकि संकलक जानता है कि x86 घुमाएँ और शिफ्ट निर्देश सी-सोर्स करता है उसी तरह से शिफ्ट-काउंट को मास्क करें।

86, के लिए पर इस यूबी-परहेज मुहावरा के लिए संकलक समर्थन uint32_t xऔर unsigned int nचर-गिनती बदलाव के लिए:

  • क्लैंग: क्लैंग 3.5 के बाद से वेरिएबल-काउंट रोटेट के लिए पहचाना जाता है, इससे पहले कई शिफ्ट + या इंसन्स।
  • gcc: gcc4.9 के बाद से वेरिएबल-काउंट रोटेट के लिए पहचाना जाता है , उससे पहले कई शिफ्ट + या इंसन्स। gcc5 और बाद में विकिपीडिया संस्करण में शाखा और मुखौटा को अनुकूलित करें, भी, चर गणना के लिए सिर्फ एक rorया rolनिर्देश का उपयोग करके ।
  • आईसीसी: ICC13 या इससे पहले के बाद से चर-गिनती घूमता है के लिए समर्थित । लगातार गिनती रोटेट का उपयोग shld edi,edi,7करती है जो धीमा है और rol edi,7कुछ सीपीयू (विशेष रूप से एएमडी, लेकिन कुछ इंटेल) की तुलना में अधिक बाइट्स लेता है , जब बीएमवी 2 एक एमओवी rorx eax,edi,25को बचाने के लिए उपलब्ध नहीं है ।
  • MSVC: x86-64 CL19: केवल निरंतर-गिनती रोटेट के लिए पहचाना जाता है। (विकिपीडिया मुहावरे को मान्यता दी गई है, लेकिन शाखा और इसे दूर नहीं किया गया है)। X86 पर (x86-64 सहित) से _rotl/ _rotrआंतरिक का उपयोग करें <intrin.h>

एआरएम के लिए जीसीसी एक का उपयोग करता है and r1, r1, #31चर गिनती घूमता है के लिए, लेकिन अभी भी एक एकल अनुदेश के साथ वास्तविक घुमाने करता है : ror r0, r0, r1। तो जीसीसी को यह एहसास नहीं होता है कि रोटेट-काउंट स्वाभाविक रूप से मॉड्यूलर हैं। जैसा कि एआरएम डॉक्स कहते हैं, "शिफ्ट की लंबाई के साथ आरओआर, n32 से अधिक शिफ्ट लंबाई के साथ आरओआर के समान है n-32" । मुझे लगता है कि जीएमसी यहां उलझन में है क्योंकि एआरएम पर बाएं / दाएं बदलाव गिनती को संतृप्त करते हैं, इसलिए 32 या अधिक की शिफ्ट से रजिस्टर साफ हो जाएगा। (X86 के विपरीत, जहां बदलाव मुखौटा को घुमाए जाने के समान है)। यह संभवत: यह तय करता है कि घुमाए जाने वाले मुहावरे को पहचानने से पहले इसे एक निर्देश की जरूरत है, क्योंकि गैर-परिपत्र बदलाव उस लक्ष्य पर कैसे काम करते हैं।

वर्तमान x86 कंपाइलर अभी भी 8 और 16-बिट रोटेट के लिए एक वैरिएबल काउंट को मास्क करने के लिए एक अतिरिक्त निर्देश का उपयोग करते हैं, शायद उसी कारण से वे ARM पर AND से नहीं बचते हैं। यह एक चूक अनुकूलन है, क्योंकि प्रदर्शन किसी भी x86-64 सीपीयू पर रोटेट काउंट पर निर्भर नहीं करता है। (परफॉर्मेंस कारणों से काउंट्स की मास्किंग को 286 के साथ पेश किया गया था, क्योंकि यह चलने-फिरने में बदलाव करता है, आधुनिक सीपीयू जैसे निरंतर-विलंबता के साथ नहीं।)

BTW, वैरिएबल-काउंट रोटेट के लिए रोटेट-राईट को प्राथमिकता देते हैं, कम्पेर करने से बचने के 32-nलिए ARM और MIPS जैसे आर्किटेक्चर पर लेफ्ट रोटेट को लागू करने के लिए करते हैं जो केवल रोटेट-राइट प्रदान करते हैं। (यह संकलन-समय-निरंतर गणना के साथ दूर हो जाता है।)

मज़ेदार तथ्य: एआरएम वास्तव में समर्पित पारी / घुमाएँ निर्देश नहीं है, इसके साथ सिर्फ MOV है स्रोत संकार्य ROR मोड में प्रति बैरल-शिफ्टर से गुजर रही : mov r0, r0, ror r1। तो एक बारी बारी से एक ईओआर निर्देश या कुछ के लिए एक रजिस्टर-सोर्स ऑपरेंड में बदल सकता है।


सुनिश्चित करें कि आप के लिए अहस्ताक्षरित प्रकार nऔर वापसी मूल्य का उपयोग करते हैं, अन्यथा यह एक घुमाव नहीं होगा । (x86 लक्ष्य के लिए जीसी अंकगणित सही बदलाव करता है, शून्य के बजाय साइन-बिट की प्रतियों में शिफ्टिंग, एक समस्या के लिए अग्रणी है जब आप ORदो मानों को एक साथ स्थानांतरित करते हैं। नकारात्मक हस्ताक्षरित पूर्णांकों के राइट-शिफ्ट कार्यान्वयन सी में परिभाषित व्यवहार है।)

यह भी सुनिश्चित करें कि शिफ्ट काउंट एक अहस्ताक्षरित प्रकार है , क्योंकि (-n)&31एक हस्ताक्षरित प्रकार के साथ एक का पूरक या संकेत / परिमाण हो सकता है, और मॉड्यूलर 2 ^ n के समान नहीं है जो आपको अहस्ताक्षरित या दो के पूरक के साथ मिलता है। (रेगर की ब्लॉग पोस्ट पर टिप्पणियां देखें)। unsigned intहर कंपाइलर पर अच्छी तरह से करता हूं, जिसकी हर चौड़ाई पर मैंने गौर किया है x। कुछ अन्य प्रकार वास्तव में कुछ संकलक के लिए मुहावरे-मान्यता को पराजित करते हैं, इसलिए केवल उसी प्रकार का उपयोग न करें जैसा कि x


कुछ संकलक घुमाने के लिए आंतरिक प्रदान करते हैं , जो कि इनलाइन-एएसएम की तुलना में कहीं बेहतर है यदि पोर्टेबल संस्करण आपके द्वारा लक्षित टारगेट पर अच्छा कोड उत्पन्न नहीं करता है। किसी भी संकलक के लिए क्रॉस-प्लेटफ़ॉर्म इंट्रिंसिक्स नहीं हैं जो मुझे पता है। ये x86 विकल्पों में से कुछ हैं:

  • इंटेल दस्तावेज़ जो <immintrin.h>प्रदान करता है _rotlऔर _rotl64आंतरिक , और सही बदलाव के लिए समान है। MSVC की आवश्यकता होती है <intrin.h>, जबकि gcc की आवश्यकता होती है <x86intrin.h>। एक #ifdefजीसीसी बनाम आईसीसी का ख्याल रखता है, लेकिन बजना, उन्हें कहीं भी प्रदान करने के लिए प्रतीत नहीं होता है के साथ MSVC संगतता मोड में छोड़कर-fms-extensions -fms-compatibility -fms-compatibility-version=17.00 । और asm यह उनके लिए बेकार है (अतिरिक्त मास्किंग और एक CMOV)।
  • MSVC: _rotr8और_rotr16
  • जीसीसी और आईसीसी (बजना नहीं): <x86intrin.h>यह भी प्रदान करता है __rolb/ __rorbके लिए 8 बिट बाएं घुमाएं / सही, __rolw/ __rorw(16-बिट), __rold/ __rord(32-बिट), __rolq/ __rorq(64-बिट, केवल 64-बिट लक्ष्यों के लिए परिभाषित)। संकीर्ण रोटेट के लिए, कार्यान्वयन का उपयोग करता है __builtin_ia32_rolhiया ...qi, लेकिन 32 / और 64-बिट रोटेट को शिफ्ट / या (यूबी के खिलाफ कोई सुरक्षा नहीं होने के साथ परिभाषित किया गया है, क्योंकि कोड ia32intrin.hकेवल x86 के लिए gcc पर काम करना है)। GNU C में ऐसा कोई क्रॉस-प्लेटफ़ॉर्म __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 संकलक में आंतरिक भी हैं, लेकिन आइए उन सभी को शामिल करने के लिए इस समुदाय-विकी उत्तर का विस्तार न करें। (हो सकता है कि आंतरिक जवाब के बारे में मौजूदा जवाब में )।


(इस उत्तर के पुराने संस्करण ने सुझाव दिया कि MSVC- विशिष्ट इनलाइन asm (जो कि केवल 32 बिट x86 कोड के लिए काम करता है), या C संस्करण के लिए http://www.devx.com/tips/Tip/14043 है । टिप्पणियां इसका उत्तर दे रही हैं। ।)

इनलाइन asm कई अनुकूलन को हराता है , विशेष रूप से MSVC- शैली क्योंकि यह इनपुट को संग्रहीत / पुनः लोड करने के लिए मजबूर करता है । एक सावधानी से लिखा गया GNU C इनलाइन-asm रोटेट, गणना को संकलित-समय-स्थिर शिफ्ट काउंट के लिए एक तत्काल ऑपरेंड होने की अनुमति देता है, लेकिन यह अभी भी पूरी तरह से अनुकूलन नहीं कर सकता है यदि स्थानांतरित किया जाने वाला मान भी एक संकलन-समय स्थिरांक है inlining के बाद। https://gcc.gnu.org/wiki/DontUseInlineAsm


1
जिज्ञासु, क्यों नहीं bits = CHAR_BIT * sizeof(n);और c &= bits - 1;और return ((n >> c) | (n << (bits - c)))है, जो है कि मैं क्या उपयोग करना चाहते हैं?
mirabilos

@mirabilos: आपके संस्करण में बिट्स के साथ यूबी = 32, गिनती = 32 है, शिफ्ट में bits - c= 32 - 0। (मुझे इससे पिंग नहीं मिला क्योंकि मैंने केवल विकी को संपादित किया था, इसे पहली जगह पर नहीं लिख रहा था।)
पीटर कॉर्ड्स

@PeterCordes 0 < count < bitsरोटेशन को लागू करने वाली लगभग सभी सीपीयू और प्रोग्रामिंग भाषाओं की एक निरंतर आवश्यकता है (कभी-कभी 0 ≤ count < bits, लेकिन बिट्स की सटीक मात्रा द्वारा स्थानांतरण वास्तव में या तो हमेशा परिभाषित नहीं होता है या मूल्य को साफ़ करने के बजाय एक एनओपी के लिए नीचे जाता है, और घूर्णन, अच्छी तरह से।)
मिराबिलोस

@mirabilos: सही है, लेकिन हमारा लक्ष्य एक फ़ंक्शन लिखना है जो कि शिफ़्ट काउंट को सीधे एक एसम निर्देश पर फीड करता है, लेकिन किसी भी संभावित शिफ्ट काउंट के लिए सी स्तर पर यूबी से बचा जाता है। चूँकि C में रोटेट ऑपरेटर या फ़ंक्शन नहीं है, इसलिए हम इस मुहावरे के किसी भी घटक भाग में UB से बचना चाहते हैं। हम बल्कि संकलक पर भरोसा नहीं करेंगे सी का इलाज करने के लिए उसी तरह के रूप में asm शिफ्ट के निर्देशों पर अपने संकलन के लिए निर्देश। (और बीटीडब्लू, एआरएम रजिस्टर की चौड़ाई बाइट से अधिक चर-गणना शिफ्ट के साथ रजिस्टर शून्य करता है। रजिस्टर के नीचे बाइट से गिनती ले। उत्तर में लिंक।)
पीटर कॉर्ड्स

1
मैं "बस पोर्टेबल-स्निपेट्स का उपयोग करने वाला" कहने जा रहा था, लेकिन फिर मैंने कोड की जांच की और ऐसा लगता है कि (ए) शून्य शिफ्ट काउंट के लिए यूबी को लागू करता है और (बी) केवल एमएसवीसी पर इंट्रिंसिक्स का उपयोग करता है । सामान्य तौर पर, कि सभी संकलक और प्लेटफॉर्म विशिष्ट हैक्स के साथ काम करने वाले "संदर्भ कोड" के रूप में होने पर एक अच्छा विचार लगता है ...
BeeOnRope

33

चूंकि यह C ++ है, एक इनलाइन फ़ंक्शन का उपयोग करें:

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

C ++ 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));
}

5
चेतावनी: यदि INTहस्ताक्षरित पूर्णांक है और हस्ताक्षर सेट है तो यह कोड टूट गया है! उदाहरण के लिए परीक्षण करें rol<std::int32_t>(1 << 31)जो 1 से अधिक पर फ्लिप होना चाहिए लेकिन वास्तव में बन जाता है -1(क्योंकि संकेत बरकरार है)।
कोई भी

9
@ कोई नहीं: मैंने पहले ही 5 साल पहले टिप्पणी की थी कि आपको हस्ताक्षर किए पूर्णांक प्रकारों का उपयोग नहीं करना चाहिए। रोटेशन पर हस्ताक्षर किए पूर्णांक प्रकार पर कोई मतलब नहीं है।
एमएसलटर्स

2
आप उपयोग कर सकते हैं std::numeric_limits<INT>::digitsके बजाय CHAR_BIT * sizeof। मैं भूल जाता हूं कि यदि अहस्ताक्षरित प्रकारों को अप्रयुक्त पैडिंग करने की अनुमति है (उदाहरण के लिए 32 बिट्स में संग्रहीत 24-बिट पूर्णांक), लेकिन यदि ऐसा है तो digitsबेहतर होगा। एक चर-गिनती पारी के लिए अधिक जांच वाले संस्करण के लिए gist.github.com/pabigot/7550454 भी देखें ।
पीटर कॉर्डेस

1
@PeterCordes: वे हैं। मुझे लगता है कि क्रे ने (फ्लोटिंग पॉइंट रजिस्टरों का उपयोग किया जहां पैडिंग के साथ जहां एक्सपोनेंट फील्ड होगा)।
एमएसलटर्स

1
@ नकली-नाम '> इसलिए C ++ 11 संस्करण विंडोज़ पर तब तक काम नहीं करेगा जब तक कि आप इसे किसी और चीज़ में नहीं बदलते ...' हाँ, इसे लिनक्स में बदल दें। :)
स्लाव

20

अधिकांश संकलक के पास इसके लिए आंतरिक हैं। उदाहरण के लिए Visual Studio _rotr8, _rotr16


वाह! आसान तरीका है तो स्वीकृत जवाब। btw, एक DWORD (32-बिट) के लिए _rotr और _rotl का उपयोग करें।
गाबे हेल्समर

15

निश्चित:

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

6
क्या यह 8एक गलत वर्तनी है CHAR_BIT(जिसकी आवश्यकता बिल्कुल 8 नहीं है)?
टोबे स्पाइट

2
चूँकि यह मेरा ही उत्तर है (मेरे लिए बाएं से दाएं को छोड़कर), मेरे उत्तर पर पीटर कॉर्डेस की टिप्पणी यहां भी लागू होती है: उपयोग std::numeric_limits<T>::digits
एमएसलटर्स

14

सी ++ 20 std::rotlऔरstd::rotr

यह पहुंच चुका है! http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html और इसे <bit>हैडर में जोड़ना चाहिए ।

cppreference कहता है कि उपयोग इस प्रकार होगा:

#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 घूर्णन [bitops.rot]

निम्नलिखित विवरणों में, N को निरूपित करें std::numeric_limits<T>::digits

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

बाधाएं: T एक अहस्ताक्षरित पूर्णांक प्रकार है (3.9.1 [basic.fundamental])।

बता दें कि r% s है।

रिटर्न: यदि r 0, x है; आर सकारात्मक है अगर, (x << r) | (x >> (N - r)); अगर आर नकारात्मक है, rotr(x, -r)

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

बाधाएं: T एक अहस्ताक्षरित पूर्णांक प्रकार है (3.9.1 [basic.fundamental])। बता दें कि r% s है।

रिटर्न: यदि r 0, x है; आर सकारात्मक है अगर, (x >> r) | (x << (N - r)); अगर आर नकारात्मक है, rotl(x, -r)

std::popcount1 बिट्स की संख्या को गिनने के लिए A भी जोड़ा गया: 32-बिट पूर्णांक में सेट बिट्स की संख्या की गणना कैसे करें?


आधुनिक c ++ में उतरने के लिए बिट रोटेशन को इतना लंबा समय कैसे लगा? यहां तक ​​कि एलएलवीएम क्लैंग में, कुछ साल पहले सिर्फ इंट्रेंसिक्स रहे हैं => reviews.llvm.org/D21457 मुझे लगा कि एआरएम ने 2010 से पहले रास्ता बदल दिया था, इसलिए उन्हें सी ++ 11 के बाद से होना चाहिए था।
सैंडथॉर्न

7

कैसे इस तरह कुछ abt, मानक बिटसेट का उपयोग कर ...

#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;
}

HTH,


बिटसेट की लंबाई से अधिक बदलाव के लिए इसे संशोधित करने की आवश्यकता है।
एच। ग्रीन

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
===================

और आपको अपना शिफ्ट किया हुआ रोलओवर मान मिलता है। याद रखें बिट वार ऑपरेशन तेज़ हैं और इसके लिए किसी लूप की भी आवश्यकता नहीं है।


1
ऊपर के सबरूटीन के समान ... b = b << m | बी >> (एनएम);
एसएम कामरान

कि XOR नहीं होना चाहिए, या नहीं? 1 ^ 0 = 1, 0 ^ 0 = 0, आदि। यदि यह विशेष नहीं है, तो इस प्रकार यह हमेशा 1. होगा
BK

5

यह मानते हुए कि आप Lबिट्स द्वारा सही शिफ्ट करना चाहते हैं , और इनपुट बिट्स के xसाथ एक नंबर है N:

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

3

सही उत्तर निम्नलिखित है:

#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

स्रोत कोड x बिट संख्या

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

नीचे Dídac Pérez के उत्तर का थोड़ा सुधरा हुआ संस्करण है , जिसमें दोनों दिशाओं को कार्यान्वित किया गया है, साथ ही इन कार्यों के उपयोग के डेमो के साथ अहस्ताक्षरित चार और अहस्ताक्षरित लंबे लंबे मानों का उपयोग किया गया है। कई नोट:

  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

एक समारोह अधिभार:

unsigned int rotate_right(unsigned int x)
{
 return (x>>1 | (x&1?0x80000000:0))
}

unsigned short rotate_right(unsigned short x) { /* etc. */ }

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

मैक्रो को तर्क के रूप में गंदे आश्चर्य से बचने के लिए आपको कोष्ठक में x लपेटना चाहिए।
जॉय

3
यदि मूल्य 16-बिट नहीं है, तो आप चुपचाप बकवास करते हैं
जेम्स हॉपकिन

यदि इसे एक मैक्रो के रूप में परिभाषित किया जाता है, तो एक को भी तर्क के रूप में साइड इफेक्ट के साथ एक अभिव्यक्ति से बचने के लिए सावधान रहने की आवश्यकता है।
फिल मिलर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.