मैं अहस्ताक्षरित पूर्णांक का ओवरफ़्लो कैसे पता लगा सकता हूँ?


618

मैं C ++ एक कार्यक्रम लिख रहा था के सभी समाधान खोजने के लिए एक = , जहां एक , और एक साथ सभी अंकों का उपयोग 0-9 ठीक एक बार। कार्यक्रम के मूल्यों पर फंस एक और , और यह एक अंकों की गिनती दिनचर्या पर हर बार भाग गया एक , और एक अगर अंक हालत संतुष्ट किया गया था जांच करने के लिए।

हालांकि, जब बी एक पूर्णांक सीमा को ओवरफ्लो करता है, तो संयमी समाधान उत्पन्न किया जा सकता है। मैंने इसके लिए कोड का उपयोग करके जाँच समाप्त की:

unsigned long b, c, c_test;
...
c_test=c*b;         // Possible overflow
if (c_test/b != c) {/* There has been an overflow*/}
else c=c_test;      // No overflow

क्या अतिप्रवाह के लिए परीक्षण का एक बेहतर तरीका है? मुझे पता है कि कुछ चिप्स में एक आंतरिक झंडा होता है जो ओवरफ्लो होने पर सेट किया जाता है, लेकिन मैंने कभी इसे C या C ++ के माध्यम से एक्सेस नहीं किया।


ओवरफ़्लो पर हस्ताक्षर किए जाने वाले int खबरदार सी और सी ++ में अपरिभाषित व्यवहार है , और इस प्रकार आपको वास्तव में इसे पैदा किए बिना इसका पता लगाना होगा। इसके अलावा हस्ताक्षर किए गए पहले अतिप्रवाह के लिए, C / C ++ में हस्ताक्षरित अतिप्रवाह का पता लगाना देखें ।


21
जानकारी जो इस विषय पर उपयोगी हो सकती है: Seacord द्वारा "C और C ++ में सुरक्षित कोडिंग" के अध्याय 5 - http://www.informit.com/content/images/0321335724/samplechapter/seacord_ch_5.pdf CI के लिए सुरक्षित कक्षाएँ - http : //blogs.msdn.com/david_leblanc/archive/2008/09/30/safeint-3-on-codeplex.aspx - http://www.codeplex.com/SafeInt C के लिए पुस्तकालय: - - Blogs.msdn .com / michael_howard / archiv
माइकल बूर

3
सीकोर्ड का सिक्योर कोडिंग एक बेहतरीन संसाधन है, लेकिन IntegerLib का उपयोग न करें। देखें blog.regehr.org/archives/593
jww

32
Gcc संकलक विकल्प के -ftrapvकारण यह (हस्ताक्षरित) पूर्णांक ओवरफ़्लो पर एक SIGABRT उत्पन्न करेगा। देखें यहाँ
निबोट

1
यह अतिप्रवाह प्रश्न का उत्तर नहीं देता है, लेकिन समस्या पर आने का एक और तरीका यह होगा कि आप हमेशा पर्याप्त सटीकता की गारंटी के लिए जीएमपी जैसे बिगएनम लाइब्रेरी का उपयोग करें । यदि आप पर्याप्त संख्या में मोर्चे आवंटित करते हैं, तो आपको अतिप्रवाह के बारे में चिंता करने की ज़रूरत नहीं होगी।
लेखक

1
उनके जवाब में @HeadGeek द्वारा दी गई जानकारी बहुत सुंदर है जो मैं भी कहूंगा। हालांकि, एक जोड़ के साथ। जिस तरह से आप गुणन के लिए ओवरफ्लो का पता लगा रहे हैं, वह शायद सबसे तेज है। एआरएम के रूप में मैंने हेडगेक के उत्तर में टिप्पणी की है आप संख्या की रैंक (जहां इसका उच्चतम बिट है) निर्धारित करने के लिए clzनिर्देश या __clz(unsigned)फ़ंक्शन का उपयोग कर सकते हैं । जब से मैं अनिश्चित हूं अगर यह x86 या x64 पर उपलब्ध है तो मैं मानूंगा कि यह नहीं है और कहते हैं कि सबसे महत्वपूर्ण बिट खोजने के लिए सबसे खराब log(sizeof(int)*8)निर्देश लगेगा ।
nonsensickle

जवाबों:


229

मैं देखता हूं कि आप अहस्ताक्षरित पूर्णांक का उपयोग कर रहे हैं। परिभाषा में, C में (मुझे C ++ के बारे में पता नहीं है), अहस्ताक्षरित अंकगणित अतिप्रवाह नहीं करता है ... इसलिए, कम से कम C के लिए, आपकी बात म्यूट है :)

हस्ताक्षरित पूर्णांक के साथ, एक बार अतिप्रवाह होने के बाद, अपरिभाषित व्यवहार (यूबी) हुआ है और आपका कार्यक्रम कुछ भी कर सकता है (उदाहरण के लिए: परीक्षण अनिर्णायक)। 

#include <limits.h>

int a = <something>;
int x = <something>;
a += x;              /* UB */
if (a < 0) {         /* Unreliable test */
  /* ... */
}

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

// For addition
#include <limits.h>

int a = <something>;
int x = <something>;
if ((x > 0) && (a > INT_MAX - x)) /* `a + x` would overflow */;
if ((x < 0) && (a < INT_MIN - x)) /* `a + x` would underflow */;

// For subtraction
#include <limits.h>
int a = <something>;
int x = <something>;
if ((x < 0) && (a > INT_MAX + x)) /* `a - x` would overflow */;
if ((x > 0) && (a < INT_MIN + x)) /* `a - x` would underflow */;

// For multiplication
#include <limits.h>

int a = <something>;
int x = <something>;
// There may be a need to check for -1 for two's complement machines.
// If one number is -1 and another is INT_MIN, multiplying them we get abs(INT_MIN) which is 1 higher than INT_MAX
if ((a == -1) && (x == INT_MIN)) /* `a * x` can overflow */
if ((x == -1) && (a == INT_MIN)) /* `a * x` (or `a / x`) can overflow */
// general case
if (a > INT_MAX / x) /* `a * x` would overflow */;
if ((a < INT_MIN / x)) /* `a * x` would underflow */;

विभाजन के लिए ( INT_MINऔर -1विशेष मामले को छोड़कर ), पर INT_MINया जाने की कोई संभावना नहीं है INT_MAX


97
अहस्ताक्षरित पूर्णांक सी ++ में या तो सख्ती से ओवरफ्लो नहीं करते हैं (आईएसओ / आईईसी 14882: 2003 3.9.1.4)। प्रश्न में 'अतिप्रवाह' का मेरा उपयोग अधिक बोलचाल का अर्थ था, जिसका उद्देश्य अहस्ताक्षरित प्रकारों की अच्छी तरह से परिभाषित रैपिंग को शामिल करना था, क्योंकि मैं गणितीय सकारात्मक पूर्णांकों का प्रतिनिधित्व करने वाले अहस्ताक्षरित अभिरुचियों में रुचि रखता था, न कि सकारात्मक पूर्णांक mod ​​2 ^ 32 (या 2 ^) 64)। गणितीय अनंत-आकार पूर्णांक व्यवहार से विचलन के रूप में अतिप्रवाह और भाषा में एक अपरिभाषित व्यवहार के रूप में अतिप्रवाह के बीच का अंतर शायद ही कभी स्पष्ट किया जाता है।
क्रिस जॉनसन

15
उस परीक्षण की आवश्यकता नहीं है x >= 0- x > 0पर्याप्त होगा (यदि x == 0, तो x + aस्पष्ट कारणों के लिए अतिप्रवाह नहीं हो सकता है)।
कैफे

