अंकगणित अतिप्रवाह की अनदेखी क्यों की जाती है?


76

कभी अपनी पसंदीदा प्रोग्रामिंग भाषा में 1 से 2,000,000 तक सभी संख्याओं को समेटने की कोशिश की? परिणाम को मैन्युअल रूप से गणना करना आसान है: 2,000,001,000,000, जो एक अहस्ताक्षरित 32 बिट पूर्णांक के अधिकतम मूल्य से कुछ 900 गुना बड़ा है।

C # प्रिंट आउट -1453759936- एक नकारात्मक मान! और मुझे लगता है कि जावा भी ऐसा ही करता है।

इसका मतलब है कि कुछ सामान्य प्रोग्रामिंग भाषाएं हैं जो डिफ़ॉल्ट रूप से अंकगणितीय अतिप्रवाह को अनदेखा करती हैं (सी # में, इसे बदलने के लिए छिपे हुए विकल्प हैं)। यह एक ऐसा व्यवहार है जो मुझे बहुत जोखिम भरा लगता है, और एरियन 5 की दुर्घटना ऐसी अतिप्रवाह के कारण नहीं हुई थी?

तो: इस तरह के खतरनाक व्यवहार के पीछे डिजाइन के फैसले क्या हैं?

संपादित करें:

इस सवाल का पहला जवाब जाँच की अत्यधिक लागत को व्यक्त करता है। आइए इस धारणा का परीक्षण करने के लिए एक लघु C # कार्यक्रम निष्पादित करें:

Stopwatch watch = Stopwatch.StartNew();
checked
{
    for (int i = 0; i < 200000; i++)
    {
        int sum = 0;
        for (int j = 1; j < 50000; j++)
        {
            sum += j;
        }
    }
}
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);

मेरी मशीन पर, चेक किया गया संस्करण 11015ms लेता है, जबकि अनियंत्रित संस्करण 4125ms लेता है। यानी चेकिंग स्टेप लगभग दो बार लगते हैं जब तक संख्याओं को जोड़ते हैं (मूल समय में कुल 3 गुना)। लेकिन 10,000,000,000 पुनरावृत्तियों के साथ, एक चेक द्वारा लिया गया समय अभी भी 1 नैनोसेकंड से कम है। ऐसी स्थिति हो सकती है जहां यह महत्वपूर्ण है, लेकिन अधिकांश अनुप्रयोगों के लिए, इससे कोई फर्क नहीं पड़ेगा।

2 संपादित करें:

मैंने हमारे सर्वर एप्लिकेशन (कई सेंसर से प्राप्त डेटा का विश्लेषण करने वाली एक विंडोज सेवा, काफी कुछ क्रंचिंग शामिल है) को /p:CheckForOverflowUnderflow="false"पैरामीटर (सामान्य रूप से, मैं ओवरफ्लो चेक स्विच ऑन करता हूं) और इसे एक डिवाइस पर तैनात किया। नागियोस मॉनिटरिंग से पता चलता है कि औसत सीपीयू लोड 17% रहा।

इसका मतलब यह है कि ऊपर दिए गए उदाहरण में पाया गया प्रदर्शन हिट हमारे आवेदन के लिए पूरी तरह अप्रासंगिक है।


19
नोट के रूप में, C # के लिए आप checked { }उस कोड के हिस्सों को चिह्नित करने के लिए अनुभाग का उपयोग कर सकते हैं जो अंकगणितीय अतिप्रवाह चेक करना चाहिए। यह प्रदर्शन के कारण है
पावेल dueukasik

14
"कभी अपनी पसंदीदा प्रोग्रामिंग भाषा में 1 से 2,000,000 तक सभी संख्याओं को समेटने की कोशिश की?" - हां (1..2_000_000).sum #=> 2000001000000:। मेरी पसंदीदा भाषाओं में से एक और sum [1 .. 2000000] --=> 2000001000000:। मेरा पसंदीदा नहीं Array.from({length: 2000001}, (v, k) => k).reduce((acc, el) => acc + el) //=> 2000001000000:। (निष्पक्ष होने के लिए, आखिरी वाला धोखा दे रहा है।)
जॉर्ग डब्ल्यू मित्तग

27
IntegerHaskell में @BernhardHiller मनमानी-सटीक है, यह किसी भी संख्या को तब तक आयोजित करेगा जब तक आप आवंटन योग्य RAM से बाहर नहीं निकल जाते।
पॉलिग्नोम

50
एरियन 5 दुर्घटना एक अतिप्रवाह के लिए जाँच करने के कारण हुई थी जो कोई फर्क नहीं पड़ता था - रॉकेट उड़ान के एक हिस्से में था जहां गणना के परिणाम की आवश्यकता भी नहीं थी। इसके बजाय, अतिप्रवाह का पता चला, और जिसके कारण उड़ान निरस्त हो गई।
साइमन बी

9
But with the 10,000,000,000 repetitions, the time taken by a check is still less than 1 nanosecond.यह पाश का एक संकेत है जो बाहर अनुकूलित किया जा रहा है। इसके अलावा वह वाक्य पिछली संख्याओं का खंडन करता है जो मेरे लिए बहुत मान्य हैं।
usr

जवाबों:


86

इसके 3 कारण हैं:

  1. रन-टाइम में ओवरफ्लो (हर एक अंकगणितीय ऑपरेशन के लिए) की जाँच की लागत अत्यधिक है।

  2. यह साबित करने की जटिलता है कि संकलन-समय पर एक अतिप्रवाह चेक को छोड़ा जा सकता है।

  3. कुछ मामलों में (जैसे सीआरसी गणना, बड़ी संख्या में पुस्तकालय, आदि) "ओवरफ्लो पर लपेट" प्रोग्रामर के लिए अधिक सुविधाजनक है।


10
@DmitryGrigoryev unsigned intको ध्यान में नहीं आना चाहिए क्योंकि ओवरफ्लो चेकिंग वाली भाषा को डिफ़ॉल्ट रूप से सभी पूर्णांक प्रकारों की जांच करनी चाहिए । आपको लिखना होगा wrapping unsigned int
इमिबिज़

32
मैं लागत तर्क नहीं खरीदता। सीपीयू हर पल पूर्णांक गणना पर अतिप्रवाह की जांच करता है और ALU में कैरी फ्लैग सेट करता है। यह प्रोग्रामिंग भाषा का समर्थन है जो गायब है। यदि आप इसका उपयोग नहीं करते हैं तो एक साधारण didOverflow()इनलाइन फ़ंक्शन या यहां तक ​​कि एक वैश्विक चर __carryजो कैरी फ़्लैग तक पहुंच की अनुमति देता है।
स्लीबटमैन

37
@ स्लेबेटमैन: यह x86 है। एआरएम नहीं करता है। जैसे ADDकैरी सेट नहीं है (आपको ज़रूरत है ADDS)। Itanium के पास कैरी फ़्लैग भी नहीं है । और x86 पर भी, AVX के पास झंडे नहीं हैं।
MSalters

30
@slebetman यह कैरी फ्लैग सेट करता है, हां (x86 पर, माइंड यू)। लेकिन फिर आपको कैरी फ्लैग को पढ़ना होगा और परिणाम पर फैसला करना होगा - यह महंगा हिस्सा है। चूँकि अंकगणित संचालन अक्सर छोरों (और उस पर तंग छोरों) में उपयोग किया जाता है, यह आसानी से कई सुरक्षित संकलक अनुकूलन को रोक सकता है जो प्रदर्शन पर बहुत बड़ा प्रभाव डाल सकता है, भले ही आपको केवल एक अतिरिक्त निर्देश की आवश्यकता हो (और आपको इससे कहीं अधिक की आवश्यकता है )। क्या इसका मतलब यह डिफ़ॉल्ट होना चाहिए? हो सकता है, विशेष रूप से सी # जैसी भाषा में, जहां कहना uncheckedकाफी आसान है; लेकिन आप कितनी बार अतिप्रवाह मामलों overestimating हो सकता है।
लुआण

