2013-07-10 11 views
8

मैं हस्ताक्षरित संतृप्त 64 बिट अतिरिक्त के लिए कुछ सी कोड ढूंढ रहा हूं जो gcc अनुकूलक के साथ कुशल X86-64 कोड को संकलित करता है। पोर्टेबल कोड आदर्श होगा, हालांकि यदि आवश्यक हो तो एक एएसएम समाधान का उपयोग किया जा सकता है।64-बिट इनट्स के संतृप्त जोड़ पर हस्ताक्षर किए गए?

static const int64 kint64max = 0x7fffffffffffffffll; 
static const int64 kint64min = 0x8000000000000000ll; 

int64 signed_saturated_add(int64 x, int64 y) { 
    bool x_is_negative = (x & kint64min) != 0; 
    bool y_is_negative = (y & kint64min) != 0; 
    int64 sum = x+y; 
    bool sum_is_negative = (sum & kint64min) != 0; 
    if (x_is_negative != y_is_negative) return sum; // can't overflow 
    if (x_is_negative && !sum_is_negative) return kint64min; 
    if (!x_is_negative && sum_is_negative) return kint64max; 
    return sum; 
} 

लिखित कार्य कई शाखाओं के साथ काफी लंबा असेंबली आउटपुट उत्पन्न करता है। अनुकूलन पर कोई सुझाव? ऐसा लगता है कि इसे कुछ सीएमओवी निर्देशों के साथ केवल एक एडीडी के साथ कार्यान्वित किया जाना चाहिए, लेकिन मैं इस सामान के साथ थोड़ा सा जंगली हूं।

+2

आपके मूल्यों के संकेत की गणना करने का आपका तरीका बहुत जटिल है, क्यों न केवल '(x <0) 'उदा? पोर्टेबल उपयोग 'u] int64_t' होने के लिए। फिर आपके पास 'INT64_MAX' और' INT64_MIN' निःशुल्क है और इसके लिए अपने स्वयं के स्थिरांक का उपयोग करने की आवश्यकता नहीं है। –

+0

सी (एचडब्ल्यू) में बिटवाइड संतृप्त परिवर्धन के संभावित डुप्लिकेट (http://stackoverflow.com/questions/5277623/bitwise-saturated-addition-in-c-hw) – jxh

+0

जीसीसी 128-बिट संख्याओं पर संचालन को अनुकूलित कर सकता है। कुछ क्लैंप ((int128_t) x + y, INT64_MIN, INT64_MAX) जैसे काम करने की कोशिश करें) और देखें कि यह स्वीकार्य है या नहीं। – zch

उत्तर

1

मैं अभी भी एक सभ्य पोर्टेबल समाधान के लिए देख रहा हूँ, लेकिन यह के रूप में अच्छा है के रूप में मैं अब तक लेकर आए हैं: सुधार के लिए

सुझाव?

int64 saturated_add(int64 x, int64 y) { 
#if __GNUC__ && __X86_64__ 
    asm("add %1, %0\n\t" 
     "jno 1f\n\t" 
     "cmovge %3, %0\n\t" 
     "cmovl %2, %0\n" 
     "1:" : "+r"(x) : "r"(y), "r"(kint64min), "r"(kint64max)); 
    return x; 
#else 
    return portable_saturated_add(x, y); 
#endif 
} 
+1

एक समाधान के लिए मेरा उत्तर देखें जो केवल एक सशर्त चाल उत्पन्न करता है। चाहे यह बेहतर है या नहीं, आपको बेंचमार्क करना होगा। –

+0