2
@pmg, क्या मानक से एक सहायक बोली है?
पचेरियर

5
मुझे यह दृष्टिकोण पसंद है ... हालांकि, सावधान रहें: गुणन अतिप्रवाह का पता लगाने में एक सकारात्मक एक्स होता है। X == 0 के लिए, यह शून्य पहचान से विभाजित होता है, और नकारात्मक x के लिए, यह हमेशा गलत तरीके से अतिप्रवाह का पता लगाता है।
फ्रांज डी।

4
if ((a < INT_MIN / x))परीक्षण में बहुत देर हो चुकी है। if (x == -1) पहले एक परीक्षण की जरूरत है।
chux -

164

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

इसके अलावा, किसी भी दो ऑपरेंड का परिणाम (सबसे अधिक) सबसे बड़े ऑपरेंड के उच्चतम एक-बिट से एक बिट अधिक होगा। उदाहरण के लिए:

bool addition_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
    return (a_bits<32 && b_bits<32);
}

गुणन के लिए, किसी भी दो ऑपरेंड का परिणाम होगा (अधिकतम) ऑपरेंड के बिट्स का योग। उदाहरण के लिए:

bool multiplication_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
    return (a_bits+b_bits<=32);
}

इसी तरह, आप इस तरह aकी शक्ति के परिणाम के अधिकतम आकार का अनुमान लगा सकते हैं b:

bool exponentiation_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a);
    return (a_bits*b<=32);
}

(निश्चित रूप से अपने लक्ष्य पूर्णांक के लिए बिट्स की संख्या को प्रतिस्थापित करें।)

मैं एक संख्या में उच्चतम एक बिट की स्थिति का निर्धारण करने के लिए सबसे तेज़ तरीका सुनिश्चित नहीं कर रहा हूँ, यहाँ एक जानवर-बल विधि है:

size_t highestOneBitPosition(uint32_t a) {
    size_t bits=0;
    while (a!=0) {
        ++bits;
        a>>=1;
    };
    return bits;
}

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


98
और निश्चित रूप से आप उच्चतम लॉग इन करने के लिए नाम बदल सकते हैं :) लॉग इन करने के लिए
ओलिवर

37
हां, यह उसी तरह का ऑपरेशन है log2, लेकिन यह जरूरी नहीं कि किसी ऐसे व्यक्ति के लिए स्पष्ट हो, जिसके पास गणितीय पृष्ठभूमि नहीं है।
हेड गीक

48
क्या यह एल्गोरिथ्म सुरक्षित उत्तरों को कम नहीं समझता है? 2 ^ 31 + 0 उच्चतम के रूप में असुरक्षित के बाद से पता लगाएगा (2 ^ 31) = 32. (2 ^ 32 - 1) * 1 के बाद से असुरक्षित के रूप में 32 + 1> 32 से पता चलेगा। 1 ^ 100 अपने * 100 से असुरक्षित के रूप में पता लगाएगा। > 32.
क्लीई

19
आपके multiplication_is_safe 0x8000 * 0x10000ओवरफ्लो के अनुसार (बिट पोज़िशन 16 + 17 = 33 है जो कि > 32 है ), हालाँकि ऐसा नहीं है क्योंकि यह 0x8000 * 0x10000 = 0x80000000स्पष्ट रूप से अभी भी एक अहस्ताक्षरित 32 बिट इंट में फिट बैठता है। यह उन उदाहरणों में से केवल एक है जिसके लिए यह कोड काम नहीं करता है। 0x8000 * 0x10001, ...
मिकी

13
@GT_mh: आपकी बात? जैसा कि मैंने कहा, यह सही नहीं है; यह एक नियम के-अंगूठे निश्चित कहेंगे कि जब कुछ है सुरक्षित है, लेकिन वहाँ निर्धारित करने के लिए हर गणना पूर्ण गणना कर के बिना उचित रहेगा कोई रास्ता नहीं है। 0x8000 * 0x10000इस परिभाषा से "सुरक्षित" नहीं है, भले ही यह ठीक हो।
हेड गीक

147

क्लैंग 3.4+ और जीसीसी 5+ ऑफ़र की अंकगणित बिल्डिंग्स की जाँच की। वे इस समस्या का बहुत तेज़ समाधान प्रस्तुत करते हैं, खासकर जब बिट-टेस्टिंग सेफ्टी चेक की तुलना में।

ओपी के प्रश्न में उदाहरण के लिए, यह इस तरह काम करेगा:

unsigned long b, c, c_test;
if (__builtin_umull_overflow(b, c, &c_test))
{
    // Returned non-zero: there has been an overflow
}
else
{
    // Return zero: there hasn't been an overflow
}

क्लैंग प्रलेखन निर्दिष्ट नहीं करता है कि क्या c_testअतिप्रवाह होने पर अतिप्रवाहित परिणाम होता है, लेकिन जीसीसी प्रलेखन का कहना है कि यह करता है। यह देखते हुए कि इन दोनों को __builtinअसंगत होना पसंद है , शायद यह मान लेना सुरक्षित है कि यह क्लैंग भी काम करता है।

वहाँ एक __builtinप्रत्येक गणित आपरेशन कि अतिप्रवाह कर सकते हैं (इसके अलावा, घटाव, गुणा), पर हस्ताक्षर किए और अहस्ताक्षरित भिन्न रूपों के साथ, पूर्णांक आकार, लंबे आकार, और लंबे आकार के लिए के लिए। नाम के लिए सिंटैक्स है __builtin_[us](operation)(l?l?)_overflow:

  • uके लिए अहस्ताक्षरित या sके लिए हस्ताक्षर किए ;
  • ऑपरेशन में से एक है add, subया mul;
  • कोई lप्रत्यय का मतलब यह नहीं है कि ऑपरेंड intएस हैं; एक का lमतलब long; दो का lमतलब long long

तो एक हस्ताक्षरित लंबे पूर्णांक जोड़ के लिए, यह होगा __builtin_saddl_overflow। पूरी सूची क्लैंग प्रलेखन पृष्ठ पर पाई जा सकती है ।

जीसीसी 5 + और बजना 3.8+ अतिरिक्त मूल्यों के प्रकार निर्दिष्ट किए बिना कि काम सामान्य builtins प्रदान करते हैं: __builtin_add_overflow, __builtin_sub_overflowऔर __builtin_mul_overflow। ये छोटे से छोटे प्रकार पर भी काम करते हैं int

प्लेटफ़ॉर्म के लिए सबसे अच्छा निर्माण करने के लिए निम्न निर्मित। X86 पर, वे कैरी, ओवरफ्लो और झंडे पर हस्ताक्षर करते हैं।

विजुअल स्टूडियो का cl.exe प्रत्यक्ष समकक्ष नहीं है। अहस्ताक्षरित परिवर्धन और घटाव के लिए, सहित <intrin.h>आप का उपयोग करने की अनुमति देगा addcarry_uNNऔर subborrow_uNN(जहां NN बिट्स की संख्या है, जैसे addcarry_u8या subborrow_u64)। उनके हस्ताक्षर एक सा है:

unsigned char _addcarry_u32(unsigned char c_in, unsigned int src1, unsigned int src2, unsigned int *sum);
unsigned char _subborrow_u32(unsigned char b_in, unsigned int src1, unsigned int src2, unsigned int *diff);

c_in/ b_inइनपुट पर ले जाने / उधार झंडा है, और वापसी मूल्य आउटपुट पर ले / उधार है। यह हस्ताक्षरित संचालन या गुणन के लिए समतुल्य प्रतीत नहीं होता है।

