जावा पूर्णांक को कैसे हटाता है और ओवरफ्लो करता है और आप इसकी जांच कैसे करेंगे?


226

जावा पूर्णांक को कैसे हटाता है और ओवरफ्लो करता है?

उसी से आगे बढ़ते हुए, आप कैसे जाँचेंगे / परीक्षण करेंगे कि यह क्या हो रहा है?


28
यह बहुत बुरा है कि जावा सीपीयू के अतिप्रवाह झंडे को अप्रत्यक्ष पहुंच प्रदान नहीं करता है , जैसा कि C # में किया गया है
ड्रू नोक

@DrewNoakes और यह बहुत बुरा है कि C # checkedजहां तक ​​मुझे पता है डिफ़ॉल्ट नहीं है। मुझे नहीं लगता कि यह बहुत अधिक उपयोग किया जाता है, और टाइपिंग checked { code; }एक पद्धति को कॉल करने के रूप में ज्यादा काम के बारे में है।
मार्टन बोडेवेस

2
@MaartenBodewes, आप इसे किसी असेंबली के संकलन के दौरान डिफ़ॉल्ट के रूप में सेट कर सकते हैं। csc /checked ...या Visual Studio में प्रोजेक्ट के गुण फलक में गुण सेट करें।
ड्रू नोकें

@DrewNoakes ठीक है, दिलचस्प है। थोड़ा अजीब है कि यह कोड के बाहर एक सेटिंग है, हालांकि। सामान्य तौर पर मैं इस तरह की सेटिंग्स (संभवत: अपवादों को छोड़कर) की परवाह किए बिना एक कार्यक्रम के समान व्यवहार करना चाहता हूं।
मार्टन बॉड्यूज

@MaartenBodewes, मुझे लगता है कि तर्क यह है कि जाँच के लिए एक गैर तुच्छ पूर्ण ओवरहेड है। तो शायद आप इसे डिबग बिल्ड में सक्षम करेंगे, फिर इसे रिलीज़ बिल्ड में अक्षम कर सकते हैं, जैसे कई अन्य प्रकार के दावे।
ड्रू नोज

जवाबों:


217

यदि यह ओवरफ्लो होता है, तो यह न्यूनतम मूल्य पर वापस चला जाता है और वहां से जारी रहता है। यदि यह कम होता है, तो यह अधिकतम मूल्य पर वापस चला जाता है और वहां से जारी रहता है।

आप पहले से ही इस प्रकार की जाँच कर सकते हैं:

public static boolean willAdditionOverflow(int left, int right) {
    if (right < 0 && right != Integer.MIN_VALUE) {
        return willSubtractionOverflow(left, -right);
    } else {
        return (~(left ^ right) & (left ^ (left + right))) < 0;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    if (right < 0) {
        return willAdditionOverflow(left, -right);
    } else {
        return ((left ^ right) & (left ^ (left - right))) < 0;
    }
}

(आप के लिए एक ही जाँच करने के लिए intद्वारा स्थानापन्न कर सकते हैं )longlong

यदि आपको लगता है कि यह अक्सर से अधिक हो सकता है, तो डेटाटाइप या ऑब्जेक्ट का उपयोग करने पर विचार करें जो बड़े मूल्यों, जैसे longया हो सकता है java.math.BigInteger। अंतिम एक अतिप्रवाह नहीं है, व्यावहारिक रूप से, उपलब्ध जेवीएम मेमोरी सीमा है।


यदि आप जावा 8 पर पहले से ही हैं, तो आप नए Math#addExact()और Math#subtractExact()तरीकों का उपयोग कर सकते हैं, जो ArithmeticExceptionअतिप्रवाह पर फेंक देंगे ।

public static boolean willAdditionOverflow(int left, int right) {
    try {
        Math.addExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    try {
        Math.subtractExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

स्रोत कोड यहां और यहां पाया जा सकता है क्रमशः ।

बेशक, आप उन्हें booleanउपयोगिता पद्धति में छिपाने के बजाय बस उनका सही उपयोग कर सकते हैं ।


13
@dhblah, मान लीजिए कि अधिकतम और न्यूनतम मानों को जावा +100, -100क्रमशः एक इंट के लिए अनुमति देता है। यदि आप एक जावा पूर्णांक में एक जोड़ रहे थे, तो यह प्रक्रिया इस तरह दिखेगी जैसे यह बह निकली हो। 98, 99, 100, -100, -99, -98, ...। क्या यह ज़्यादा सही लगता है?
ऑस्टिन ए

6
मैं कोड को तुरंत उपयोग करने के बजाय उपयोगिता विधियों का उपयोग करने की सलाह देता हूं। उपयोगिता के तरीके आंतरिक हैं और मशीन विशिष्ट कोड द्वारा प्रतिस्थापित किए जाएंगे। एक त्वरित परीक्षण से पता चला है कि Math.addExact एक कॉपी किए गए तरीके (Java 1.8.0_40) की तुलना में 30% अधिक तेज है।
तिलमनज

1
@ErikE Math#addExactवाक्य रचना सामान्य रूप से प्रयोग किया जाता है जब javadocs लेखन है - जबकि सामान्य रूप से है कि करने के लिए परिवर्तित किया जा चाहते हैं Math.addExact, कभी कभी अन्य रूप बस चारों ओर चिपक
Pokechu22

1
If it underflows, it goes back to the maximum value and continues from there.- आपको लगता है कि नकारात्मक अतिप्रवाह के साथ भ्रमित हो रहा है। पूर्णांक में अंडरफ़्लो हर समय होता है (जब परिणाम एक अंश होता है)।
नौ

1
en.wikipedia.org/wiki/Arithmetic_underflow का कहना है कि अंडरफ्लो एक कंप्यूटर प्रोग्राम में एक ऐसी स्थिति है जहां गणना का परिणाम कंप्यूटर की तुलना में छोटे निरपेक्ष मूल्य की एक संख्या है जो वास्तव में अपने सीपीयू पर मेमोरी में प्रतिनिधित्व कर सकता है। इसलिए अंडरफ़्लो जावा इंटेगर पर लागू नहीं होता है। @ बालसु
याओ

66

खैर, जहां तक ​​आदिम पूर्णांक प्रकार के रूप में जाते हैं, जावा डोंट ओवर ओवर / अंडरफ्लो को संभालता है (फ्लोट के लिए और डबल व्यवहार भिन्न होता है, यह IEEE-754 जनादेश के रूप में +/- अनंत तक प्रवाहित होगा)।

दो इंटों को जोड़ते समय, ओवरफ्लो होने पर आपको कोई संकेत नहीं मिलेगा। अतिप्रवाह के लिए जाँच करने का एक सरल तरीका यह है कि अगले बड़े प्रकार का उपयोग वास्तव में ऑपरेशन करने और जाँचने के लिए किया जाए कि परिणाम अभी भी स्रोत प्रकार के लिए सीमा में है:

public int addWithOverflowCheck(int a, int b) {
    // the cast of a is required, to make the + work with long precision,
    // if we just added (a + b) the addition would use int precision and
    // the result would be cast to long afterwards!
    long result = ((long) a) + b;
    if (result > Integer.MAX_VALUE) {
         throw new RuntimeException("Overflow occured");
    } else if (result < Integer.MIN_VALUE) {
         throw new RuntimeException("Underflow occured");
    }
    // at this point we can safely cast back to int, we checked before
    // that the value will be withing int's limits
    return (int) result;
}

आप थ्रो क्लॉज़ के स्थान पर क्या करेंगे, यह आपके एप्लिकेशन की आवश्यकताओं (थ्रो, मिनट / अधिकतम फ्लश या सिर्फ लॉग इन करने पर निर्भर करता है) पर निर्भर करता है। यदि आप लंबे ऑपरेशन पर अतिप्रवाह का पता लगाना चाहते हैं, तो आप भाग्य से बाहर हो गए हैं, इसके बजाय BigInteger का उपयोग करें।


संपादित करें (2014-05-21): चूंकि यह प्रश्न काफी बार संदर्भित किया जा रहा है और मुझे स्वयं उसी समस्या को हल करना था, इसलिए एक ही विधि द्वारा अतिप्रवाह की स्थिति का मूल्यांकन करना काफी आसान है एक सीपीयू अपने वी ध्वज की गणना करेगा।

इसकी मूल रूप से एक बूलियन अभिव्यक्ति है जिसमें परिणाम के साथ-साथ दोनों ऑपरेंड का संकेत शामिल है:

/**
 * Add two int's with overflow detection (r = s + d)
 */
public static int add(final int s, final int d) throws ArithmeticException {
    int r = s + d;
    if (((s & d & ~r) | (~s & ~d & r)) < 0)
        throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");    
    return r;
}

जावा में पूरे 32 बिट्स पर अभिव्यक्ति (यदि में) लागू करने के लिए सरल है, और <0 का उपयोग करके परिणाम की जांच करें (यह प्रभावी रूप से साइन बिट का परीक्षण करेगा)। सिद्धांत सभी पूर्णांक आदिम प्रकारों के लिए समान रूप से काम करता है , उपरोक्त विधि में सभी घोषणाओं को लंबे समय तक बदलने से यह लंबे समय तक काम करता है।

छोटे प्रकार के लिए, उदाहरण के लिए अंतर्निहित रूपांतरण के कारण (विवरण के लिए बिट्स संचालन के लिए जेएलएस देखें), चेक करने के बजाय <0, चेक को साइन बिट को स्पष्ट रूप से मास्क करने की जरूरत है (छोटे ऑपरेंड के लिए 0x8000, बायर्स ऑपरेंड के लिए 0x80, कास्ट को समायोजित करें) और पैरामीटर घोषणा appropiately):

/**
 * Subtract two short's with overflow detection (r = d - s)
 */
public static short sub(final short d, final short s) throws ArithmeticException {
    int r = d - s;
    if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
        throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
    return (short) r;
}

(नोट ऊपर के उदाहरण के लिए अभिव्यक्ति की जरूरत का उपयोग करता है घटाना अतिप्रवाह का पता लगाने)


तो ये बूलियन भाव कैसे / क्यों काम करते हैं? सबसे पहले, कुछ तार्किक सोच बताती है कि अतिप्रवाह तभी हो सकता है जब दोनों तर्कों के संकेत समान हों। क्योंकि, यदि एक तर्क नकारात्मक है और एक सकारात्मक है, तो परिणाम (ऐड) शून्य के करीब होना चाहिए, या चरम मामले में एक तर्क शून्य है, अन्य तर्क के समान। अपने आप से तर्क नहीं कर सकते अतिप्रवाह स्थिति नहीं बनाया जा सकता है, इसलिए उनकी राशि एक अतिप्रवाह नहीं बना सकती है।

तो क्या होगा यदि दोनों तर्कों में एक ही संकेत हो? आइए इस मामले पर नज़र डालें, दोनों सकारात्मक हैं: MAX_VALUE से बड़े योग बनाने वाले दो तर्क जोड़ने से हमेशा नकारात्मक मान निकलेगा, इसलिए यदि arg1 + arg2> MAX_VALUE पर अतिप्रवाह होता है । अब जो अधिकतम मूल्य हो सकता है वह MAX_VALUE + MAX_VALUE होगा (चरम स्थिति दोनों तर्क MAX_VALUE हैं)। एक बाइट (उदाहरण) के लिए जिसका अर्थ होगा 127 + 127 = 254। सभी मूल्यों के बिट प्रतिनिधित्व को देखते हुए जो दो सकारात्मक मूल्यों को जोड़ सकते हैं, एक यह पाता है कि जो अतिप्रवाह (128 से 254) सभी में बिट 7 सेट है, जबकि सभी जो अतिप्रवाह नहीं करते हैं (0 से 127) बिट 7 (सबसे ऊपर, संकेत) को मंजूरी दे दी है। अभिव्यक्ति की जांच का पहला (दाएं) हिस्सा ठीक यही है:

if (((s & d & ~r) | (~s & ~d & r)) < 0)

(~ s & ~ d & r) सत्य हो जाता है, केवल अगर , दोनों ऑपरेंड (s, d) धनात्मक होते हैं और परिणाम (r) ऋणात्मक होता है (अभिव्यक्ति सभी 32 बिट्स पर काम करता है, लेकिन एकमात्र बिट जिसमें हम रुचि रखते हैं) सबसे ऊपरी (साइन) बिट है, जिसे <0) के विरुद्ध जांचा जाता है।

अब यदि दोनों तर्क नकारात्मक हैं, तो उनकी राशि किसी भी तर्क से शून्य के करीब नहीं हो सकती है, यह राशि न्यूनतम अनंतता के करीब होनी चाहिए। सबसे अधिक मूल्य जो हम पैदा कर सकते हैं, वह MIN_VALUE + MIN_VALUE है, जो (बाइट उदाहरण के लिए फिर से) दिखाता है कि किसी भी रेंज मान (-1 से -128) के लिए साइन बिट सेट है, जबकि कोई भी संभावित अतिप्रवाह मूल्य (-129 -256) ) का संकेत बिट साफ़ हो गया है। तो परिणाम का संकेत फिर से अतिप्रवाह स्थिति का पता चलता है। दैट लेफ्ट हाफ (s & d & ~ r) उस मामले के लिए जाँच करता है जहाँ दोनों तर्क (s, d) नकारात्मक हैं और इसका परिणाम सकारात्मक है। तर्क काफी हद तक सकारात्मक मामले के बराबर है; सभी बिट पैटर्न जो दो नकारात्मक मूल्यों को जोड़ने के परिणामस्वरूप हो सकते हैं, साइन बिट को साफ कर दिया जाएगा अगर और केवल अगर एक अंडरफ़्लो हुआ।


1
आप इसे बिटवाइज़ ऑपरेटर्स के साथ-साथ betterlogic.com/roger/2011/05/…
rogerdpack

1
यह काम करेगा लेकिन मैं मान रहा हूं कि यह एक बुरा प्रदर्शन होगा।
चेसोफर्नाड

33

डिफ़ॉल्ट रूप से, Java का int और long math चुपचाप ओवरफ्लो और अंडरफ्लो पर चारों ओर लपेटता है। (अन्य पूर्णांक प्रकारों पर पूर्णांक संचालन, पहले JLS 4.2.2 के अनुसार, इंट या लंबे समय तक ऑपरेंड को बढ़ावा देकर किया जाता है ।)

जावा 8, के रूप में java.lang.Mathप्रदान करता है addExact, subtractExact, multiplyExact, incrementExact, decrementExactऔर negateExactदोनों पूर्णांक और लंबी बहस है कि नामित कार्रवाई करने, अतिप्रवाह पर ArithmeticException फेंकने के लिए स्थिर तरीके। (कोई विभाजन विधि नहीं है - आपको एक विशेष मामले की जांच करनी होगी ()MIN_VALUE / -1 ) की ।)