मुझे आश्चर्य है कि आप कुछ एएसएम ("%% [y],% [x] \ n \ t" "jno 1f \ n \ t" "xor %% रैक्स, %% रैक्स \ n \ t" "mov% [MAX],% [x] \ n \ t" "%% al \ n \ t" "%% रैक्स जोड़ें,% [x] \ n \ t" "1:": [x] " + आर "(एक्स): [वाई]" आर "(वाई), [MAX]" i "(INT64_MAX):" eax "," cc ");'। पहले ब्लश पर, यह आपके कोड से अधिक लंबा लग सकता है, लेकिन याद रखें कि आपके कोड को आपके एएसएम को कॉल करने से पहले% 2 और% 3 में मान लोड करने की आवश्यकता है, भले ही वह उनका उपयोग न करे। मेरा केवल ओवरफ्लो पर लोड करता है (संभवतः कम आम मामला)। एनबी: देर हो चुकी है और मैंने इसे नहीं चलाया है। और @JensGustedt के रूप में, बेंचमार्क कहते हैं। –

9

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

#include <stdint.h> 

int64_t sadd64(int64_t a, int64_t b) 
{ 
    if (a > 0) { 
     if (b > INT64_MAX - a) { 
      return INT64_MAX; 
     } 
    } else if (b < INT64_MIN - a) { 
      return INT64_MIN; 
    } 

    return a + b; 
} 
+2

बहुत अच्छा समाधान। – jxh

+1

सहमत हैं कि यह पोर्टेबल, सुरुचिपूर्ण और 100% सही है। एक संभावित अनुकूलन: 'INT64_MAX' वापसी के बजाय, 'b = INT64_MAX - a' आज़माएं। और 'INT64_MIN' वापसी के बजाय, 'b = INT64_MIN - a' आज़माएं। मेरे कंपाइलर (जीसीसी 4.7.3) पर, यह सशर्त चाल के साथ दो सशर्त शाखाओं की जगह, थोड़ा हल्का कोड उत्पन्न करता है। (दूसरी ओर, यह अधिक डेटा निर्भरताओं को प्रस्तुत करता है, इसलिए यह धीमा हो सकता है ...) – Nemo

+0

मैं मानता हूं कि यह सही, "सीधा" समाधान है। @ नीमो, वास्तव में एक संभावना है जिसके परिणामस्वरूप केवल एक सशर्त कदम है, नीचे मेरा जवाब देखें। इनमें से कौन सा समाधान अधिक कुशल है केवल बेंचमार्किंग दिखा सकता है। –

3

यह एक समाधान है कि नस कि टिप्पणियों में से एक में दिया गया था में भी जारी है, और ouah के समाधान में इस्तेमाल किया गया है, है। यहां तैयार किए गए कोड सशर्त छलांग

int64_t signed_saturated_add(int64_t x, int64_t y) { 
    // determine the lower or upper bound of the result 
    int64_t ret = (x < 0) ? INT64_MIN : INT64_MAX; 
    // this is always well defined: 
    // if x < 0 this adds a positive value to INT64_MIN 
    // if x > 0 this subtracts a positive value from INT64_MAX 
    int64_t comp = ret - x; 
    // the condition is equivalent to 
    // ((x < 0) && (y > comp)) || ((x >=0) && (y <= comp)) 
    if ((x < 0) == (y > comp)) ret = x + y; 
    return ret; 
} 

पहले दिखता बिना किया जाना चाहिए के रूप में अगर वहाँ करने के लिए एक सशर्त कदम होगा, लेकिन क्योंकि विशेष मूल्यों की मेरी संकलक एक अतिरिक्त के साथ बंद हो जाता है: 2 के पूरक में INT64_MININT64_MAX+1 है । कुछ भी ठीक होने पर, राशि के असाइनमेंट के लिए केवल एक सशर्त कदम है।

इसमें से कोई भी यूबी नहीं है, क्योंकि अमूर्त राज्य मशीन में योग केवल तभी किया जाता है जब कोई ओवरफ़्लो न हो।

+1

सुंदर (+1)। कुछ टिप्पणियों का उपयोग कर सकते हैं :-) – Nemo

+1

@ नीमो, हाँ, थोड़ा सा, कल रात बहुत देर हो चुकी थी। अब मैंने कुछ व्याख्यात्मक टिप्पणियां जोड़ दी हैं। –

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