अन्यथा, विंडोज के लिए क्लैंग अब उत्पादन-तैयार है (क्रोम के लिए काफी अच्छा है), ताकि एक विकल्प भी हो सके।


__builtin_sub_overflowनिश्चित रूप से क्लैंग 3.4 में नहीं है।
रिचर्ड कुक

2
@ रीचर्डकूक, इसमें कुछ समय लगा लेकिन क्लैंग के पास संस्करण 3.9 के रूप में जेनेरिक बिल्डिंग्स हैं।
zneak

@tambre, मुझे नहीं लगता कि वहाँ हैं।
zneak

4
डॉक्स के अनुसार , __builtin_add_overflowऔर दोस्तों को पहले से ही क्लैंग 3.8 पर उपलब्ध होना चाहिए।
लेकेनस्टाइन

2
धन्यवाद। यह बहुत अच्छा काम करता है। किसी भी विचार दृश्य सी ++ के लिए इसी समारोह क्या है? उन्हें खोजने के लिए प्रतीत नहीं कर सकते।
मुदित जैन

53

कुछ संकलक सीपीयू में पूर्णांक ओवरफ्लो ध्वज तक पहुंच प्रदान करते हैं जिसे आप तब परीक्षण कर सकते हैं लेकिन यह मानक नहीं है।

गुणा करने से पहले आप अतिप्रवाह की संभावना के लिए भी परीक्षण कर सकते हैं:

if ( b > ULONG_MAX / a ) // a * b would overflow

11
... या
num_limits का

20
एक = 0 को संभालने के लिए मत भूलना - तब विभाजन टूट जाता है।
इलेमा जूल 3'09

16
@ उलेमा: "a = 0 हैंडल करना न भूलें" - और INT_MIN / -1।
jww

1
क्या होगा अगर b == ULONG_MAX / a? फिर यह अभी भी फिट हो सकता है, यह देखते हुए कि अवशिष्ट के बिना aविभाजित ULONG_MAXहोता है।
सूअर

मजेदार है कि, प्रदर्शन के लिहाज से, गुणा एक विभाजन की तुलना में तेज है और आप प्रत्येक गुणा के लिए एक विभाजन जोड़ रहे हैं। इस तरह ध्वनि नहीं है समाधान।
ढोल

40

चेतावनी: जब संकलन के साथ जीसीसी एक अतिप्रवाह जांच को अनुकूलित कर सकता है -O2। विकल्प -Wallआपको कुछ मामलों में चेतावनी देगा जैसे

if (a + b < a) { /* Deal with overflow */ }

लेकिन इस उदाहरण में नहीं:

b = abs(a);
if (b < 0) { /* Deal with overflow */ }

सीईआरटी पेपर में वर्णित होने से पहले एकमात्र सुरक्षित तरीका अतिप्रवाह के लिए जांचना है , और यह व्यवस्थित रूप से उपयोग करने के लिए अविश्वसनीय रूप से थकाऊ होगा।

-fwrapvसमस्या को हल करता है, लेकिन कुछ अनुकूलन अक्षम करता है।

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


8
ध्यान दें कि संकलक केवल हस्ताक्षरित पूर्णांक प्रकारों के साथ ऐसा कर सकते हैं; ओवरफ्लो को अहस्ताक्षरित पूर्णांक प्रकारों के लिए पूरी तरह से परिभाषित किया गया है। फिर भी, हाँ, यह काफी खतरनाक जाल है!
साम्ब

1
"मुझे लगता है कि कंपाइलर को ऑप्टिमाइज़ेशन करते समय डिफ़ॉल्ट रूप से एक चेतावनी जारी करनी चाहिए जो ओवरफ्लो न होने पर निर्भर करती है।" - तो for(int k = 0; k < 5; k++) {...}एक चेतावनी उठानी चाहिए?
user253751

2
@ मिनीबिस: ऐसा क्यों होना चाहिए? के मूल्यों को kआसानी से संकलन समय पर निर्धारित किया जा सकता है। संकलक को कोई भी धारणा बनाने की आवश्यकता नहीं है।
मिकएमबी

2
@immibis: ऊपर उद्धृत करने के लिए: "मुझे लगता है कि कंपाइलर को डिफ़ॉल्ट बनाते समय एक चेतावनी जारी करनी चाहिए जब एक अनुकूलन जो ओवरफ्लो न होने पर निर्भर करता है।"
मिकएमबी

1
@MikeMB वह कंपाइलर जहां अनुकूलन nकम से कम 5 बिट्स का उपयोग करने वाली शिफ्ट इंस्ट्रक्शन को छोड़ने से पहले 32 से कम की जाँच करने की जहमत नहीं उठाता n?
user253751

30

Clang अब हस्ताक्षरित और अहस्ताक्षरित पूर्णांक दोनों के लिए डायनामिक ओवरफ़्लो चेक का समर्थन करता है। -Fsanitize = पूर्णांक स्विच देखें । अभी के लिए, यह डिबग उद्देश्यों के लिए पूरी तरह से समर्थित डायनामिक ओवरफ़्लो जाँच वाला एकमात्र C ++ कंपाइलर है।


25

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

मुख्य बिंदु यह है कि ऊपरी बाउंड जिसे समस्या के लिए ए, बी या सी की आवश्यकता होती है वह 98.765.432 है। वैसे भी, तुच्छ और गैर तुच्छ भागों में समस्या को विभाजित करके शुरू करना:

  • x 0 == 1 (9, 8, 7, 6, 5, 4, 3, 2 के सभी क्रमबद्ध समाधान हैं)
  • x 1 == x (कोई समाधान संभव नहीं)
  • 0 बी == 0 (कोई समाधान संभव नहीं)
  • 1 बी == 1 (कोई समाधान संभव नहीं)
  • एक , एक> 1, b> 1 (गैर तुच्छ)

अब हमें केवल यह दिखाने की आवश्यकता है कि कोई अन्य समाधान संभव नहीं है और केवल क्रमपरिवर्तन वैध हैं (और फिर उन्हें प्रिंट करने का कोड तुच्छ है)। हम ऊपरी सीमा पर वापस जाते हैं। वास्तव में ऊपरी सीमा c 98.765.432 है। यह ऊपरी सीमा है क्योंकि यह 8 अंकों (प्रत्येक और बी के लिए 10 अंक कुल शून्य 1) ​​के साथ सबसे बड़ी संख्या है। यह ऊपरी बाउंड केवल c के लिए है क्योंकि ए और बी के लिए सीमा घातीय वृद्धि के कारण बहुत कम होनी चाहिए, क्योंकि हम गणना कर सकते हैं, बी से 2 से ऊपरी सीमा तक भिन्न हो सकते हैं:

    9938.08^2 == 98765432
    462.241^3 == 98765432
    99.6899^4 == 98765432
    39.7119^5 == 98765432
    21.4998^6 == 98765432
    13.8703^7 == 98765432
    9.98448^8 == 98765432
    7.73196^9 == 98765432
    6.30174^10 == 98765432
    5.33068^11 == 98765432
    4.63679^12 == 98765432
    4.12069^13 == 98765432
    3.72429^14 == 98765432
    3.41172^15 == 98765432
    3.15982^16 == 98765432
    2.95305^17 == 98765432
    2.78064^18 == 98765432
    2.63493^19 == 98765432
    2.51033^20 == 98765432
    2.40268^21 == 98765432
    2.30883^22 == 98765432
    2.22634^23 == 98765432
    2.15332^24 == 98765432
    2.08826^25 == 98765432
    2.02995^26 == 98765432
    1.97741^27 == 98765432