जावा 8 के रूप में, java.lang.Math toIntExactएक int को लंबा कास्ट करने के लिए भी प्रदान करता है, ArithmeticException को फेंक देता है यदि लंबे मान किसी int में फिट नहीं होता है। यह उदाहरण के लिए अनियंत्रित लंबे गणित का उपयोग करके चींटियों के योग की गणना करने के लिए उपयोगी हो सकता है, फिर उपयोग करनाtoIntExact अंत में इंट को कास्ट करने के लिए (लेकिन अपनी राशि को अतिप्रवाह नहीं करने के लिए सावधान रहना) ।

यदि आप अभी भी जावा के पुराने संस्करण का उपयोग कर रहे हैं, तो Google Guava IntMath और LongMath स्थिर तरीकों को चेक किए गए जोड़, घटाव, गुणन और घातांक (अतिप्रवाह पर फेंकना) के लिए प्रदान करता है। ये वर्ग फैक्टरियल और द्विपद गुणांक की गणना करने के तरीके भी प्रदान करते हैं MAX_VALUEजो अतिप्रवाह पर लौटते हैं (जो जांच करने के लिए कम सुविधाजनक है)। अमरूद के आदिम उपयोगिता कक्षाएं, SignedBytes, UnsignedBytes, Shortsऔर Ints, प्रदान checkedCastबड़ा प्रकार (नीचे / अतिप्रवाह, पर IllegalArgumentException फेंकने को सीमित करने के लिए तरीके नहीं ArithmeticException), साथ ही saturatingCastतरीकों कि वापसी MIN_VALUEया MAX_VALUEअतिप्रवाह पर।