12
ARM की addsकीमत उसी तरह है add(यह सिर्फ एक निर्देश 1-बिट फ्लैग है जो चयन करता है कि कैरी फ्लैग अपडेट है या नहीं)। MIPS के addअनुदेश जाल पर अतिप्रवाह - आपको इसके बजाय का उपयोग करके अतिप्रवाह पर नहीं फंसने के लिए कहना है addu!
इमिबिज़

65

कौन कहता है कि यह एक बुरा व्यापार है ?!

मैं अपने सभी प्रोडक्शन ऐप्स को ओवरफ्लो चेकिंग सक्षम के साथ चलाता हूं। यह C # कंपाइलर ऑप्शन है। मैंने वास्तव में इसे बेंचमार्क किया और मैं अंतर को निर्धारित करने में सक्षम नहीं था। HTML (गैर-खिलौना) उत्पन्न करने के लिए डेटाबेस तक पहुँचने की लागत ओवरफ्लो जाँच की लागतों की देखरेख करती है।

मैं इस तथ्य की सराहना करता हूं कि मुझे पता है कि कोई भी संचालन उत्पादन में अतिप्रवाह नहीं करता है। लगभग सभी कोड ओवरफ्लो की उपस्थिति में गलत व्यवहार करेंगे। कीड़े सौम्य नहीं होंगे। डेटा भ्रष्टाचार की संभावना है, सुरक्षा एक संभावना जारी करती है।

मामले में मुझे प्रदर्शन की आवश्यकता होती है, जो कभी-कभी होता है, मैं unchecked {}एक दानेदार आधार का उपयोग करके अतिप्रवाह जाँच को अक्षम करता हूं । जब मुझे कॉल करना होता है कि मैं एक ऑपरेशन पर भरोसा करता हूं, तो मैं checked {}उस तथ्य को दस्तावेज करने के लिए कोड को अतिरेक से नहीं जोड़ सकता हूं । मैं ओवरफ्लो का मन बना रहा हूं, लेकिन मुझे जांच करने के लिए धन्यवाद करने की आवश्यकता नहीं है।

मेरा मानना ​​है कि सी # टीम ने गलत चुनाव किया जब उन्होंने डिफ़ॉल्ट रूप से अतिप्रवाह की जांच नहीं करने का फैसला किया , लेकिन मजबूत संगतता चिंताओं के कारण यह विकल्प अब सील कर दिया गया है। ध्यान दें, यह विकल्प वर्ष 2000 के आसपास बनाया गया था। हार्डवेयर कम सक्षम था और .NET के पास अभी बहुत अधिक कर्षण नहीं था। शायद .NET इस तरह से जावा और C / C ++ प्रोग्रामर से अपील करना चाहता था। .NET का मतलब धातु के करीब होना भी है। यही कारण है कि इसमें असुरक्षित कोड, संरचना और महान देशी कॉल क्षमताएं हैं, जिनमें से सभी में जावा नहीं है।

जितनी तेज़ी से हमारा हार्डवेयर मिलता है और होशियार आउट कंपाइलरों को डिफ़ॉल्ट रूप से अधिक आकर्षक ओवरफ़्लो जाँच मिलती है।

मेरा यह भी मानना ​​है कि अतिप्रवाह जाँच प्रायः असीम आकार की संख्याओं से बेहतर है। असीम रूप से आकार की संख्या में एक प्रदर्शन लागत होती है जो कि अधिक होती है, अनुकूलन के लिए कठिन होती है (मुझे विश्वास है) और वे अनबाउंड संसाधन खपत की संभावना को खोलते हैं।

ओवरफ्लो से निपटने का जावास्क्रिप्ट का तरीका और भी खराब है। जावास्क्रिप्ट संख्या फ्लोटिंग पॉइंट डबल्स हैं। एक "अतिप्रवाह" पूर्णांक के पूर्ण सटीक सेट को छोड़ने के रूप में खुद को प्रकट करता है। थोड़े गलत परिणाम आएंगे (जैसे एक-एक करके बंद होना - यह परिमित छोरों को अनंत में बदल सकता है)।

कुछ भाषाओं के लिए जैसे कि डिफ़ॉल्ट रूप से C / C ++ ओवरफ़्लो जाँच स्पष्ट रूप से अनुचित है क्योंकि इन भाषाओं में लिखे जाने वाले अनुप्रयोगों के प्रकारों को नंगे प्रदर्शन की आवश्यकता होती है। फिर भी, C / C ++ को सुरक्षित मोड में चुनने की अनुमति देकर सुरक्षित भाषा में बनाने का प्रयास किया जाता है। यह 90-99% कोड ठंडा होने के बाद से सराहनीय है। एक उदाहरण fwrapvसंकलक विकल्प है जो 2 के पूरक को लपेटने के लिए मजबूर करता है। यह संकलक द्वारा "कार्यान्वयन की गुणवत्ता" सुविधा है, भाषा द्वारा नहीं।

हास्केल का कोई तार्किक कॉल स्टैक नहीं है और न ही कोई मूल्यांकन मूल्यांकन आदेश है। यह अप्रत्याशित बिंदुओं पर अपवाद होता है। में a + bयह है कि क्या अनिर्दिष्ट है aया bपहले मूल्यांकन किया जाता है और उन भाव सब या नहीं पर समाप्त या नहीं। इसलिए, हास्केल के लिए ज्यादातर समय अनबाउंड पूर्णांक का उपयोग करना समझ में आता है। यह विकल्प विशुद्ध रूप से कार्यात्मक भाषा के लिए उपयुक्त है क्योंकि अपवाद वास्तव में अधिकांश हास्केल कोड में अनुचित हैं। और शून्य से विभाजन वास्तव में हास्कल्स भाषा डिजाइन में एक समस्याग्रस्त बिंदु है। अनबाउंड पूर्णांकों के बजाय वे निश्चित-चौड़ाई वाले रैपिंग पूर्णांकों का उपयोग कर सकते थे, लेकिन यह "सुविधाओं पर ध्यान केंद्रित" विषय के साथ फिट नहीं होता है जो कि भाषा सुविधाएँ।

अतिप्रवाह अपवादों का एक विकल्प जहर मूल्य हैं जो अपरिभाषित संचालन द्वारा बनाए जाते हैं और संचालन के माध्यम से प्रचार करते हैं (जैसे फ्लोट NaNमूल्य)। यह अतिप्रवाह जाँच की तुलना में कहीं अधिक महंगा लगता है और सभी ऑपरेशनों को धीमा कर देता है, न कि केवल वे ही विफल हो सकते हैं (हार्डवेयर त्वरण को रोकना जो आमतौर पर तैरता है और आम तौर पर इन्टस नहीं होता है - हालांकि इटेनियम में NaT है जो "Not a Thing" है )। मैं यह भी नहीं देख रहा हूँ कि प्रोग्राम को खराब डेटा के साथ-साथ सीमित करना जारी है। यह पसंद है ON ERROR RESUME NEXT। यह त्रुटियों को छुपाता है लेकिन सही परिणाम प्राप्त करने में मदद नहीं करता है। सुपरकैट बताता है कि ऐसा करने के लिए यह कभी-कभी एक प्रदर्शन अनुकूलन है।


2
बहुत बढ़िया जवाब। तो इस बारे में आपका सिद्धांत क्या है कि उन्होंने ऐसा करने का फैसला क्यों किया? बस हर कोई नकल कर रहा है जिसने C और अंततः असेंबली और बाइनरी की नकल की?
jpmc26