नोटिस, उदाहरण के लिए अंतिम पंक्ति: यह कहता है कि 1.97 ^ 27 ~ 98M। इसलिए, उदाहरण के लिए, 1 ^ 27 == 1 और 2 ^ 27 == 134.217.728 और इसका कोई हल नहीं है क्योंकि इसमें 9 अंक (2> 1.97 है) इसलिए यह वास्तव में परीक्षण किए जाने वाले से बड़ा है)। जैसा कि देखा जा सकता है, ए और बी के परीक्षण के लिए उपलब्ध संयोजन वास्तव में छोटे हैं। B == 14 के लिए, हमें 2 और 3 प्रयास करने की आवश्यकता है। b == 3 के लिए, हम 2 से शुरू करते हैं और 462 पर रुकते हैं। सभी परिणाम ~ 98M से कम होने की अनुमति है।

अब बस उपरोक्त सभी संयोजनों का परीक्षण करें और उन लोगों की तलाश करें जो किसी भी अंक को नहीं दोहराते हैं:

    ['0', '2', '4', '5', '6', '7', '8'] 84^2 = 7056
    ['1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481
    ['0', '1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481 (+leading zero)
    ['1', '2', '3', '5', '8'] 8^3 = 512
    ['0', '1', '2', '3', '5', '8'] 8^3 = 512 (+leading zero)
    ['1', '2', '4', '6'] 4^2 = 16
    ['0', '1', '2', '4', '6'] 4^2 = 16 (+leading zero)
    ['1', '2', '4', '6'] 2^4 = 16
    ['0', '1', '2', '4', '6'] 2^4 = 16 (+leading zero)
    ['1', '2', '8', '9'] 9^2 = 81
    ['0', '1', '2', '8', '9'] 9^2 = 81 (+leading zero)
    ['1', '3', '4', '8'] 3^4 = 81
    ['0', '1', '3', '4', '8'] 3^4 = 81 (+leading zero)
    ['2', '3', '6', '7', '9'] 3^6 = 729
    ['0', '2', '3', '6', '7', '9'] 3^6 = 729 (+leading zero)
    ['2', '3', '8'] 2^3 = 8
    ['0', '2', '3', '8'] 2^3 = 8 (+leading zero)
    ['2', '3', '9'] 3^2 = 9
    ['0', '2', '3', '9'] 3^2 = 9 (+leading zero)
    ['2', '4', '6', '8'] 8^2 = 64
    ['0', '2', '4', '6', '8'] 8^2 = 64 (+leading zero)
    ['2', '4', '7', '9'] 7^2 = 49
    ['0', '2', '4', '7', '9'] 7^2 = 49 (+leading zero)

उनमें से कोई भी समस्या से मेल नहीं खाता (जिसे '0', '1', ..., '9') की अनुपस्थिति से भी देखा जा सकता है।

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

    import math

    m = 98765432
    l = []
    for i in xrange(2, 98765432):
        inv = 1.0/i
        r = m**inv
        if (r < 2.0): break
        top = int(math.floor(r))
        assert(top <= m)

        for j in xrange(2, top+1):
            s = str(i) + str(j) + str(j**i)
            l.append((sorted(s), i, j, j**i))
            assert(j**i <= m)

    l.sort()
    for s, i, j, ji in l:
        assert(ji <= m)
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d' % (s, i, j, ji)

        # Try with non significant zero somewhere
        s = ['0'] + s
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d (+leading zero)' % (s, i, j, ji)

1
आप ऊपरी सीमा के रूप में 9.876.543.210 का उपयोग क्यों नहीं कर रहे हैं?
टॉम रोजगारो

3
क्योंकि समीकरण के बाएं हाथ के लिए 2 अंकों का उपयोग किया जाना चाहिए।
hdante

2
ऐसा नहीं है कि इससे कोई फर्क पड़ता है, लेकिन ऊपरी सीमा को वास्तव में 98765410 के रूप में लिया जा सकता है क्योंकि आपने एलएचएस पर मूल्यों को बताया है> 1
पॉल

24

यहां प्रश्न का "गैर-पोर्टेबल" समाधान है। इंटेल x86 और x64 CPU में तथाकथित EFLAGS-register है , जो प्रत्येक पूर्णांक अंकगणितीय ऑपरेशन के बाद प्रोसेसर द्वारा भरा जाता है। मैं यहां एक विस्तृत विवरण छोड़ दूंगा। प्रासंगिक झंडे "अतिप्रवाह" ध्वज (मुखौटा 0x800) और "कैर्री" ध्वज (मुखौटा 0x1) हैं। उन्हें सही ढंग से व्याख्या करने के लिए, किसी को विचार करना चाहिए कि क्या ऑपरेंड हस्ताक्षरित या अहस्ताक्षरित प्रकार के हैं।

यहां सी / सी ++ से झंडे की जांच करने का एक व्यावहारिक तरीका है। निम्न कोड विजुअल स्टूडियो 2005 या नए (32 और 64 बिट दोनों) पर और साथ ही जीएनयू सी / सी ++ 64 बिट पर काम करेगा।

#include <cstddef>
#if defined( _MSC_VER )
#include <intrin.h>
#endif

inline size_t query_intel_x86_eflags(const size_t query_bit_mask)
{
    #if defined( _MSC_VER )

        return __readeflags() & query_bit_mask;

    #elif defined( __GNUC__ )
        // This code will work only on 64-bit GNU-C machines.
        // Tested and does NOT work with Intel C++ 10.1!
        size_t eflags;
        __asm__ __volatile__(
            "pushfq \n\t"
            "pop %%rax\n\t"
            "movq %%rax, %0\n\t"
            :"=r"(eflags)
            :
            :"%rax"
            );
        return eflags & query_bit_mask;

    #else

        #pragma message("No inline assembly will work with this compiler!")
            return 0;
    #endif
}

int main(int argc, char **argv)
{
    int x = 1000000000;
    int y = 20000;
    int z = x * y;
    int f = query_intel_x86_eflags(0x801);
    printf("%X\n", f);
}

यदि ऑपरेंड को ओवरफ्लो के बिना गुणा किया गया था, तो आपको 0 से रिटर्न वैल्यू मिलेगी query_intel_eflags(0x801), यानी न तो कैरी और न ही ओवरफ्लो के झंडे सेट हैं। प्रदान किए गए उदाहरण कोड ऑफ मेन () में, एक अतिप्रवाह होता है और दोनों झंडे 1 पर सेट होते हैं। यह चेक आगे की गणना नहीं करता है, इसलिए यह काफी तेज होना चाहिए।


21

यदि आपके पास एक डेटाटाइप है जो आपके द्वारा परीक्षण किए जाने से बड़ा है (जैसे कि आप 32-बिट ऐड करते हैं और आपके पास 64-बिट प्रकार है), तो यह पता चलेगा कि क्या अतिप्रवाह हुआ। मेरा उदाहरण 8-बिट ऐड के लिए है। लेकिन इसे बढ़ाया जा सकता है।

uint8_t x, y;    /* Give these values */
const uint16_t data16    = x + y;
const bool carry        = (data16 > 0xFF);
const bool overflow     = ((~(x ^ y)) & (x ^ data16) & 0x80);

यह इस पृष्ठ पर बताई गई अवधारणाओं पर आधारित है: http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/Comb/overflow.html

32-बिट उदाहरण के लिए, 0xFFबन जाता है 0xFFFFFFFFऔर 0x80बन जाता है 0x80000000और अंत में uint16_tबन जाता है uint64_t

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


लिंक टूट गया है: HTTP 403: निषिद्ध
पीटर मॉर्टेंसन

18

सबसे सरल तरीका यह है कि अपने unsigned longएस को एस में परिवर्तित करें unsigned long long, अपना गुणा करें और परिणाम की तुलना 0x100000000LL से करें।

आप शायद पाएंगे कि यह विभाजन करने की तुलना में अधिक कुशल है जैसा आपने अपने उदाहरण में किया है।

ओह, और यह C और C ++ दोनों में काम करेगा (जैसा कि आपने प्रश्न को दोनों के साथ टैग किया है)।


बस glibc मैनुअल पर एक नज़र डाल रहा है । के FPE_INTOVF_TRAPभाग के रूप में एक पूर्णांक अतिप्रवाह जाल ( ) का उल्लेख है SIGFPE। यह आदर्श होगा, मैनुअल में गंदे बिट्स के अलावा:

FPE_INTOVF_TRAP पूर्णांक अतिप्रवाह (एक सी कार्यक्रम में असंभव जब तक कि आप हार्डवेयर-विशिष्ट फैशन में अतिप्रवाह फंसाने को सक्षम नहीं करते)।

वास्तव में थोड़ा शर्म की बात है।


4
हे ... जो मैंने नहीं कहा था कि मैं बड़ी संख्या के साथ एक समस्या को हल करने के लिए एक कार्यक्रम लिखने की तैयारी में यह सवाल पूछ रहा हूं, जिसमें मैं पहले से ही लंबे लंबे इंट का उपयोग कर रहा हूं। चूंकि C ++ मानक में लंबे समय तक इंट (कथित तौर पर) नहीं है, इसलिए भ्रम से बचने के लिए मैं 32-बिट संस्करण के साथ फंस गया।
क्रिस जॉनसन

मैं सलाह देता हूं कि ULONG_MAXहार्ड-कोडिंग की तुलना में टाइप करना और अधिक पोर्टेबल होना आसान है 0x100000000
jw013

24
यह काम नहीं करता है जब longऔर long longएक ही आकार (जैसे कई 64-बिट compilers पर) कर रहे हैं।
१०:१३ बजे

ओवरफ्लो के बारे में बताने के लिए संकेतों पर भरोसा करना वास्तव में वैसे भी धीमा होगा।
सैमबी

@SBB केवल अगर overflows अक्सर होने की उम्मीद कर रहे थे।
user253751

17

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

यह विचार यह है कि वास्तव में क्योंकि प्रोसेसर केवल मान को वापस शून्य में लपेटने देगा और यह कि C / C ++ को किसी भी विशिष्ट प्रोसेसर से अलग किया जाना है, आप कर सकते हैं:

uint32_t x, y;
uint32_t value = x + y;
bool overflow = value < (x | y);

यह दोनों सुनिश्चित करता है कि यदि एक ऑपरेंड शून्य है और एक नहीं है, तो अतिप्रवाह का झूठा पता नहीं लगाया जाएगा और पहले से सुझाए गए बहुत सारे NOT / XOR / AND / परीक्षण कार्यों की तुलना में काफी तेज है।

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

uint32_t x, y;
uint32_t value = x + y;
const bool overflow = value < x; // Alternatively "value < y" should also work

गुणन अतिप्रवाह का पता लगाने का एक अधिक कुशल और सस्ता तरीका है:

uint32_t x, y;
const bool overflow = (x >> 16U) * (y >> 16U);
uint32_t value = overflow ? UINT32_MAX : x * y;

यह परिणाम या तो UINT32_MAX के अतिप्रवाह पर, या गुणन के परिणामस्वरूप होता है। इस मामले में हस्ताक्षरित पूर्णांकों के लिए गुणा करने की अनुमति देने के लिए यह कड़ाई से अपरिभाषित व्यवहार है।


मैं गणना सिद्धांत के कारण असहमत हूं। निम्नलिखित पर विचार करें: y> x, मान अधिकता, y केवल x से बड़ा है क्योंकि साइन बिट सेट किया जा रहा है (1 + 255, उदाहरण के लिए, अहस्ताक्षरित वर्णों के लिए) परीक्षण मान और x परिणाम होगा अतिप्रवाह में = गलत - इसलिए तार्किक का उपयोग या इस टूटे हुए व्यवहार को रोकने के लिए ..
DX-MON

परीक्षण आपके द्वारा दिए गए नंबरों के लिए काम करता है (x: = 1, y: = 255, size = uint8_t): मान 0 (1 + 255) और 0 <1 सत्य होगा। यह वास्तव में हर नंबर जोड़ी के लिए काम करता है।
गुनथर पाईज

हम्म, आप एक अच्छी बात करते हैं। मैं अभी भी सुरक्षा के पक्ष में या चाल का उपयोग करते हुए छड़ी करता हूं, हालांकि कोई भी अच्छा संकलक इसे प्रदाता को अनुकूलित करेगा जो आप वास्तव में सभी इनपुट के लिए सही हैं, जिसमें "0 + 4" जैसे गैर-अतिप्रवाह संख्याएं शामिल हैं, जहां परिणाम अतिप्रवाह नहीं होगा।
DX-MON

4
अगर वहाँ एक अतिप्रवाह है, की तुलना में x+y>=256और value=x+y-256। क्योंकि y<256हमेशा सही होता है, (y-256) नकारात्मक होता है और इसलिए value < xहमेशा सच होता है। गैर अतिप्रवाह मामले के लिए प्रमाण काफी समान है।
गनथर पाईज़

2
@ डीएक्स-मॉन: आपका पहला तरीका आवश्यक है यदि आपके पास पिछले ऐड से कैरी बिट है। uint32_t x[N], y[N], z[N], carry=0; for (int i = 0; i < N; i++) { z[i] = x[i] + y[i] + carry; carry = z[i] < (x[i] | y[i]); }यदि आप orमान नहीं रखते हैं, तो आप एक ऑपरेंड और कैरी बिट शून्य होने और एक ऑपरेंड होने 0xffffffffऔर कैरी बिट एक होने के बीच अंतर नहीं कर पाएंगे ।
मैट

14

आप C / C ++ से ओवरफ़्लो ध्वज तक नहीं पहुँच सकते।

कुछ संकलक आपको कोड में जाल निर्देश सम्मिलित करने की अनुमति देते हैं। जीसीसी पर विकल्प है -ftrapv

केवल पोर्टेबल और संकलक स्वतंत्र चीज़ जो आप कर सकते हैं, वह है अपने दम पर ओवरफ्लो की जांच करना। जैसे आपने अपने उदाहरण में किया।

हालांकि, -ftrapvनवीनतम GCC का उपयोग करके x86 पर कुछ भी नहीं लगता है। मुझे लगता है कि यह एक पुराने संस्करण से बचा हुआ है या किसी अन्य वास्तुकला के लिए विशिष्ट है। मुझे उम्मीद थी कि कंपाइलर प्रत्येक जोड़ के बाद एक INTO opcode डालेगा। दुर्भाग्य से यह ऐसा नहीं करता है।


हो सकता है कि यह भिन्न हो: -सिग्विन बॉक्स पर जीसीसी 4.3.4 का उपयोग कर ठीक काम करता है। वहाँ कम से एक उदाहरण है stackoverflow.com/questions/5005379/...
नैट कोल

3
तुम दोनों सही हो। -फ्त्राव नौकरी करते हैं लेकिन केवल हस्ताक्षरित पूर्णांक के लिए
ZAB

14

अहस्ताक्षरित पूर्णांकों के लिए, बस जाँच करें कि परिणाम एक तर्क से छोटा है:

unsigned int r, a, b;
r = a + b;
if (r < a)
{
    // Overflow
}

हस्ताक्षरित पूर्णांक के लिए आप तर्कों और परिणाम के संकेतों की जांच कर सकते हैं।

विभिन्न चिह्नों के पूर्णांक अतिप्रवाह नहीं कर सकते हैं, और एक ही संकेत अतिप्रवाह के पूर्णांक केवल तभी होते हैं जब परिणाम एक अलग संकेत का होता है:

signed int r, a, b, s;
r = a + b;
s = a>=0;
if (s == (b>=0) && s != (r>=0))
{
    // Overflow
}

अच्छी तरह से पहली विधि भी हस्ताक्षरित पूर्णांक के लिए काम करेगी, है ना? char result = (char)127 + (char)3;होगा -126; दोनों ऑपरेंड से छोटा।
प्राइमफ़ाकटर

1
ओह, मैं देख रहा हूँ, समस्या यह है कि यह हस्ताक्षरित प्रकारों के लिए अपरिभाषित है।
प्राइमफ़ाकटर

27
-1 हस्ताक्षरित संख्याओं के अतिप्रवाह से अपरिभाषित व्यवहार होता है (इसलिए परीक्षण वास्तव में उपयोगी होने में बहुत देर हो चुकी है)।
व्रू

1
@primfaktor यह हस्ताक्षरित int के लिए काम नहीं करता है: char ((- 127) + (-17)) = 112. हस्ताक्षरित int के लिए आपको तर्कों और परिणाम के संकेत बिट की जांच करनी होगी
phuclv

3
जैसा कि पहले ही कहा गया है, अतिप्रवाह के मामले में a + b के अपरिभाषित व्यवहार के कारण हस्ताक्षरित पूर्णांक का समाधान काम नहीं करता है। ऑपरेशन से पहले हस्ताक्षरित पूर्णांक के साथ अतिप्रवाह के लिए जाँच की जानी चाहिए।
मारवान बुर्लेल

11

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

अतिप्रवाह परीक्षण, जोड़ और घटाव:

  1. प्रकार, MAXVALUE और MINVALUE के लिए सबसे बड़े और छोटे संभव मानों का प्रतिनिधित्व करने वाले स्थिरांक प्राप्त करें।

  2. ऑपरेंड के संकेतों की गणना और तुलना करें।

    ए। यदि या तो मान शून्य है, तो न तो जोड़ और घटाव अतिप्रवाह कर सकते हैं। शेष परीक्षण छोड़ें।

    ख। यदि संकेत विपरीत हैं, तो इसके अलावा अतिप्रवाह नहीं हो सकता है। शेष परीक्षण छोड़ें।

    सी। यदि संकेत समान हैं, तो घटाव अतिप्रवाह नहीं हो सकता है। शेष परीक्षण छोड़ें।

  3. MAXVALUE के सकारात्मक अतिप्रवाह के लिए परीक्षण।

    ए। यदि दोनों संकेत सकारात्मक हैं और MAXVALUE - A <B है, तो जोड़ अतिप्रवाह होगा।

    ख। यदि B का चिन्ह ऋणात्मक और MAXVALUE - A <-B है, तो घटाव अतिप्रवाह होगा।

  4. MINVALUE के नकारात्मक अतिप्रवाह के लिए परीक्षण।

    ए। यदि दोनों लक्षण नकारात्मक हैं और MINVALUE - A> B है, तो इसके अलावा अतिप्रवाह होगा।

    ख। यदि A का चिन्ह ऋणात्मक और MINVALUE - A> B है, तो घटाव अतिप्रवाह होगा।

  5. अन्यथा, कोई अतिप्रवाह नहीं।

हस्ताक्षरित अतिप्रवाह परीक्षण, गुणा और भाग:

  1. प्रकार, MAXVALUE और MINVALUE के लिए सबसे बड़े और छोटे संभव मानों का प्रतिनिधित्व करने वाले स्थिरांक प्राप्त करें।

  2. कंप्यूटर्स के परिमाण (पूर्ण मान) की गणना और तुलना करें। (नीचे, मान लें कि ए और बी ये परिमाण हैं, हस्ताक्षरित मूल नहीं हैं।)

    ए। यदि या तो मान शून्य है, तो गुणन अतिप्रवाह नहीं कर सकता है, और विभाजन शून्य या अनंत का उत्पादन करेगा।

    ख। यदि या तो मान एक है, तो गुणन और विभाजन अतिप्रवाह नहीं हो सकता है।

    सी। यदि एक ऑपरेंड का परिमाण एक से कम है और दूसरे का एक से अधिक है, तो गुणा अधिक नहीं हो सकता है।

    घ। यदि परिमाण दोनों एक से कम हैं, तो विभाजन अतिप्रवाह नहीं हो सकता है।

  3. MAXVALUE के सकारात्मक अतिप्रवाह के लिए परीक्षण।

    ए। यदि दोनों ऑपरेंड एक और MAXVALUE / A <B से अधिक हैं, तो गुणा अधिक हो जाएगा।

    ख। यदि B एक और MAXVALUE * B <A से कम है, तो विभाजन ओवरफ्लो हो जाएगा।

  4. अन्यथा, कोई अतिप्रवाह नहीं।

नोट: MINVALUE का न्यूनतम ओवरफ्लो 3 से संभाला जाता है, क्योंकि हमने पूर्ण मान लिया था। हालाँकि, अगर ABS (MINVALUE)> MAXVALUE, तो हमारे पास कुछ दुर्लभ झूठी सकारात्मकताएँ होंगी।

अंडरफ्लो के लिए परीक्षण समान हैं, लेकिन इसमें ईपीएसआईएलओएन (शून्य से अधिक सबसे छोटी सकारात्मक संख्या) शामिल है।


1
POSIX सिस्टम पर कम से कम, SIGFPE सिग्नल को फ्लोटिंग पॉइंट के तहत / ओवरफ्लो के लिए सक्षम किया जा सकता है।
क्रिस जॉनसन

फ्लोटिंग पॉइंट और बैक वर्क्स में परिवर्तित करते समय, यह (32 बिट मशीन पर मेरे परीक्षण के अनुसार) अन्य समाधानों की तुलना में बहुत धीमा है।
जनकानि

एक समीक्षक ने घटाव भाग 2 के लिए एक लापता मामले का पता लगाया। मैं सहमत हूं कि 0 - न्यूनतम ओवरफ्लो होगा। तो इस मामले के लिए परीक्षण जोड़ा जाना चाहिए।
पॉल चेरोच

<पांडित्य> इंटर्जर कम नहीं होते (= किसी भी सटीकता के साथ प्रतिनिधित्व करने के लिए शून्य के बहुत करीब हो जाते हैं)। 1.0e-200 / 1.0e200IEEE डबल्स को मानते हुए एक वास्तविक अंडरफ्लो का उदाहरण होगा। इसके बजाय, यहां सही शब्द नकारात्मक अतिप्रवाह है। </ pedantic>
Arne Vogel

सटीक होने के लिए, पूर्णांक को अंडरफ्लो नहीं माना जाता है, इसका कारण परिभाषित ट्रंकेशन व्यवहार है, जैसे 1/INT_MAX अच्छी तरह से अंडरफ्लो माना जा सकता है, लेकिन भाषा केवल ट्रंकेशन को शून्य करने का आदेश देती है।
अरने वोगल

8

CERT ने साइन इन किए गए पूर्णांक ओवरफ़्लो, अहस्ताक्षरित पूर्णांक रैपिंग और पूर्णांक ट्रंकेशन को "as-if" असीम रूप से (AIR) पूर्णांक मॉडल का उपयोग करके पता लगाने और रिपोर्ट करने के लिए एक नया दृष्टिकोण विकसित किया है। CERT ने मॉडल का वर्णन करते हुए एक तकनीकी रिपोर्ट प्रकाशित की है और GCC 4.4.0 और GCC 4.5.0 पर आधारित एक कार्यशील प्रोटोटाइप का उत्पादन किया है।

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


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

8

एक और दिलचस्प उपकरण IOC है: C / C ++ के लिए एक पूर्णांक अतिप्रवाह चेकर

यह एक पैबंद है कंपाइलर है, जो संकलन समय पर कोड को जोड़ता है।

आपको आउटपुट इस तरह दिख रहा है:

CLANG ARITHMETIC UNDEFINED at <add.c, (9:11)> :
Op: +, Reason : Signed Addition Overflow,
BINARY OPERATION: left (int32): 2147483647 right (int32): 1

1
इस पैच को अब अन्य सैनिटाइज़र के बीच कोडबेस में मिला दिया गया है, मेरा जवाब देखें।
ZAB

7

असेंबली भाषा का उपयोग करते हुए एक समाधान का दूसरा संस्करण, एक बाहरी प्रक्रिया है। लिनक्स x64 के तहत g ++ और फ़ासम का उपयोग करके अहस्ताक्षरित पूर्णांक गुणन के लिए यह उदाहरण है।

यह प्रक्रिया दो अहस्ताक्षरित पूर्णांक तर्कों (32 बिट्स) को बढ़ाती है (amd64 के लिए विनिर्देशन के अनुसार (खंड 3.2.3 पैरामीटर पास ))।

यदि वर्ग INTEGER है, तो अनुक्रम% rdi,% rsi,% rdx,% rx,% r8 और% r9 का अगला उपलब्ध रजिस्टर उपयोग किया जाता है

(edi और esi मेरे कोड में रजिस्टर करता है)) और परिणाम देता है या 0 यदि कोई अतिप्रवाह हुआ है।

format ELF64

section '.text' executable

public u_mul

u_mul:
  MOV eax, edi
  mul esi
  jnc u_mul_ret
  xor eax, eax
u_mul_ret:
ret

परीक्षा:

extern "C" unsigned int u_mul(const unsigned int a, const unsigned int b);

int main() {
    printf("%u\n", u_mul(4000000000,2)); // 0
    printf("%u\n", u_mul(UINT_MAX/2,2)); // OK
    return 0;
}

प्रोग्राम को asm ऑब्जेक्ट फ़ाइल के साथ लिंक करें। मेरे मामले में, Qt Creator में , इसे LIBS.pro फ़ाइल में जोड़ें ।


5

युगल के साथ परिणामों की गणना करें। उनके 15 महत्वपूर्ण अंक हैं। आपकी आवश्यकता 10 8 के सी पर एक कठिन ऊपरी सीमा है  - इसमें अधिकतम 8 अंक हो सकते हैं। इसलिए, यदि यह सीमा में है, तो परिणाम सटीक होगा, और यह अन्यथा अतिप्रवाह नहीं होगा।


5

32-बिट मशीनों के अतिप्रवाह बिट का परीक्षण करने के लिए इस मैक्रो का प्रयास करें (एंजेल सिंजर्सकी के समाधान को अनुकूलित किया गया)

#define overflowflag(isOverflow){   \
size_t eflags;                      \
asm ("pushfl ;"                     \
     "pop %%eax"                    \
    : "=a" (eflags));               \
isOverflow = (eflags >> 11) & 1;}