32

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

यह उत्तर पहले पूर्णांक ओवरफ़्लो का वर्णन करता है, एक उदाहरण देता है कि यह कैसे हो सकता है, यहां तक ​​कि अभिव्यक्ति मूल्यांकन में मध्यवर्ती मूल्यों के साथ, और फिर उन संसाधनों के लिंक देता है जो पूर्णांक ओवरफ़्लो को रोकने और पता लगाने के लिए विस्तृत तकनीक देते हैं।

पूर्ण या अनपेक्षित अतिप्रवाह में परिणामी अंकगणित और अभिव्यक्तियाँ एक सामान्य प्रोग्रामिंग त्रुटि हैं। अप्रत्याशित या अघोषित पूर्णांक अतिप्रवाह भी एक सुविख्यात शोषक सुरक्षा मुद्दा है, विशेष रूप से यह सरणी, स्टैक और सूची वस्तुओं को प्रभावित करता है।

अतिप्रवाह या तो सकारात्मक या नकारात्मक दिशा में हो सकता है जहां प्रश्न में आदिम प्रकार के लिए सकारात्मक या नकारात्मक मूल्य अधिकतम या न्यूनतम मूल्यों से परे होगा। ओवरफ़्लो अभिव्यक्ति या ऑपरेशन मूल्यांकन के दौरान एक मध्यवर्ती मूल्य में हो सकता है और एक अभिव्यक्ति या ऑपरेशन के परिणाम को प्रभावित कर सकता है जहां अंतिम मूल्य सीमा के भीतर होने की उम्मीद होगी।

