2016-04-29 4 views
15

कंपाइलर एक्सटेंशन पर भरोसा किए बिना, एक पूर्णांक के अंतहीनता को स्वैप करने के लिए constexpr फ़ंक्शन कैसे लिखें और क्या आप इसे कैसे करें इस पर एक उदाहरण दे सकते हैं?एक पूर्णांक के अंतहीनता को बदलने के लिए constexpr स्वैप फ़ंक्शन कैसे लिखें?

+6

"पूर्णांक की समाप्ति" क्या है? 15 की अंतहीनता क्या है? –

+0

@KerrekSB जो कुछ भी है। मैंने उस सवाल से नहीं पूछा। मेरा सवाल यह है कि बड़े-एंडियन को छोटे-एंडियन और इसके विपरीत कैसे स्वैप करना है। – user1095108

+3

@KerrekSB: C++ (और सामान्य रूप से अधिकांश प्रोग्रामिंग) के संदर्भ में, जब कोई पूर्णांक कहता है, तो वे आम तौर पर एक पूर्णांक वस्तु का जिक्र कर रहे हैं। यही है, स्मृति में एक क्षेत्र पूर्णांक डेटा को स्टोर करने के लिए प्रयोग किया जाता है, आमतौर पर मौलिक पूर्णांक प्रकारों में से एक (चार, छोटा, int, लंबा और लंबा लंबा, उनके हस्ताक्षरित रूपों के साथ)। क्या आप वास्तव में उस उपयोग में कभी नहीं आए हैं? –

उत्तर

31

हाँ, यह बहुत आसान है;

#include <climits> 
#include <cstdint> 
#include <type_traits> 

template<class T> 
constexpr typename std::enable_if<std::is_unsigned<T>::value, T>::type 
bswap(T i, T j = 0u, std::size_t n = 0u) { 
    return n == sizeof(T) ? j : 
    bswap<T>(i >> CHAR_BIT, (j << CHAR_BIT) | (i & (T)(unsigned char)(-1)), n + 1); 
} 

Example.

यहाँ मैं j संचायक के रूप में और n पाश काउंटर के रूप में (अनुक्रमण बाइट्स) का उपयोग कर रहा: यहाँ एक पुनरावर्ती (सी ++ 11-संगत) कार्यान्वयन (केवल अहस्ताक्षरित अभिन्न प्रकार) है ।

आप एक संकलक C++17 fold expressions समर्थन है, तो यह कुछ है कि वास्तव में में बाहर फैलता है क्या आप हाथ से लिखते हैं लिखने के लिए संभव है:

template<class T, std::size_t... N> 
constexpr T bswap_impl(T i, std::index_sequence<N...>) { 
    return ((((i >> (N * CHAR_BIT)) & (T)(unsigned char)(-1)) << 
      ((sizeof(T) - 1 - N) * CHAR_BIT)) | ...); 
}; //          ^~~~~ fold expression 
template<class T, class U = typename std::make_unsigned<T>::type> 
constexpr U bswap(T i) { 
    return bswap_impl<U>(i, std::make_index_sequence<sizeof(T)>{}); 
} 

इस फार्म के लाभ यह है कि क्योंकि यह का उपयोग नहीं करता है लूप या रिकर्सन, आप इष्टतम असेंबली आउटपुट प्राप्त करने के लिए बहुत अधिक गारंटी रखते हैं - x86-64 पर, क्लैंग भी work out to use the bswap instruction पर प्रबंधित होता है।

2

ईकटामूर से प्रेरित मैं निम्नलिखित समाधान का सुझाव देता हूं, जिसमें संभावित रूप से बेहतर प्रदर्शन होता है जब संकलक (ओ (लॉग (एन) बनाम ओ (एन)) द्वारा bswap का पता नहीं लगाया जाता है। यह देखते हुए कि एन आमतौर पर < = 8 यह शायद अप्रासंगिक है है, अभी भी: इस फार्म ecatmur के समाधान संकलक एक कठिन काम अनुकूलन है तुलना में अधिक जटिल है, लेकिन अभी भी बजना पता चल गया है कि हम bswap मतलब

template <typename T> 
typename std::enable_if<std::is_unsigned<T>::value,T>::type 
constexpr alternating_bitmask(const size_t step){ 
    T mask(0); 
    for (size_t i=0;i<digits<T>();i+=2*step){ 
    mask|=(~T(0)>>(digits<T>()-step))<<i; 
    } 
    return mask; 
} 

template <typename T> 
typename std::enable_if<std::is_unsigned<T>::value,T>::type 
constexpr bswap(T n){ 
    for (size_t i=digits<unsigned char>();i<digits<T>();i*=2){ 
    n = ((n&(~(alternating_bitmask<T>(i))))>>i)| 
     ((n&((alternating_bitmask<T>(i))))<<i); 
    } 
    return n; 
} 

के रूप में।

+1

इस समाधान में वास्तव में Θ (एन) की समय जटिलता है क्योंकि आंतरिक लूप (अनुकूलन की गणना नहीं) में Θ (एन/लॉग एन) (बाहरी पाश के प्रति पुनरावृत्ति) की एक अमूर्त जटिलता है। वास्तविक Θ (लॉग एन) प्राप्त करने के लिए, बिटमास्क को याद रखना होगा, उदा। एक सरणी में precomputed। –

+0

@ArneVogel यह सच है, मैंने अभी माना है कि बिटकमास्क समय स्थिरांक संकलित करेंगे क्योंकि उनके द्वारा उत्पन्न कार्य एक कॉन्स्टेक्सर है। – Lykos

संबंधित मुद्दे