19
जब आपके उपयोगकर्ता आधार का 99% एक व्यवहार की उम्मीद करता है, तो आप उन्हें देने के लिए करते हैं। और "नकल सी" के रूप में, यह वास्तव में सी की नकल नहीं है, लेकिन इसका एक विस्तार है। सी unsignedकेवल पूर्णांकों के लिए अपवाद मुक्त व्यवहार की गारंटी देता है । हस्ताक्षरित पूर्णांक अतिप्रवाह का व्यवहार वास्तव में C और C ++ में अपरिभाषित व्यवहार है। हां, अपरिभाषित व्यवहार । यह सिर्फ इतना होता है कि लगभग सभी इसे 2 के पूरक अतिप्रवाह के रूप में लागू करते हैं। सी # वास्तव में इसे आधिकारिक बनाता है, बजाय यूबी को छोड़ने के बजाय सी / सी ++
कॉर्ट अमोन

10
@CortAmmon: डिज़ाइन की गई भाषा डेनिस रिची ने हस्ताक्षर किए गए पूर्णांकों के लिए रैपराउंड व्यवहार को परिभाषित किया था, लेकिन गैर-दो-पूरक प्लेटफार्मों पर उपयोग के लिए वास्तव में उपयुक्त नहीं था। सटीक दो के पूरक विचलन से कुछ विचलन की अनुमति देते समय बहुत कुछ अनुकूलन की सहायता कर सकते हैं (जैसे कि एक संकलक को x * y / y को x के साथ गुणा करने से एक गुणन और एक विभाजन को बचाने की अनुमति मिल सकती है), संकलक लेखकों ने अनिर्धारित व्यवहार की व्याख्या एक अवसर के रूप में नहीं की है। किसी दिए गए लक्ष्य प्लेटफ़ॉर्म और अनुप्रयोग फ़ील्ड के लिए क्या मायने रखता है, बल्कि खिड़की को समझ से बाहर फेंकने के अवसर के रूप में।
सुपरकैट

3
@CortAmmon - द्वारा बनाया गया कोड की जाँच करें gcc -O2के लिए x + 1 > x(जहां xएक है int)। इसके अलावा gcc.gnu.org/onbuildocs/gcc-6.3.0/gcc/… देखें । सी में हस्ताक्षर किए गए अतिप्रवाह पर 2s-पूरक व्यवहार वैकल्पिक है , यहां तक ​​कि वास्तविक संकलक में भी, और gccसामान्य अनुकूलन स्तरों में इसे अनदेखा करने के लिए चूक।
जोनाथन

2
@supercat हाँ, अधिकांश सी संकलक लेखक यह सुनिश्चित करने में अधिक रुचि रखते हैं कि कुछ अवास्तविक बेंचमार्क प्रोग्रामर को उचित शब्दार्थ प्रदान करने की तुलना में 0.5% तेज़ी से चलता है (हाँ मैं समझता हूँ कि इसे हल करना आसान समस्या क्यों नहीं है और कुछ उचित मूल्यांकन हैं जो पैदा कर सकते हैं अप्रत्याशित परिणाम जब संयुक्त, यादा, यादा, लेकिन फिर भी यह सिर्फ फोकस नहीं है और यदि आप वार्तालापों का पालन करते हैं तो आप इसे नोटिस करते हैं)। सौभाग्य से कुछ लोग हैं जो बेहतर करने की कोशिश करते हैं
Voo

30

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


28
यह किसी तरह कह रहा है कि बफर ओवरफ्लो के लिए चेक को छोड़ दिया जाना चाहिए क्योंकि वे शायद ही कभी होते हैं ...
बर्नहार्ड हिलेर

73
@BernhardHiller: और यही C और C ++ करते हैं।
माइकल बोर्गवर्ड्ट

12
@ डैडीब्रोर्न: जैसा कि अंकगणित की अधिकता है। पूर्व हालांकि VM से समझौता नहीं करता है।
डिडुप्लिकेटर

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

7
@svick अंकगणित संचालन संभवतः सरणी अनुक्रमण संचालन की तुलना में कहीं अधिक सामान्य हैं। और अधिकांश पूर्णांक आकार काफी बड़े होते हैं जो कि बहुत अधिक दुर्लभ होते हैं जो अंकगणित करते हैं। तो लागत-लाभ अनुपात बहुत अलग हैं।
बरमार

20

इस तरह के खतरनाक व्यवहार के पीछे डिजाइन के फैसले क्या हैं?

"उपयोगकर्ताओं को एक ऐसी सुविधा के लिए प्रदर्शन जुर्माना देने के लिए मजबूर न करें जिसकी उन्हें आवश्यकता नहीं है।"

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

नई भाषाएँ कई अन्य विशेषताओं के लिए इस दृष्टिकोण से टूटती हैं, जैसे कि सरणी सीमा जाँच। मुझे यकीन नहीं है कि उन्होंने इसे ओवरफ्लो जाँच के लिए क्यों नहीं किया; यह केवल एक निरीक्षण हो सकता है।


18
यह निश्चित रूप से सी # के डिजाइन में एक निरीक्षण नहीं है। C # के डिज़ाइनरों ने जानबूझकर दो मोड बनाए: checkedऔर unchecked, स्थानीय स्तर पर उनके बीच स्विच करने के लिए सिंटैक्स जोड़ा और इसे विश्व स्तर पर बदलने के लिए लाइन स्विच (और वीएस में प्रोजेक्ट सेटिंग्स) को भी जोड़ा। आप uncheckedडिफ़ॉल्ट बनाने में असहमत हो सकते हैं (मैं करता हूं), लेकिन यह सब स्पष्ट रूप से बहुत जानबूझकर है।
svick

8
@slebetman - सिर्फ रिकॉर्ड के लिए: यहां की लागत अतिप्रवाह (जो कि तुच्छ है) के लिए जाँच की लागत नहीं है, लेकिन ओवरफ़्लो हुआ (जो बहुत महंगा है) के आधार पर विभिन्न कोड चलाने की लागत। सीपीयू को सशर्त शाखा के बयान पसंद नहीं हैं।
जोनाथन

5
@jcast आधुनिक प्रोसेसर पर शाखा की भविष्यवाणी लगभग सशर्त शाखा विवरण दंड को समाप्त नहीं करेगी? सभी सामान्य मामले के बाद कोई अतिप्रवाह नहीं होना चाहिए, इसलिए यह बहुत ही पूर्वानुमानित शाखाओं में बंटने वाला व्यवहार है।
कोडमोंकी

4
@CodeMonkey से सहमत हैं। एक कंपाइलर ओवरफ्लो के मामले में एक सशर्त छलांग लगाएगा, एक ऐसे पृष्ठ पर जो सामान्य रूप से लोड / ठंडा नहीं है। उसके लिए डिफ़ॉल्ट भविष्यवाणी "नहीं ली गई" है, और यह शायद नहीं बदलेगी। कुल ओवरहेड पाइप लाइन में एक निर्देश है। लेकिन वह एक अंकगणित प्रति अंकगणितीय अनुदेश है।
MSalters

2
@MSalters हाँ, एक अतिरिक्त निर्देश ओवरहेड है। और प्रभाव बड़ा हो सकता है यदि आपके पास विशेष रूप से सीपीयू बाध्य समस्याएं हैं। IO और CPU भारी कोड के मिश्रण के साथ अधिकांश अनुप्रयोगों में मुझे लगता है कि प्रभाव न्यूनतम है। मुझे केवल डिबग बिल्ड में ओवरहेड जोड़ने के लिए जंग रास्ता पसंद है, लेकिन इसे रिलीज बिल्ड में हटा देता है।
कोडमोंकी

20

विरासत

मैं कहूंगा कि मुद्दा विरासत में होने की संभावना है। सी में:

  • हस्ताक्षरित अतिप्रवाह अपरिभाषित व्यवहार है (कंपाइलर इसे लपेटने के लिए झंडे का समर्थन करते हैं),
  • अहस्ताक्षरित अतिप्रवाह परिभाषित व्यवहार है (यह लपेटता है)।

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

स्टेचू-क्वो की ओर जाता है

