कभी अपनी पसंदीदा प्रोग्रामिंग भाषा में 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% रहा।
इसका मतलब यह है कि ऊपर दिए गए उदाहरण में पाया गया प्रदर्शन हिट हमारे आवेदन के लिए पूरी तरह अप्रासंगिक है।
(1..2_000_000).sum #=> 2000001000000
:। मेरी पसंदीदा भाषाओं में से एक और sum [1 .. 2000000] --=> 2000001000000
:। मेरा पसंदीदा नहीं Array.from({length: 2000001}, (v, k) => k).reduce((acc, el) => acc + el) //=> 2000001000000
:। (निष्पक्ष होने के लिए, आखिरी वाला धोखा दे रहा है।)
Integer
Haskell में @BernhardHiller मनमानी-सटीक है, यह किसी भी संख्या को तब तक आयोजित करेगा जब तक आप आवंटन योग्य RAM से बाहर नहीं निकल जाते।
But with the 10,000,000,000 repetitions, the time taken by a check is still less than 1 nanosecond.
यह पाश का एक संकेत है जो बाहर अनुकूलित किया जा रहा है। इसके अलावा वह वाक्य पिछली संख्याओं का खंडन करता है जो मेरे लिए बहुत मान्य हैं।
checked { }
उस कोड के हिस्सों को चिह्नित करने के लिए अनुभाग का उपयोग कर सकते हैं जो अंकगणितीय अतिप्रवाह चेक करना चाहिए। यह प्रदर्शन के कारण है