मैंने इसे एक मैक्रो के रूप में परिभाषित किया क्योंकि अन्यथा अतिप्रवाह बिट को ओवरराइट किया गया होता।

उपर्युक्त कोड सेगमेंट के साथ एक छोटा अनुप्रयोग है:

#include <cstddef>
#include <stdio.h>
#include <iostream>
#include <conio.h>
#if defined( _MSC_VER )
#include <intrin.h>
#include <oskit/x86>
#endif

using namespace std;

#define detectOverflow(isOverflow){     \
size_t eflags;                      \
asm ("pushfl ;"                     \
    "pop %%eax"                     \
    : "=a" (eflags));               \
isOverflow = (eflags >> 11) & 1;}

int main(int argc, char **argv) {

    bool endTest = false;
    bool isOverflow;

    do {
        cout << "Enter two intergers" << endl;
        int x = 0;
        int y = 0;
        cin.clear();
        cin >> x >> y;
        int z = x * y;
        detectOverflow(isOverflow)
        printf("\nThe result is: %d", z);
        if (!isOverflow) {
            std::cout << ": no overflow occured\n" << std::endl;
        } else {
            std::cout << ": overflow occured\n" << std::endl;
        }

        z = x * x * y;
        detectOverflow(isOverflow)
        printf("\nThe result is: %d", z);
        if (!isOverflow) {
            std::cout << ": no overflow ocurred\n" << std::endl;
        } else {
            std::cout << ": overflow occured\n" << std::endl;
        }

        cout << "Do you want to stop? (Enter \"y\" or \"Y)" << endl;

        char c = 0;

        do {
            c = getchar();
        } while ((c == '\n') && (c != EOF));

        if (c == 'y' || c == 'Y') {
            endTest = true;
        }

        do {
            c = getchar();
        } while ((c != '\n') && (c != EOF));

    } while (!endTest);
}