तथ्य यह है कि सी (और विस्तार सी ++) को घुमाव में अतिप्रवाह का पता लगाने की आवश्यकता नहीं है, इसका मतलब है कि अतिप्रवाह जाँच सुस्त है।

हार्डवेयर ज्यादातर C / C ++ को पूरा करता है (गंभीरता से, x86 में एक strcmpनिर्देश है (उर्फ PCMPISTRI SSE 4.2 के रूप में!), और चूंकि C परवाह नहीं करता है, आम सीपीयू ओवरफ्लो का पता लगाने के कुशल तरीके नहीं पेश करते हैं। X86 में, आपको प्रत्येक संभावित अतिप्रवाह ऑपरेशन के बाद प्रति-कोर ध्वज की जांच करनी होगी; जब आप वास्तव में चाहते हैं, तो परिणाम पर "दागी" झंडा है (NaN प्रचार की तरह)। और वेक्टर ऑपरेशन और भी अधिक समस्याग्रस्त हो सकते हैं। कुछ नए खिलाड़ी कुशल ओवरफ्लो हैंडलिंग के साथ बाजार में दिखाई दे सकते हैं; लेकिन अब x86 और ARM की परवाह नहीं है।

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

कैस्केडिंग प्रभाव के साथ

इसलिए, कुशल अनुकूलन रणनीतियों और कुशल सीपीयू समर्थन की अनुपस्थिति में, अतिप्रवाह-जाँच महंगा है। लपेटने की तुलना में बहुत अधिक महंगा।

कुछ कष्टप्रद व्यवहार में जोड़ें, जैसे कि x + y - 1अतिप्रवाह x - 1 + y, जो वैध रूप से नाराज उपयोगकर्ताओं को नहीं कर सकता है, और अतिप्रवाह-चेकिंग को आमतौर पर रैपिंग के पक्ष में छोड़ दिया जाता है (जो इस उदाहरण को और कई अन्य लोगों को इनायत से संभालता है)।

फिर भी, सभी आशा खो नहीं है

"सैनिटाइज़र" को लागू करने के लिए क्लैंग और जीसीसी संकलक में एक प्रयास किया गया है: अनिर्धारित व्यवहार के मामलों का पता लगाने के लिए बायनेरिज़ को साधन करने के तरीके। उपयोग करते समय -fsanitize=undefined, हस्ताक्षरित अतिप्रवाह का पता लगाया जाता है और कार्यक्रम को रद्द कर देता है; परीक्षण के दौरान बहुत उपयोगी है।

जंग प्रोग्रामिंग भाषा अतिप्रवाह-चेकिंग सक्षम किया गया है डिफ़ॉल्ट रूप से डीबग मोड में (यह प्रदर्शन कारणों से रिलीज मोड में अंकगणित लपेटकर का उपयोग करता है)।

इसलिए, अतिप्रवाह-जाँच के बारे में चिंता बढ़ रही है और फर्जी परिणामों के खतरे कम हो रहे हैं, और उम्मीद है कि इससे अनुसंधान समुदाय, संकलक समुदाय और हार्डवेयर समुदाय में रुचि बढ़ेगी।


6
@DmitryGrigoryev जो ओवरफ्लो की जाँच करने के लिए एक प्रभावी तरीके के विपरीत है, उदाहरण के लिए हैसवेल पर यह प्रति चक्र 4 सामान्य परिवर्धन से केवल 1 चेक किए गए जोड़ को कम कर देता है, और यह शाखा के प्रभाव से पहले विचार करने से पहले है jo, और प्रदूषण का अधिक वैश्विक प्रभाव वे शाखा भविष्यवक्ता और बढ़े हुए कोड आकार में जोड़ते हैं। यदि वह झंडा चिपचिपा था तो यह कुछ वास्तविक क्षमता की पेशकश करेगा .. और फिर आप इसे वेक्टर कोड में ठीक से नहीं कर सकते।

3
चूंकि आप जॉन रेगर द्वारा लिखित एक ब्लॉग पोस्ट से लिंक कर रहे हैं , मैंने सोचा कि आपके लिंक से कुछ महीने पहले लिखे गए उनके लेख के किसी अन्य लिंक से लिंक करना भी उचित होगा । ये लेख विभिन्न दर्शन के बारे में बात करते हैं: पहले के लेख में, पूर्णांक निश्चित आकार के होते हैं; पूर्णांक अंकगणित की जाँच की जाती है (अर्थात कोड इसके निष्पादन को जारी नहीं रख सकता है); एक अपवाद या एक जाल है। नए लेख में निश्चित आकार के पूर्णांकों को खोदने की बात की गई है, जो ओवरफ्लो को समाप्त करता है।
17'17

2
@rwong अनंत-आकार के पूर्णांकों में भी उनकी समस्याएं हैं। यदि आपका अतिप्रवाह बग का परिणाम है (जो अक्सर होता है), तो यह एक त्वरित दुर्घटना को एक लंबे समय तक पीड़ा में बदल सकता है जो सभी सर्वर संसाधनों का उपभोग करता है जब तक कि सब कुछ बुरी तरह से विफल न हो जाए। मैं ज्यादातर "जल्दी असफल" दृष्टिकोण का प्रशंसक हूं - पूरे पर्यावरण को जहर देने की कम संभावना। मैं 1..100इसके बजाय पास्कल-ईश प्रकारों को पसंद करूंगा - 2 ^ 31 आदि में "मजबूर" होने के बजाय अपेक्षित सीमाओं के बारे में स्पष्ट हो। कुछ भाषाएँ निश्चित रूप से इसकी पेशकश करती हैं, और वे डिफ़ॉल्ट रूप से (कभी-कभी) ओवरफ्लो जाँच करते हैं संकलन-समय, यहां तक ​​कि)।
लुआण

1
@ लालन: जो दिलचस्प है वह यह है कि कई बार मध्यवर्ती संगणना अस्थायी रूप से ओवरफ्लो हो सकती है, लेकिन परिणाम नहीं होता है। उदाहरण के लिए, आपकी १.१०० की सीमा पर, x * 2 - 2जब xपरिणाम ५१ होता है , तब भी ओवरफ्लो हो सकता है , जब आप अपनी गणना (कभी-कभी अप्राकृतिक तरीके से) को पुनर्व्यवस्थित करने के लिए मजबूर करते हैं। अपने अनुभव में, मैंने पाया है कि मैं आम तौर पर गणना को बड़े प्रकार में चलाना पसंद करता हूं, और फिर जांचता हूं कि परिणाम फिट बैठता है या नहीं।
मैथ्यू एम।

1
@MatthieuM। हाँ, यह वह जगह है जहाँ आप "पर्याप्त रूप से स्मार्ट कंपाइलर" क्षेत्र में आते हैं। आदर्श रूप से, 103 का मान 1..100 प्रकार के लिए मान्य होना चाहिए, जब तक कि इसका उपयोग कभी भी उस संदर्भ में न किया जाए जहां एक सच्चा 1..100 अपेक्षित है (जैसे x = x * 2 - 2सभी के लिए काम करना चाहिए xजहां एक मान्य 1 में असाइनमेंट का परिणाम होता है। .100 नंबर)। यही है, जब तक असाइनमेंट फिट बैठता है, तब तक न्यूमेरिक प्रकार के संचालन में टाइप की तुलना में अधिक सटीकता हो सकती है। यह उन मामलों में काफी उपयोगी होगा जैसे (a + b) / 2अनदेखी (अहस्ताक्षरित) ओवरफ्लो सही विकल्प हो सकता है।
लुआण

10

जो भाषाएं ओवरफ्लो का पता लगाने का प्रयास करती हैं, उन्होंने ऐतिहासिक रूप से संबंधित शब्दार्थों को परिभाषित किया है जो गंभीर रूप से प्रतिबंधित हैं अन्यथा उपयोगी अनुकूलन हो सकते हैं। अन्य बातों के अलावा, जबकि यह अक्सर कोड में निर्दिष्ट एक अलग अनुक्रम में संगणना करने के लिए उपयोगी होगा, ज्यादातर भाषाएं जो जाल ओवरफ्लो की गारंटी देती हैं, जैसे कि दिए गए कोड:

for (int i=0; i<100; i++)
{
  Operation1();
  x+=i;
  Operation2();
}

यदि x का आरंभिक मान लूप के माध्यम से 47 वीं पास पर अतिप्रवाह का कारण होगा, तो ऑपरेशन 1 47 बार निष्पादित होगा और ऑपरेशन 2 46 निष्पादित करेगा। ऐसी गारंटी के अभाव में, यदि लूप के भीतर और कुछ भी x का उपयोग नहीं करता है, और कुछ भी नहीं। ऑपरेशन 1 या ऑपरेशन 2 द्वारा फेंके गए अपवाद के बाद x के मूल्य का उपयोग करेगा, कोड को इसके साथ बदला जा सकता है:

x+=4950;
for (int i=0; i<100; i++)
{
  Operation1();
  Operation2();
}

दुर्भाग्यवश, ऐसे मामलों में सही शब्दार्थ की गारंटी देते हुए ऐसे अनुकूलन करना जहां लूप के भीतर एक अतिप्रवाह होता है मुश्किल है - अनिवार्य रूप से कुछ की आवश्यकता होती है जैसे:

if (x < INT_MAX-4950)
{
  x+=4950;
  for (int i=0; i<100; i++)
  {
    Operation1();
    Operation2();
  }
}
else
{
  for (int i=0; i<100; i++)
  {
    Operation1();
    x+=i;
    Operation2();
  }
}

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

अतिप्रवाह का पता लगाने के लिए क्या करने की आवश्यकता होगी सस्ती सस्ती ओवरफ्लो का पता लगाने वाले शब्दार्थ का एक निर्धारित सेट होगा, जो कोड के लिए यह रिपोर्ट करना आसान बना देगा कि क्या किसी भी ओवरफ्लो के बिना एक संगणना का प्रदर्शन किया गया था जो परिणाम (*) को प्रभावित कर सकता है, लेकिन बिना बोझ के। उस से परे विवरण के साथ संकलक। यदि उपरोक्त को प्राप्त करने के लिए आवश्यक न्यूनतम करने के लिए अतिप्रवाह पहचान की लागत को कम करने के लिए एक भाषा कल्पना पर ध्यान केंद्रित किया गया था, तो इसे मौजूदा भाषाओं की तुलना में बहुत कम महंगा बनाया जा सकता है। मैं कुशल अतिप्रवाह पहचान की सुविधा के लिए किसी भी प्रयास से अनजान हूँ, हालाँकि।

(*) यदि कोई भाषा वादा करती है कि सभी ओवरफ्लो की सूचना दी जाएगी, तो एक अभिव्यक्ति x*y/yको सरलीकृत नहीं किया जा सकता xजब तक कि x*yअतिप्रवाह की गारंटी नहीं दी जा सकती। इसी तरह, भले ही गणना के परिणाम को नजरअंदाज कर दिया जाएगा, एक भाषा जो सभी ओवरफ्लो की रिपोर्ट करने का वादा करती है, उसे वैसे भी प्रदर्शन करने की आवश्यकता होगी ताकि यह अतिप्रवाह जांच कर सके। चूँकि ऐसे मामलों में अतिप्रवाह का परिणाम अंकगणित-गलत व्यवहार के रूप में सामने नहीं आ सकता है, इस बात की गारंटी के लिए किसी प्रोग्राम को ऐसी जाँच करने की आवश्यकता नहीं होगी कि कोई भी ओवरफ्लो संभावित रूप से गलत परिणाम का कारण न बने।

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

#include <stdint.h>
uint32_t test(uint16_t x, uint16_t y) { return x*y & 65535u; }
uint32_t test2(uint16_t q, int *p)
{
  uint32_t total=0;
  q|=32768;
  for (int i = 32768; i<=q; i++)
  {
    total+=test(i,65535);
    *p+=1;
  }
  return total;
}

जीसीसी टेस्ट 2 के लिए कोड उत्पन्न करेगा जो बिना शर्त वृद्धि (* पी) एक बार करता है और क्यू में पारित मूल्य की परवाह किए बिना 32768 लौटाता है। इसके तर्क से, (32769 * 65535) और 65535u की गणना अतिप्रवाह का कारण बनेगी और इस प्रकार संकलक को किसी भी मामले पर विचार करने की कोई आवश्यकता नहीं है, जहां (q। 32768) 32768 से बड़ा मान प्राप्त करेगा। हालांकि कोई भी नहीं है। कारण यह है कि (32769 * 65535) और 65535u की गणना परिणाम के ऊपरी बिट्स की परवाह करना चाहिए, जीसीसी लूप की अनदेखी के औचित्य के रूप में हस्ताक्षरित अतिप्रवाह का उपयोग करेगा।


2
"यह आधुनिक संकलक के लिए फैशनेबल है ..." - इसी तरह, यह कुछ प्रसिद्ध गुठली के डेवलपर्स के लिए संक्षिप्त रूप से फैशनेबल था जो वे उपयोग किए गए अनुकूलन झंडे के बारे में दस्तावेज़ीकरण नहीं पढ़ते हैं, और फिर पूरे इंटरनेट पर गुस्सा करते हैं। क्योंकि वे व्यवहार को पाने के लिए और अधिक संकलक झंडे जोड़ने के लिए मजबूर थे; ;-)। इस मामले में, -fwrapvपरिभाषित व्यवहार में परिणाम, प्रश्नकर्ता के व्यवहार को नहीं चाहता है। दी, gcc अनुकूलन मानक और संकलक व्यवहार पर गहन परीक्षा में किसी भी प्रकार के C विकास को बदल देता है।
स्टीव जेसप

1
@SteveJessop: C एक बहुत ही स्वस्थ भाषा होगी यदि कंपाइलर लेखकों ने निम्न-स्तरीय बोली को मान्यता दी जहाँ "अपरिभाषित व्यवहार" का अर्थ "अंतर्निहित प्लेटफ़ॉर्म पर कुछ भी करना होगा", और फिर प्रोग्रामर के लिए अनावश्यक गारंटियों को माफ करने के तरीकों को जोड़ा। यह मानने के बजाय कि मानक में "गैर-पोर्टेबल या गलत" वाक्यांश का अर्थ "गलत" है। कई मामलों में, कमजोर व्यवहार की गारंटी के साथ एक भाषा में प्राप्त किया जा सकने वाला इष्टतम कोड, मजबूत गारंटी के साथ प्राप्त किया जा सकता है या कोई गारंटी नहीं है। उदाहरण के लिए ...
सुपरकैट

1
... अगर किसी प्रोग्रामर को x+y > zऐसे फैशन में मूल्यांकन करने की ज़रूरत है जो उपज 0 या उपज 1 के अलावा कुछ भी नहीं करेगा, लेकिन या तो परिणाम अतिप्रवाह के मामले में समान रूप से स्वीकार्य होगा, एक संकलक जो यह गारंटी देता है कि अक्सर बेहतर कोड उत्पन्न कर सकता है। x+y > zकिसी भी संकलक की तुलना में अभिव्यक्ति की रक्षात्मक रूप से लिखित संस्करण के लिए उत्पन्न करने में सक्षम होगा। वास्तविक रूप से बोलते हुए, उपयोगी अतिप्रवाह से संबंधित अनुकूलन का कौन सा अंश एक गारंटी से अलग होगा जो विभाजन / शेष के अलावा पूर्णांक गणना बिना किसी दुष्प्रभाव के निष्पादित करेगा?
सुपरकैट