कभी-कभी नकारात्मक अतिप्रवाह को गलती से अंडरफ्लो कहा जाता है। अंडरफ़्लो वह होता है जब कोई मूल्य प्रतिनिधित्व की अनुमति से शून्य के करीब होगा। अंडरफ़्लो पूर्णांक अंकगणित में होता है और अपेक्षित होता है। पूर्णांक अंडरफ़्लो तब होता है जब एक पूर्णांक मूल्यांकन -1 और 0 या 0 और 1. के बीच होगा। भिन्नात्मक परिणाम 0. से कम हो जाएगा। यह सामान्य है और पूर्णांक अंकगणित के साथ अपेक्षित है और त्रुटि नहीं माना जाता है। हालांकि, यह एक अपवाद को फेंकने वाले कोड को जन्म दे सकता है। एक उदाहरण "ArithmeticException: / शून्य से" अपवाद है यदि पूर्णांक अंडरफ़्लो का परिणाम अभिव्यक्ति में विभाजक के रूप में उपयोग किया जाता है।

निम्नलिखित कोड पर विचार करें:

int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;

जिसके परिणामस्वरूप x को 0 असाइन किया जा रहा है और bigValue / x के बाद के मूल्यांकन में एक अपवाद फेंकता है, "ArithmeticException: / by zero" (यानी शून्य से विभाजित), y के बजाय मान 2 असाइन किया जा रहा है।

X के लिए अपेक्षित परिणाम 858,993,458 होगा जो 2,147,483,647 के अधिकतम अंतर मूल्य से कम है। हालांकि, Integer.MAX_Value * 2 का मूल्यांकन करने से मध्यवर्ती परिणाम, 4,294,967,294 होगा, जो कि अधिकतम int मान से अधिक है और 2s पूरक पूर्णांक निरूपण के अनुसार -2 है। -2 / 5 के बाद का मूल्यांकन 0 को मूल्यांकन करता है जो x को सौंपा गया है।

कंप्यूटिंग एक्स के लिए एक्सप्रेशन को फिर से अभिव्यक्त करना, जब मूल्यांकन किया जाता है, तो गुणा करने से पहले विभाजित होता है, निम्न कोड:

int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;

x में परिणाम 858,993,458 और y को 2 असाइन किया जा रहा है, जो अपेक्षित है।