4
सभी 32-बिट मशीनें इंटेल x86- संगत नहीं हैं, और सभी कंपाइलर ग्नू असेंबली सिंटैक्स का समर्थन नहीं करते हैं (मुझे यह अजीब लगता है कि आप कोड को पोस्ट करते हैं जो परीक्षण करते हैं, _MSC_VERहालांकि एमएस कंपाइल सभी कोड को अस्वीकार कर देंगे)।
बेन वोइगट

2

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


2

आप C / C ++ से ओवरफ़्लो ध्वज तक नहीं पहुँच सकते।

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

info asऔर देखो info gcc


8
इनलाइन कोडांतरक कोई C / C ++ सुविधा और प्लेटफ़ॉर्म स्वतंत्र नहीं है। X86 पर आप शाखाओं btw के निर्देश istead में उपयोग कर सकते हैं।
Nils Pipenbrinck

0

हेड गीक के जवाब पर विस्तार करने के लिए, एक तेज़ तरीका है addition_is_safe;

bool addition_is_safe(unsigned int a, unsigned int b)
{
    unsigned int L_Mask = std::numeric_limits<unsigned int>::max();
    L_Mask >>= 1;
    L_Mask = ~L_Mask;

    a &= L_Mask;
    b &= L_Mask;

    return ( a == 0 || b == 0 );
}

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