मैं स्वीकार करता हूं कि मैं पूरी तरह से विवरण में नहीं हूं, लेकिन यह तथ्य कि आपकी शिकायत सामान्य रूप से "संकलक लेखकों" के साथ है, न कि विशेष रूप से "कोई व्यक्ति जो मेरे -fwhatever-makes-senseपैच स्वीकार नहीं करेगा ", दृढ़ता से मुझे सुझाव देता है कि और भी बहुत कुछ है यह उनकी ओर से सनकी की तुलना में। मैंने जो सामान्य तर्क सुने हैं, वे हैं कोड कोड इनलाइनिंग (और यहां तक ​​कि मैक्रो विस्तार) कोड निर्माण के विशिष्ट उपयोग के बारे में जितना संभव हो सके कटौती करने से लाभ होता है, क्योंकि आमतौर पर कोई भी चीज सम्मिलित कोड में आमतौर पर परिणाम होती है जो उन मामलों से संबंधित है जिनकी आवश्यकता नहीं है , कि आसपास का कोड "असंभव" साबित होता है।
स्टीव जेसप

इसलिए एक सरलीकृत उदाहरण के लिए, अगर मैं लिखता हूं foo(i + INT_MAX + 1), संकलक-लेखक इनलेटेड foo()कोड में अनुकूलन लागू करने के इच्छुक हैं, जो इसके तर्क के गैर-नकारात्मक होने की शुद्धता पर भरोसा करते हैं (पैशाचिक दिवमोद चाल, शायद)। आपके अतिरिक्त प्रतिबंधों के तहत, वे केवल उन आशाओं को लागू कर सकते हैं जिनके नकारात्मक आदानों के लिए व्यवहार मंच के लिए समझ में आता है। बेशक, व्यक्तिगत रूप से मैं इसके लिए खुश -fहोऊंगा कि एक विकल्प हो जो -fwrapvआदि पर स्विच करता है , और संभवत: कुछ ऑप्टिमाइज़ेशन को अक्षम करना होगा जिसमें कोई ध्वज नहीं है। लेकिन ऐसा नहीं है कि मुझे वह सब काम करने के लिए परेशान किया जा सकता है जो मैं खुद करता हूं।
स्टीव जेसोप

9

नहीं सभी प्रोग्रामिंग भाषाओं पूर्णांक overflows की उपेक्षा। कुछ भाषाएँ पुस्तकालयों के माध्यम से सभी नंबरों (अधिकांश लिस्प बोलियों, रूबी, स्मॉलटाक, ...) और अन्य के लिए सुरक्षित पूर्णांक संचालन प्रदान करती हैं - उदाहरण के लिए C ++ के लिए विभिन्न बिगआईंट कक्षाएं हैं।

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


ध्यान दें कि अतिप्रवाह का पता लगाने के बीच एक अंतर है (और फिर एक संकेत, आतंक, अपवाद, ...) और बड़े अंकों पर स्विच करना है। पूर्व को उत्तरार्द्ध की तुलना में सस्ते में अधिक योग्य होना चाहिए।
मैथ्यू एम।

@MatthieuM। बिल्कुल - और मुझे एहसास है कि मैं अपने जवाब में इस बारे में स्पष्ट नहीं हूं।
नेमेनजा ट्रिफ़ुनोविक

7

जैसा कि आपने दिखाया है, C # 3 गुना धीमा होता अगर इसमें डिफ़ॉल्ट रूप से ओवरफ्लो चेक सक्षम होता (आपका उदाहरण उस भाषा के लिए एक विशिष्ट एप्लिकेशन है)। मैं मानता हूं कि प्रदर्शन हमेशा सबसे महत्वपूर्ण विशेषता नहीं है, लेकिन भाषाओं / संकलक की तुलना आमतौर पर विशिष्ट कार्यों में उनके प्रदर्शन पर की जाती है। यह इस तथ्य के कारण है कि भाषा सुविधाओं की गुणवत्ता कुछ व्यक्तिपरक है, जबकि एक प्रदर्शन परीक्षण उद्देश्य है।

यदि आप एक नई भाषा का परिचय देते हैं जो ज्यादातर पहलुओं में C # के समान है, लेकिन 3 गुना धीमी है, तो बाजार में हिस्सेदारी प्राप्त करना आसान नहीं होगा, भले ही अंत में आपके अधिकांश उपयोगकर्ता ओवरफ्लो चेक से अधिक लाभान्वित हों। उच्च प्रदर्शन से।


10
यह विशेष रूप से C # के लिए मामला था, जो जावा और C ++ की तुलना में अपने शुरुआती दिनों में था, न कि डेवलपर उत्पादकता मेट्रिक्स पर, जो कि मापना मुश्किल है, या कैश-सेव-से-नॉट-डील-विथ-सिक्योरिटी-ब्रीच मेट्रिक्स पर। जिसे मापना कठिन है, लेकिन तुच्छ प्रदर्शन बेंचमार्क पर।
एरिक लिपर्ट

1
और संभावना है, सीपीयू के प्रदर्शन को कुछ सरल संख्या क्रंचिंग के साथ जांचा जाता है। इस प्रकार अतिप्रवाह का पता लगाने के लिए अनुकूलन उन परीक्षणों पर "खराब" परिणाम दे सकते हैं। 22 कैच।
बर्नहार्ड हिलर

5

प्रदर्शन के आधार पर अतिप्रवाह जाँच की कमी को सही ठहराने वाले कई उत्तरों से परे, विचार करने के लिए दो अलग-अलग प्रकार के अंकगणित हैं:

  1. अनुक्रमण गणना (सरणी अनुक्रमण और / या अंकगणित अंकगणित)

  2. अन्य अंकगणित

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

इस प्रकार, आवंटित किए गए डेटा संरचनाओं को शामिल करने वाले सूचक अंकगणितीय और अनुक्रमणिक अभिव्यक्तियों के साथ काम करते समय मेमोरी आवंटन की जाँच करना पर्याप्त है। उदाहरण के लिए, यदि आपके पास 32-बिट पता स्थान है, और 32-बिट पूर्णांक का उपयोग करते हैं, और अधिकतम 2GB हीप को आवंटित (लगभग आधा पता स्थान), अनुक्रमण / सूचक गणना (मूल रूप से) अतिप्रवाह नहीं होने देंगे।

इसके अलावा, आप आश्चर्यचकित हो सकते हैं कि इसके अलावा / घटाव / गुणा में सरणी अनुक्रमण या सूचक गणना शामिल है, इस प्रकार यह पहली श्रेणी में आता है। ऑब्जेक्ट पॉइंटर, फ़ील्ड एक्सेस और सरणी जोड़-तोड़ अनुक्रमण संचालन हैं, और कई प्रोग्राम इन से अधिक अंकगणितीय गणना नहीं करते हैं! अनिवार्य रूप से, यह प्राथमिक कारण है कि प्रोग्राम काम करते हैं और साथ ही वे पूर्णांक ओवरफ़्लो जाँच के बिना भी करते हैं।

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

बाद के मामले में, प्रोग्रामर अक्सर वैकल्पिक डेटा प्रकारों का उपयोग करेंगे, जैसे कि doubleया कुछ BigInt। कई गणनाओं के decimalबजाय डेटा प्रकार की आवश्यकता होती है double, जैसे वित्तीय गणना। यदि वे पूर्णांक प्रकारों के साथ नहीं चिपके रहते हैं, तो उन्हें पूर्णांक ओवरफ़्लो की जांच करने की आवश्यकता है - या फिर, हाँ, प्रोग्राम एक पूर्व निर्धारित त्रुटि स्थिति तक पहुँच सकता है जैसा कि आप इंगित कर रहे हैं।

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


3

भाषा जंग अतिप्रवाह लगा पाएगा और न, डिबगिंग निर्माण के लिए चेक जोड़ने और उन्हें अनुकूलित रिलीज़ संस्करण में निकाल कर के बीच एक दिलचस्प समझौता प्रदान करता है। यह आपको परीक्षण के दौरान बग ढूंढने की अनुमति देता है, जबकि अभी भी अंतिम संस्करण में पूर्ण प्रदर्शन मिल रहा है।