BigValue / 5 से मध्यवर्ती परिणाम 429,496,729 है जो एक इंट के लिए अधिकतम मान से अधिक नहीं है। 429,496,729 * 2 के बाद के मूल्यांकन एक इंट के लिए अधिकतम मूल्य से अधिक नहीं है और अपेक्षित परिणाम एक्स को सौंपा गया है। Y के लिए मूल्यांकन तब शून्य से विभाजित नहीं होता है। एक्स और वाई के लिए मूल्यांकन उम्मीद के मुताबिक काम करते हैं।

जावा पूर्णांक मानों को संग्रहीत किया जाता है और 2s पूरक पूर्णांक अभ्यावेदन के अनुसार व्यवहार किया जाता है। जब परिणामी मान अधिकतम या न्यूनतम पूर्णांक मानों से बड़ा या छोटा होगा, तो इसके बजाय 2 का पूरक पूर्णांक मान परिणाम होगा। स्थितियों में स्पष्ट रूप से 2s पूरक व्यवहार का उपयोग करने के लिए डिज़ाइन नहीं किया गया है, जो कि सबसे साधारण पूर्णांक अंकगणितीय स्थितियां हैं, जिसके परिणामस्वरूप 2s पूरक मूल्य प्रोग्रामिंग लॉजिक या कम्प्यूटेशन त्रुटि का कारण होगा जैसा कि ऊपर दिए गए उदाहरण में दिखाया गया था। एक उत्कृष्ट विकिपीडिया लेख में 2 एस तारीफों का वर्णन किया गया है जो बाइनरी पूर्णांक यहाँ हैं: दो का पूरक - विकिपीडिया

अनजाने पूर्णांक अतिप्रवाह से बचने की तकनीकें हैं। Techinques को प्री-कंडीशन टेस्टिंग, अपकास्टिंग और BigInteger के उपयोग के रूप में वर्गीकृत किया जा सकता है।

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

अंकगणित में अंकगणितीय ऑपरेशन या अभिव्यक्ति करने के लिए एक बड़े आदिम प्रकार का उपयोग करना और फिर निर्धारित करना कि परिणामी मान एक पूर्णांक के लिए अधिकतम या न्यूनतम मान से परे है। उभार के साथ भी, यह अभी भी संभव है कि एक ऑपरेशन या अभिव्यक्ति में मूल्य या कुछ मध्यवर्ती मूल्य, अपस्टॉक प्रकार के लिए अधिकतम या न्यूनतम मूल्यों से परे होगा और अतिप्रवाह का कारण होगा, जिसका पता भी नहीं चलेगा और अप्रत्याशित और अवांछित परिणाम पैदा करेगा। विश्लेषण या पूर्व-स्थितियों के माध्यम से, अतिप्रवाह के साथ अतिप्रवाह को रोकने के लिए संभव हो सकता है जब उत्थान के बिना रोकथाम संभव या व्यावहारिक नहीं है। यदि प्रश्न में पूर्णांक पहले से ही लंबे आदिम प्रकार हैं, तो जावा में आदिम प्रकार के साथ उत्थान संभव नहीं है।

BigInteger तकनीक में BigInteger का उपयोग करने वाले पुस्तकालय के तरीकों का उपयोग करके अंकगणितीय ऑपरेशन या अभिव्यक्ति के लिए BigInteger का उपयोग करना शामिल है। BigInteger अतिप्रवाह नहीं करता है। यदि आवश्यक हो तो यह सभी उपलब्ध मेमोरी का उपयोग करेगा। इसके अंकगणितीय तरीके सामान्य रूप से पूर्णांक संचालन की तुलना में थोड़े कम कुशल होते हैं। यह अभी भी संभव है कि बिगइंटर का उपयोग करने वाला परिणाम पूर्णांक के लिए अधिकतम या न्यूनतम मानों से परे हो सकता है, हालांकि, परिणाम के लिए अग्रणी अंकगणित में अतिप्रवाह नहीं होगा। प्रोग्रामिंग और डिज़ाइन को अभी भी यह निर्धारित करने की आवश्यकता होगी कि यदि कोई BigInteger परिणाम वांछित आदिम परिणाम प्रकार, जैसे, int या लंबे समय के लिए अधिकतम या न्यूनतम मान से परे है, तो क्या करना है।

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