यह और भी तेज होगा यदि आप किसी निर्माणकर्ता में मास्क को पहले से लगा देते हैं, क्योंकि यह कभी नहीं बदलता है।


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

0

mozilla::CheckedInt<T>पूर्णांक प्रकार के लिए ओवरफ़्लो-चेक किए गए पूर्णांक गणित प्रदान करता है T(क्लैंग और जीसीसी पर संकलक आंतरिक का उपयोग करके)। कोड एमपीएल 2.0 के अधीन है और तीन पर निर्भर करता है ( IntegerTypeTraits.h, Attributes.hऔर Compiler.h) अन्य शीर्ष लेख केवल-अमानक पुस्तकालय हेडर प्लस मोज़िला विशेष जोर मशीनरी । यदि आप कोड आयात करते हैं तो आप शायद अभिकथन मशीनरी को बदलना चाहते हैं।


-1

MSalter का जवाब एक अच्छा विचार है।

यदि पूर्णांक गणना आवश्यक है (सटीक के लिए), लेकिन फ्लोटिंग पॉइंट उपलब्ध है, तो आप कुछ ऐसा कर सकते हैं:

uint64_t foo(uint64_t a, uint64_t b) {
    double dc;

    dc = pow(a, b);

    if (dc < UINT_MAX) {
       return (powu64(a, b));
    }
    else {
      // Overflow
    }
}