क्योंकि ओवरफ्लो रैपराउंड कभी-कभी व्यवहार चाहता है, ऐसे ऑपरेटरों के संस्करण भी हैं जो कभी भी अतिप्रवाह की जांच नहीं करते हैं।

आप बदलाव के लिए RFC में चुनाव के पीछे तर्क के बारे में अधिक पढ़ सकते हैं । इस ब्लॉग पोस्ट में बहुत सारी रोचक जानकारी भी है , जिसमें बग्स की एक सूची भी शामिल है जिसे इस फीचर ने पकड़ने में मदद की है।


2
जंग भी इस तरह के तरीके प्रदान करता है checked_mul, जो यह जाँचता है कि क्या अतिप्रवाह हुआ है और Noneयदि ऐसा है, तो वापस आ जाए Some। इसका उपयोग उत्पादन के साथ-साथ डिबग मोड में भी किया जा सकता है: doc.rust-lang.org/std/primitive.i32.html#examples-15
अकवाल

3

स्विफ्ट में, किसी भी पूर्णांक ओवरफ्लो को डिफ़ॉल्ट रूप से पता लगाया जाता है और प्रोग्राम को तुरंत रोक दिया जाता है। ऐसे मामलों में जहां आपको रैपराउंड व्यवहार की आवश्यकता होती है, वहाँ अलग-अलग ऑपरेटर और +, & - और * होते हैं जो इसे प्राप्त करते हैं। और ऐसे कार्य हैं जो एक ऑपरेशन करते हैं और बताते हैं कि कोई अतिप्रवाह था या नहीं।

यह देखना मजेदार है कि शुरुआती लोग Collatz अनुक्रम का मूल्यांकन करने की कोशिश करते हैं और उनका कोड क्रैश होता है :-)

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

पुनश्च। C, C ++ में, Objective-C हस्ताक्षरित पूर्णांक अंकगणितीय अतिप्रवाह अपरिभाषित व्यवहार है। इसका मतलब है कि हस्ताक्षरित पूर्णांक अतिप्रवाह के मामले में कंपाइलर जो कुछ भी करता है, वह सही है। हस्ताक्षर किए गए पूर्णांक अतिप्रवाह से निपटने के विशिष्ट तरीके इसे अनदेखा करना है, सीपीयू आपको जो भी परिणाम देता है, उसे लेने से कंपाइलर में यह धारणा बनती है कि ऐसा अतिप्रवाह कभी नहीं होगा (और उदाहरण के लिए निष्कर्ष निकाला है कि n + 1> n अतिप्रवाह के बाद से हमेशा सत्य है। ऐसा नहीं माना जाता है), और एक संभावना है कि शायद ही कभी इस्तेमाल किया जाता है अगर स्विफ्ट की तरह, अतिप्रवाह होता है, तो यह जांचना और दुर्घटना करना है।


1
मुझे कभी-कभी आश्चर्य होता है कि जो लोग C में UB- चालित पागलपन को आगे बढ़ा रहे हैं, वे चुपके से किसी और भाषा के पक्ष में इसे कमजोर करने की कोशिश कर रहे थे। यह समझ में आता है।
सुपरकैट

