8

जावा में दो long मानों को कैसे जोड़ सकता है ताकि यदि परिणाम ओवरफ्लो हो तो यह श्रेणी 0xपर क्लैंप हो गया है?दो हस्ताक्षरित जावा 'लम्बे' मानों का संतृप्त जोड़ा

ints जोड़ने एक long परिशुद्धता में अंकगणित को निष्पादित और परिणाम एक int करने के लिए वापस डाल सकता, उदाहरण के लिए:

int saturatedAdd(int x, int y) { 
    long sum = (long) x + (long) y; 
    long clampedSum = Math.max((long) Integer.MIN_VALUE, 
          Math.min(sum, (long) Integer.MAX_VALUE)); 
    return (int) clampedSum; 
} 

या

import com.google.common.primitives.Ints; 

int saturatedAdd(int x, int y) { 
    long sum = (long) x + (long) y; 
    return Ints.saturatedCast(sum); 
} 

लेकिन long के मामले में कोई बड़ा आदिम प्रकार जो इंटरमीडिएट (अनक्लेम्ड) योग को पकड़ सकता है।

इस के बाद से, जावा है मैं inline assembly उपयोग कर सकते हैं नहीं (विशेष रूप से SSE के संतृप्त ऐड निर्देश में।)

यह लागू किया जा सकता BigInteger उदा का उपयोग कर,

static final BigInteger bigMin = BigInteger.valueOf(Long.MIN_VALUE); 
static final BigInteger bigMax = BigInteger.valueOf(Long.MAX_VALUE); 

long saturatedAdd(long x, long y) { 
    BigInteger sum = BigInteger.valueOf(x).add(BigInteger.valueOf(y)); 
    return bigMin.max(sum).min(bigMax).longValue(); 
} 

लेकिन प्रदर्शन के लिए महत्वपूर्ण है इसलिए इस विधि आदर्श नहीं है (हालांकि परीक्षण के लिए उपयोगी।)

मैं नहीं जानता कि क्या शाखाओं से बचने में काफी जावा में प्रदर्शन को प्रभावित कर सकते हैं। मुझे लगता है कि यह कर सकता है, लेकिन मैं ब्रांचिंग के साथ और बिना दोनों विधियों को बेंचमार्क करना चाहता हूं।

संबंधित: How to do saturating addition in C?

+0

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

उत्तर

5

आप संख्या के हस्ताक्षर के आधार पर चार मामलों में तोड़ने के लिए सक्षम होना चाहिए: तो संख्याओं में से एक शून्य है, इस सवाल का जवाब दूसरे नंबर है। यदि कोई सकारात्मक और अन्य नकारात्मक है, तो आप अधिक या नीचे नहीं जा सकते हैं। यदि दोनों सकारात्मक हैं तो आप केवल अतिप्रवाह कर सकते हैं। यदि दोनों नकारात्मक हैं तो आप केवल निम्न प्रवाह कर सकते हैं।

if(x == 0 || y == 0 || (x > 0^y > 0)){ 
    //zero+N or one pos, another neg = no problems 
    return x+y; 
}else if(x > 0){ 
    //both pos, can only overflow 
    return Long.MAX_VALUE - x < y ? Long.MAX_VALUE : x+y; 
}else{ 
    //both neg, can only underflow 
    return Long.MIN_VALUE - x > y ? Long.MIN_VALUE : x+y; 
} 
2

यहाँ एक शाखा-नि: शुल्क संस्करण में अपने प्रयास है:

बस अगर यह अवांछित मामले में परिणाम होगा देखने के लिए पिछले दो मामलों के लिए एक अतिरिक्त गणना करते

long saturatedAdd(long x, long y) { 
    // Sum ignoring overflow/underflow 
    long s = x + y; 

    // Long.MIN_VALUE if result positive (potential underflow) 
    // Long.MAX_VALUE if result negative (potential overflow) 
    long limit = Long.MIN_VALUE^(s >> 63); 

    // -1 if overflow/underflow occurred, 0 otherwise 
    long overflow = ((x^s) & ~(x^y)) >> 63; 

    // limit if overflowed/underflowed, else s 
    return ((limit^s) & overflow)^s; 
} 
1

आप

int saturatedAdd(int x, int y) { 
    return (int)(x + (double) y); 
} 

x और: भी प्रकार कास्टिंग के अंतर्निहित संतृप्ति तंत्र का उपयोग कर सकतेको double के रूप में जोड़ा गया है, और int पर कास्टिंग [Integer.MIN_VALUE, Integer.MAX_VALUE] सीमा पर संतृप्त होगा।

यह double की शुद्धता के रूप में long रों के लिए के रूप में उपयुक्त नहीं है long की तुलना में कम है, लेकिन अगर परिशुद्धता के रूप में महत्वपूर्ण नहीं है, यह पर्याप्त होगा।