मानक खंड जो पूर्णांक अतिप्रवाह को रोकने या पता लगाने के लिए कोडिंग तकनीकों के व्यावहारिक उदाहरणों का वर्णन और समाहित करता है, यहां है: NUM00-J। पूर्णांक अतिप्रवाह का पता लगाना या रोकना

जावा के लिए सीईआरटी ओरेकल सिक्योर कोडिंग स्टैंडर्ड का बुक फॉर्म और पीडीएफ फॉर्म भी उपलब्ध है।


यह यहां सबसे अच्छा जवाब है क्योंकि यह स्पष्ट रूप से बताता है कि अंडरफ्लो क्या है (स्वीकृत उत्तर नहीं है) और अतिप्रवाह / अंडरफ्लो से निपटने की तकनीकों को भी सूचीबद्ध करता है
nave

12

केवल थोड़े इस समस्या में स्वयं चलकर, यहाँ मेरा समाधान (गुणा और जोड़ दोनों के लिए) है:

static boolean wouldOverflowOccurwhenMultiplying(int a, int b) {
    // If either a or b are Integer.MIN_VALUE, then multiplying by anything other than 0 or 1 will result in overflow
    if (a == 0 || b == 0) {
        return false;
    } else if (a > 0 && b > 0) { // both positive, non zero
        return a > Integer.MAX_VALUE / b;
    } else if (b < 0 && a < 0) { // both negative, non zero
        return a < Integer.MAX_VALUE / b;
    } else { // exactly one of a,b is negative and one is positive, neither are zero
        if (b > 0) { // this last if statements protects against Integer.MIN_VALUE / -1, which in itself causes overflow.
            return a < Integer.MIN_VALUE / b;
        } else { // a > 0
            return b < Integer.MIN_VALUE / a;
        }
    }
}

boolean wouldOverflowOccurWhenAdding(int a, int b) {
    if (a > 0 && b > 0) {
        return a > Integer.MAX_VALUE - b;
    } else if (a < 0 && b < 0) {
        return a < Integer.MIN_VALUE - b;
    }
    return false;
}

गलत होने पर सही करने के लिए स्वतंत्र महसूस करें या यदि इसे सरल बनाया जा सकता है। मैंने गुणा पद्धति के साथ कुछ परीक्षण किए हैं, ज्यादातर किनारे के मामले हैं, लेकिन यह अभी भी गलत हो सकता है।


विभाजन गुणन के सापेक्ष धीमा होने के लिए उपयुक्त है। के लिए int*int, मुझे लगता है कि longअगर परिणाम में फिट बैठता है और देखने के लिए बस कास्टिंग intहोगा सबसे तेज़ दृष्टिकोण होगा। के लिए long*long, अगर एक को सामान्य ऑपरेंड सकारात्मक होने के लिए, एक ऊपरी में प्रत्येक विभाजित है और 32-बिट हिस्सों कम कर सकते हैं, लंबे समय के लिए हर आधे को बढ़ावा देने के (साइन एक्सटेंशन के बारे में सावधान रहना होगा!), और उसके बाद की गणना दो आंशिक उत्पादों [ऊपरी हिस्सों में से एक होना चाहिए शून्य हो]।
सुपरकैट

जब आप "लंबे समय तक" लंबे समय तक कहते हैं, अगर कोई सकारात्मक होने के लिए ऑपरेंड को सामान्य करता है ... ", तो आप Long.MIN_VALUE को सामान्य करने के बारे में कैसे जाएंगे?
सुगंध

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

8

ऐसे पुस्तकालय हैं जो सुरक्षित अंकगणित संचालन प्रदान करते हैं, जो पूर्णांक / अतिप्रवाह की जांच करते हैं। उदाहरण के लिए, अमरूद का IntMath.checkedAdd (int a, int b) का योग देता है aऔर b, बशर्ते कि यह ओवरफ्लो नहीं होता है, और ArithmeticExceptionयदि a + bहस्ताक्षरित intअंकगणित में ओवरफ्लो होता है ।