आमतौर पर, मैं कहूंगा कि फ्लोटिंग पॉइंट में कैलकुलेशन को दोहराना एक बुरा विचार है, लेकिन एक्सप्रेशन के इस विशिष्ट मामले के लिए ए, सी, यह अच्छी तरह से अधिक कुशल हो सकता है। लेकिन परीक्षण होना चाहिए (c * log(a) < max_log), जहांconst double max_log = log(UINT_MAX)
टोबे स्पीट

-1

X86 इंस्ट्रक्शन सेट में एक अहस्ताक्षरित गुणा निर्देश शामिल होता है जो परिणाम को दो रजिस्टरों में संग्रहीत करता है। C के उस निर्देश का उपयोग करने के लिए, कोई 64-बिट प्रोग्राम (GCC) में निम्नलिखित कोड लिख सकता है:

unsigned long checked_imul(unsigned long a, unsigned long b) {
  unsigned __int128 res = (unsigned __int128)a * b;
  if ((unsigned long)(res >> 64))
    printf("overflow in integer multiply");
  return (unsigned long)res;
}

32-बिट प्रोग्राम के लिए, किसी को परिणाम 64 बिट और पैरामीटर 32 बिट बनाने की आवश्यकता है।

ध्वज रजिस्टर की जांच करने के लिए कंपाइलर-निर्भर आंतरिक का उपयोग करने के लिए एक विकल्प है। अतिप्रवाह आंतरिक के लिए जीसीसी प्रलेखन 6.56 अंतर्निहित कार्यों से पाया जा सकता है कि अतिप्रवाह जाँच के साथ अंकगणित प्रदर्शन करने के लिए


1
__uint128हस्ताक्षरित ओवरफ्लो से बचने और एक नकारात्मक मान को सही करने के लिए आपको अहस्ताक्षरित 128-बिट प्रकार का उपयोग करना चाहिए ।
चकरली

क्या हैं "संकलक पर निर्भर सहज ज्ञान" और "अतिप्रवाह प्रवृत्ति" ? क्या आपका मतलब " आंतरिक कार्य " है ? क्या आपके पास एक संदर्भ है? (कृपया अपना उत्तर संपादित करके , टिप्पणियों में यहाँ न दें (उचित रूप में)।)
पीटर मोर्टेंसन

-3
#include <stdio.h>
#include <stdlib.h>

#define MAX 100 

int mltovf(int a, int b)
{
    if (a && b) return abs(a) > MAX/abs(b);
    else return 0;
}

main()
{
    int a, b;

    for (a = 0; a <= MAX; a++)
        for (b = 0; b < MAX; b++) {

        if (mltovf(a, b) != (a*b > MAX)) 
            printf("Bad calculation: a: %d b: %d\n", a, b);

    }
}

-3

एक साफ तरीका यह है कि सभी ऑपरेटरों (विशेष रूप से * और *) को ओवरराइड किया जाए और संचालन करने से पहले एक अतिप्रवाह की जांच करें।


6
सिवाय इसके कि आप निर्मित प्रकारों के लिए ऑपरेटरों को ओवरराइड नहीं कर सकते। आपको इसके लिए एक वर्ग लिखने की आवश्यकता होगी और इसका उपयोग करने के लिए ग्राहक कोड को फिर से लिखना होगा।
ब्लिसोरब्लेड

-3

यह निर्भर करता है कि आप इसका क्या उपयोग करते हैं। अहस्ताक्षरित लंबे (DWORD) जोड़ या गुणा करना, सबसे अच्छा उपाय ULARGE_INTEGER का उपयोग करना है।

ULARGE_INTEGER दो DWORD की संरचना है। पूर्ण मान को "QuadPart" के रूप में एक्सेस किया जा सकता है जबकि उच्च DWORD को "HighPart" के रूप में और निम्न DWORD को "LowPart" के रूप में एक्सेस किया जा सकता है।

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

DWORD
My Addition(DWORD Value_A, DWORD Value_B)
{
    ULARGE_INTEGER a, b;

    b.LowPart = Value_A;  // A 32 bit value(up to 32 bit)
    b.HighPart = 0;
    a.LowPart = Value_B;  // A 32 bit value(up to 32 bit)
    a.HighPart = 0;

    a.QuadPart += b.QuadPart;

    // If  a.HighPart
    // Then a.HighPart contains the overflow (carry)

    return (a.LowPart + a.HighPart)

    // Any overflow is stored in a.HighPart (up to 32 bits)

6
दुर्भाग्य से, यह एक Windows- केवल समाधान है। अन्य प्लेटफार्मों में नहीं है ULARGE_INTEGER
मिस्टिकल

-3

एक पोर्टेबल तरीके से अतिप्रवाह के बिना एक अहस्ताक्षरित गुणा करने के लिए निम्नलिखित का उपयोग किया जा सकता है:

... /* begin multiplication */
unsigned multiplicand, multiplier, product, productHalf;
int zeroesMultiplicand, zeroesMultiplier;
zeroesMultiplicand = number_of_leading_zeroes( multiplicand );
zeroesMultiplier   = number_of_leading_zeroes( multiplier );
if( zeroesMultiplicand + zeroesMultiplier <= 30 ) goto overflow;
productHalf = multiplicand * ( c >> 1 );
if( (int)productHalf < 0 ) goto overflow;
product = productHalf * 2;
if( multiplier & 1 ){
   product += multiplicand;
   if( product < multiplicand ) goto overflow;
}
..../* continue code here where "product" is the correct product */
....
overflow: /* put overflow handling code here */

int number_of_leading_zeroes( unsigned value ){
   int ctZeroes;
   if( value == 0 ) return 32;
   ctZeroes = 1;
   if( ( value >> 16 ) == 0 ){ ctZeroes += 16; value = value << 16; }
   if( ( value >> 24 ) == 0 ){ ctZeroes +=  8; value = value <<  8; }
   if( ( value >> 28 ) == 0 ){ ctZeroes +=  4; value = value <<  4; }
   if( ( value >> 30 ) == 0 ){ ctZeroes +=  2; value = value <<  2; }
   ctZeroes -= x >> 31;
   return ctZeroes;
}

-4

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

long lng;
int n;
for (n = 0; n < 34; ++n)
{
   lng = pow (2, n);
   printf ("%li\n", lng);
}

इस तरह से ओवरफ्लो की जाँच करने से मुझे इसमें परिणाम मिले:

long signed lng, lng_prev = 0;
int n;
for (n = 0; n < 34; ++n)
{
    lng = pow (2, n);
    if (lng <= lng_prev)
    {
        printf ("Overflow: %i\n", n);
        /* Do whatever you do in the event of overflow.  */
    }
    printf ("%li\n", lng);
    lng_prev = lng;
}

यह अहस्ताक्षरित मूल्यों के साथ-साथ सकारात्मक और नकारात्मक दोनों पर हस्ताक्षर किए गए मूल्यों के लिए काम करता है।

बेशक, यदि आप मूल्यों को बढ़ाने के बजाय घटते मूल्यों के लिए कुछ ऐसा ही करना चाहते हैं, तो आप <=इसे बनाने के लिए संकेत फ्लिप करेंगे >=, यह मानते हुए कि अंडरफ्लो का व्यवहार ओवरफ्लो के व्यवहार के समान है। सभी ईमानदारी में, यह उतना ही पोर्टेबल है जितना कि आपको सीपीयू के अतिप्रवाह झंडे तक पहुंच के बिना मिलेगा (और इसके लिए इनलाइन असेंबली कोड की आवश्यकता होगी, जिससे आपके कोड को कार्यान्वयन में गैर-पोर्टेबल बना दिया जाएगा)।


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