इलाज x+1>xके रूप में बिना शर्त सच किसी भी "अनुमान" एक संकलक सुविधाजनक के रूप में मनमाने ढंग से बड़ा प्रकार का उपयोग कर पूर्णांक भाव का मूल्यांकन करने की अनुमति दी है अगर एक्स के बारे में बनाने के (या व्यवहार करते हैं जैसे कि यह तो कर रहा है) के लिए एक संकलक की आवश्यकता नहीं होगी। अतिप्रवाह-आधारित "मान्यताओं" का एक बड़ा उदाहरण यह तय करेगा कि uint32_t mul(uint16_t x, uint16_t y) { return x*y & 65535u; }एक संकलक यह sum += mul(65535, x)तय करने के लिए उपयोग कर सकता है कि x32768 से अधिक नहीं हो सकता है [व्यवहार जो संभवतः C89 राशनले को लिखने वाले लोगों को झटका देगा, जो बताता है कि निर्णायक कारकों में से एक। ..
सुपरकैट

... को unsigned shortबढ़ावा देने signed intमें यह तथ्य था कि दो-पूरक-मूक-रैपराउंड कार्यान्वयन (यानी बहुसंख्यक सी कार्यान्वयन तब उपयोग में हैं) कोड को उसी तरह से ऊपर व्यवहार करेंगे जैसे कि unsigned shortप्रचार किया गया है intया unsigned। मानक को मूक-रैपराउंड दो के पूरक हार्डवेयर पर कार्यान्वयन की आवश्यकता नहीं थी जैसा कि ऊपर दिए गए कोड की तरह है, लेकिन मानक के लेखकों को उम्मीद है कि वे किसी भी तरह से ऐसा करेंगे।
सुपरकैट

2

दरअसल, इसका असली कारण विशुद्ध रूप से तकनीकी / ऐतिहासिक है: अधिकांश भाग के लिए सीपीयू की अनदेखी संकेत। आमतौर पर रजिस्टरों में दो पूर्णांकों को जोड़ने के लिए केवल एक ही निर्देश होता है, और सीपीयू इस बात की जरा भी परवाह नहीं करता है कि क्या आप इन दो पूर्णांकों को हस्ताक्षरित या अहस्ताक्षरित करते हैं। वही घटाव के लिए जाता है, और गुणा के लिए भी। केवल अंकगणित ऑपरेशन जिसे साइन-अवेयर होना आवश्यक है वह है विभाजन।

यह क्यों काम करता है, इसका कारण यह है कि हस्ताक्षरित पूर्णांकों का 2 पूरक प्रतिनिधित्व है जो लगभग सभी सीपीयू द्वारा उपयोग किया जाता है। उदाहरण के लिए, 4-बिट 2 के पूरक में 5 और -3 का जोड़ इस तरह दिखता है:

  0101   (5)
  1101   (-3)
(11010)  (carry)
  ----
  0010   (2)

ध्यान रखें कि कैरी-आउट बिट को फेंकने के रैप-अराउंड व्यवहार से सही हस्ताक्षरित परिणाम प्राप्त होता है। इसी तरह, CPU आमतौर पर घटाव x - yको लागू करते हैं x + ~y + 1:

  0101   (5)
  1100   (~3, binary negation!)
(11011)  (carry, we carry in a 1 bit!)
  ----
  0010   (2)

हार्डवेयर में इसके अतिरिक्त के रूप में घटाव को लागू करता है, केवल तुच्छ तरीकों से अंकगणितीय-तार्किक-इकाई (ALU) के लिए आदानों को ट्विक करता है। क्या सरल हो सकता है?

चूंकि गुणा जोड़ के अनुक्रम के अलावा और कुछ नहीं है, यह एक समान तरीके से व्यवहार करता है। 2 के पूरक प्रतिनिधित्व का उपयोग करने और अंकगणितीय संचालन से बाहर ले जाने का परिणाम सरलीकृत सरलीकृत, और सरलीकृत अनुदेश सेट है।

जाहिर है, चूंकि सी को धातु के करीब काम करने के लिए डिज़ाइन किया गया था, इसने यह ठीक उसी व्यवहार को अपनाया जो अहस्ताक्षरित अंकगणित के मानकीकृत व्यवहार के रूप में है, जिससे केवल हस्ताक्षर किए गए अंकगणित को अपरिभाषित व्यवहार प्राप्त करने की अनुमति मिलती है। और वह विकल्प जावा, और, जाहिर है, सी # जैसी अन्य भाषाओं के लिए किया गया।


मैं यह जवाब देने के लिए यहां आया था।
मिस्टर लिस्टर

दुर्भाग्य से, कुछ लोगों को यह धारणा अनुचित लगती है कि एक प्लेटफ़ॉर्म पर निम्न-स्तरीय C कोड लिखने वाले लोगों में यह अपेक्षा करने की धृष्टता होनी चाहिए कि ऐसे उद्देश्य के लिए उपयुक्त C कंपाइलर अतिप्रवाह के मामले में विवश फैशन का व्यवहार करेगा। व्यक्तिगत रूप से, मुझे लगता है कि कंपाइलर के लिए व्यवहार करना उचित है क्योंकि कंपाइलर की सुविधानुसार मनमाने ढंग से विस्तारित परिशुद्धता का उपयोग करके गणना की जाती है (इसलिए 32-बिट सिस्टम पर, यदि x==INT_MAX, तो x+1मनमाने ढंग से कंपाइलर के +2757483648 या -2147483648 के रूप में व्यवहार कर सकते हैं। सुविधा), लेकिन ...
सुपरकैट

कुछ लोगों को लगता है कि अगर लगते हैं xऔर yकर रहे हैं uint16_tऔर एक 32-बिट सिस्टम पर कोड की गणना करता है x*y & 65535uजब y65535, एक संकलक कि कोड मान लेना चाहिए पहुँचा जा कभी नहीं होगा जब xसे 32768. अधिक है
supercat

1

कुछ उत्तरों ने जाँच की लागत पर चर्चा की है, और आपने अपने उत्तर को इस विवाद के लिए संपादित किया है कि यह एक उचित औचित्य है। मैं उन बिंदुओं को संबोधित करने की कोशिश करूंगा।

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

लेकिन 10,000,000,000 पुनरावृत्तियों के साथ, एक चेक द्वारा लिया गया समय अभी भी 1 नैनोसेकंड से कम है।

इस तर्क के साथ कुछ चीजें गलत हैं:

  1. यह पर्यावरण विशिष्ट है। यह आमतौर पर इस तरह के विशिष्ट आंकड़ों को उद्धृत करने के लिए बहुत कम समझ में आता है, क्योंकि सभी प्रकार के वातावरण के लिए कोड लिखा जाता है जो उनके प्रदर्शन के संदर्भ में परिमाण के आदेशों के अनुसार भिन्न होता है। एक (मुझे लगता है) डेस्कटॉप मशीन पर आपका 1 नैनोसेकंड एक एम्बेडेड वातावरण के लिए किसी को कोडिंग करने के लिए आश्चर्यजनक रूप से तेज़ लग सकता है, और एक सुपर कंप्यूटर क्लस्टर के लिए कोडिंग करने के लिए किसी व्यक्ति को असहनीय रूप से धीमा कर सकता है।

  2. 1 नैनोसेकंड कोड के एक खंड के लिए कुछ भी नहीं की तरह लग सकता है जो अक्सर चलता रहता है। दूसरी ओर, यदि यह कुछ गणना के आंतरिक लूप में है जो कोड का मुख्य कार्य है, तो समय के हर एक अंश को आप दाढ़ी बना सकते हैं। यदि आप एक क्लस्टर पर एक सिमुलेशन चला रहे हैं, तो आपके आंतरिक लूप में एक नैनोसेकंड के सहेजे गए अंश सीधे हार्डवेयर और बिजली पर खर्च किए गए धन का अनुवाद कर सकते हैं।

  3. कुछ एल्गोरिदम और संदर्भों के लिए, 10,000,000,000 पुनरावृत्तियों महत्वहीन हो सकते हैं। फिर, आम तौर पर उन विशिष्ट परिदृश्यों के बारे में बात करने का कोई मतलब नहीं है जो केवल कुछ संदर्भों में लागू होते हैं।

ऐसी स्थिति हो सकती है जहां यह महत्वपूर्ण है, लेकिन अधिकांश अनुप्रयोगों के लिए, इससे कोई फर्क नहीं पड़ेगा।

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


-1

कर रहे हैं जरूरी एक बुरी बात एक पूर्णांक अतिप्रवाह के प्रभाव नहीं है, और बाद-तथ्य यह जानना आवश्यक है कि मुश्किल है: वहाँ अच्छा जवाब हैं, लेकिन मुझे लगता है कि एक चूक यहां मुद्दा यह है iकिया जा रहा से चला गया MAX_INTहोने के MIN_INTएक अतिप्रवाह समस्या की वजह से था या अगर यह जानबूझकर -1 से गुणा करके किया गया था।

उदाहरण के लिए, यदि मैं सभी प्रतिनिधित्व योग्य पूर्णांक को 0 से अधिक जोड़ना चाहता हूं, तो मैं केवल एक for(i=0;i>=0;++i){...}अतिरिक्त लूप का उपयोग करूंगा- और जब यह ओवरफ्लो होता है तो इसके अतिरिक्त रुक जाता है, जो कि लक्ष्य व्यवहार है (एक त्रुटि को फेंकने का मतलब होगा कि मुझे दरकिनार करना होगा एक मनमाना संरक्षण क्योंकि यह मानक अंकगणित में हस्तक्षेप कर रहा है)। आदिम अंकगणित को प्रतिबंधित करना बुरा व्यवहार है, क्योंकि:

  • वे हर चीज में उपयोग किए जाते हैं- आदिम गणित में एक मंदी हर कामकाज कार्यक्रम में एक मंदी है
  • यदि एक प्रोग्रामर को उनकी आवश्यकता है, तो वे हमेशा उन्हें जोड़ सकते हैं
  • यदि आप उनके पास हैं और प्रोग्रामर को उनकी आवश्यकता नहीं है (लेकिन तेज रनटाइम की आवश्यकता है), तो वे अनुकूलन के लिए उन्हें आसानी से नहीं निकाल सकते
  • यदि आप उनके पास हैं और प्रोग्रामर को उनकी ज़रूरत नहीं है (जैसे ऊपर दिए गए उदाहरण में), प्रोग्रामर दोनों रन-टाइम हिट ले रहा है (जो प्रासंगिक हो सकता है या प्रासंगिक नहीं हो सकता है), और प्रोग्रामर को अभी भी समय निकालने के लिए निवेश करने की आवश्यकता है या 'संरक्षण' के आसपास काम कर रहा है।

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

1
आप से नहीं जा सकते INT_MAXकरने के लिए INT_MIN-1 से गुणा करके।
डेविड कॉनरेड

समाधान स्पष्ट रूप से प्रोग्रामर के लिए कोड या संकलन इकाई के दिए गए ब्लॉक में चेक को बंद करने का एक तरीका प्रदान करता है।
डेविड कॉनरेड

for(i=0;i>=0;++i){...}कोड की शैली है जिसे मैं अपनी टीम में हतोत्साहित करने की कोशिश करता हूं: यह विशेष प्रभावों / दुष्प्रभावों पर निर्भर करता है और स्पष्ट रूप से व्यक्त नहीं करता है कि इसका क्या करना है। लेकिन फिर भी मैं आपके उत्तर की सराहना करता हूं क्योंकि यह एक अलग प्रोग्रामिंग प्रतिमान दिखाता है।
बर्नहार्ड हिलर

1
@ डेलियॉथ: यदि iएक 64-बिट प्रकार है, यहां तक ​​कि एक कार्यान्वयन पर भी, जो लगातार मूक-रैपराउंड दो-पूरक व्यवहार के साथ है, तो प्रति सेकंड एक अरब पुनरावृत्तियों intको चलाने के लिए , इस तरह के लूप को केवल सबसे बड़ा मूल्य खोजने की गारंटी दी जा सकती है अगर इसे चलाने की अनुमति है सैकड़ों वर्ष। उन प्रणालियों पर जो लगातार मौन-रैपराउंड व्यवहार का वादा नहीं करते हैं, इस तरह के व्यवहार की गारंटी नहीं दी जाएगी चाहे कितना भी लंबा कोड दिया जाए।
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.