हां, यह एक अच्छा विचार है, जब तक आप जावा 8 या उच्चतर नहीं होते हैं, उस स्थिति में Mathकक्षा में समान कोड होता है।
मार्टेन बोडेवेस

6

यह चारों ओर लपेटता है।

उदाहरण के लिए:

public class Test {

    public static void main(String[] args) {
        int i = Integer.MAX_VALUE;
        int j = Integer.MIN_VALUE;

        System.out.println(i+1);
        System.out.println(j-1);
    }
}

प्रिंट

-2147483648
2147483647

कुंआ! और अब, क्या आप जवाब दे सकते हैं, इसे जटिल कैलकुलस में कैसे पहचाना जाए?
ऑबिन

5

मुझे लगता है कि आपको कुछ इस तरह का उपयोग करना चाहिए और इसे Upcasting कहा जाता है:

public int multiplyBy2(int x) throws ArithmeticException {
    long result = 2 * (long) x;    
    if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE){
        throw new ArithmeticException("Integer overflow");
    }
    return (int) result;
}

आप यहां आगे पढ़ सकते हैं: पूर्णांक अतिप्रवाह का पता लगाना या रोकना

यह काफी विश्वसनीय स्रोत है।


3

यह कुछ भी नहीं करता है - अंडर / ओवरफ्लो बस होता है।

एक "-1" जो एक संगणना का परिणाम है कि अतिप्रवाहित "-1" से अलग नहीं है जो किसी अन्य जानकारी से उत्पन्न हुआ है। तो आप कुछ स्थिति के माध्यम से या केवल एक मूल्य का निरीक्षण करके यह नहीं बता सकते हैं कि यह अतिप्रवाहित है या नहीं।

लेकिन अतिप्रवाह से बचने के लिए आप अपनी गणनाओं के बारे में होशियार हो सकते हैं, अगर यह मायने रखता है, या कम से कम यह जान लें कि यह कब होगा। आपकी स्थिति क्या है?


यह वास्तव में एक स्थिति नहीं है, बस कुछ ऐसा है जिसके बारे में मैं उत्सुक हूं और मुझे सोच रहा है। यदि आपको एक उदाहरण उपयोग-केस की आवश्यकता है, तो यहां एक है: मेरे पास एक वर्ग है जिसका अपना आंतरिक चर है जिसे 'सेकंड' कहा जाता है। मेरे पास दो विधियां हैं जो एक पूर्णांक को एक पैरामीटर के रूप में लेती हैं और उस हिसाब से वृद्धि (क्रमशः) 'सेकंड' होगी। आप कैसे जांचेंगे कि एक अंडरफ्लो / ओवरफ्लो हो रहा है और आप इसे होने से कैसे रोकेंगे?
कुषलप

1
static final int safeAdd(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE - right
                : left < Integer.MIN_VALUE - right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left + right;
}

static final int safeSubtract(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left < Integer.MIN_VALUE + right
                : left > Integer.MAX_VALUE + right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left - right;
}

static final int safeMultiply(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE/right
                  || left < Integer.MIN_VALUE/right
                : (right < -1 ? left > Integer.MIN_VALUE/right
                                || left < Integer.MAX_VALUE/right
                              : right == -1
                                && left == Integer.MIN_VALUE) ) {
    throw new ArithmeticException("Integer overflow");
  }
  return left * right;
}

static final int safeDivide(int left, int right)
                 throws ArithmeticException {
  if ((left == Integer.MIN_VALUE) && (right == -1)) {
    throw new ArithmeticException("Integer overflow");
  }
  return left / right;
}

static final int safeNegate(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return -a;
}
static final int safeAbs(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return Math.abs(a);
}

2
यह परीक्षण संभालता है। हालाँकि यह नहीं समझाता है कि जावा पूर्णांक को कैसे हटाता है और ओवरफ्लो करता है (समझाने के लिए कुछ पाठ जोड़ें)।
स्पेंसर Wieczorek

1

मुझे लगता है कि यह ठीक होना चाहिए।

static boolean addWillOverFlow(int a, int b) {
    return (Integer.signum(a) == Integer.signum(b)) && 
            (Integer.signum(a) != Integer.signum(a+b)); 
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.