संख्याओं के क्रमबद्ध सरणी के योग की गणना के लिए कौन सा एल्गोरिदम अधिक सटीक है?


22

यह देखते हुए सकारात्मक संख्या बढ़ता परिमित क्रम है z n । निम्नलिखित में से कौन सा दो एल्गोरिदम संख्याओं के योग की गणना के लिए बेहतर है?z1,z2,.....zn

s=0; 
for \ i=1:n 
    s=s + z_{i} ; 
end

या:

s=0; 
for \ i=1:n 
s=s + z_{n-i+1} ; 
end

मेरी राय में सबसे बड़ी से छोटी संख्या में संख्याओं को जोड़ना शुरू करना बेहतर होगा, क्योंकि त्रुटि छोटी और छोटी हो जाती है। हम यह भी जानते हैं कि जब हम बहुत बड़ी संख्या को बहुत कम संख्या में जोड़ते हैं, तो अनुमानित परिणाम बड़ी संख्या हो सकती है।

क्या ये सही है? इसके अलावा और क्या कहा जा सकता है?

जवाबों:


18

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

लेकिन आप बेहतर परिणाम प्राप्त करते हैं (और यह तेजी से चलता है) यदि आप चार रकम का उत्पादन करते हैं, उदाहरण के लिए: sum1, sum2, sum3, sum4 के साथ शुरू करें और बदले में sum1, sum2, sum3, sum4 में चार सरणी तत्व जोड़ें। चूंकि प्रत्येक परिणाम मूल राशि का केवल 1 / 4th औसत है, इसलिए आपकी त्रुटि चार गुना छोटी है।

अभी भी बेहतर: जोड़े में संख्याएं जोड़ें। फिर जोड़े में परिणाम जोड़ें। जोड़े में उन परिणामों को फिर से जोड़ें, और इसी तरह जब तक आप जोड़ने के लिए दो नंबरों के साथ छोड़ दिए जाते हैं।

बहुत सरल: उच्च परिशुद्धता का उपयोग करें। युगल की राशि की गणना के लिए लंबे डबल का उपयोग करें। झांकियों के योग की गणना के लिए डबल का उपयोग करें।

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


26

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


24

animal_magic का जवाब सही है कि आपको सबसे छोटी से लेकर सबसे बड़ी संख्या को जोड़ना चाहिए, हालांकि मैं यह दिखाने के लिए एक उदाहरण देना चाहता हूं।

मान लें कि हम एक फ्लोटिंग पॉइंट फॉर्मेट में काम कर रहे हैं जो हमें सटीकता का चौंका देने वाला 3 अंक देता है। अब हम दस नंबर जोड़ना चाहते हैं:

[1000, 1, 1, 1, 1, 1, 1, 1, 1, 1]

बेशक सटीक उत्तर 1009 है, लेकिन हम अपने 3 अंकों के प्रारूप में ऐसा नहीं कर सकते। 3 अंको तक गोलाई में, सबसे सटीक उत्तर जो हमें मिलता है वह है 1010। यदि हम सबसे छोटे से छोटे को जोड़ते हैं, तो प्रत्येक लूप पर:

Loop Index        s
1                 1
2                 2
3                 3
4                 4
5                 5
6                 6
7                 7
8                 8
9                 9
10                1009 -> 1010

तो हम अपने प्रारूप के लिए सबसे सटीक उत्तर प्राप्त कर सकते हैं। अब मान लेते हैं कि हम सबसे बड़े से लेकर सबसे छोटे तक को जोड़ते हैं।

Loop Index        s
1                 1000
2                 1001 -> 1000
3                 1001 -> 1000
4                 1001 -> 1000
5                 1001 -> 1000
6                 1001 -> 1000
7                 1001 -> 1000
8                 1001 -> 1000
9                 1001 -> 1000
10                1001 -> 1000

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


15

सामान्य स्थिति के लिए, मैं मुआवजे के योग (या कहन समन) का उपयोग करता हूँ। जब तक संख्याओं को पहले से ही हल नहीं किया जाता है, तब तक उन्हें जोड़ना उन्हें जोड़ने की तुलना में बहुत अधिक महंगा होगा । सघन समन, छांटे गए समन या भोले योग से अधिक सटीक है (पिछले लिंक को देखें)।

संदर्भों के अनुसार, फ्लोटिंग-पॉइंट अंकगणित के बारे में प्रत्येक प्रोग्रामर को क्या पता होना चाहिए कि बुनियादी बिंदुओं को पर्याप्त विवरण में शामिल किया गया है कि कोई व्यक्ति इसे 20 (+/- 10) मिनटों में पढ़ सकता है और मूल बातें समझ सकता है। गोल्डबर्ग द्वारा फ्लोटिंग-पॉइंट अंकगणित के बारे में "हर कंप्यूटर वैज्ञानिक को क्या पता होना चाहिए" शास्त्रीय संदर्भ है, लेकिन मैं जानता हूं कि ज्यादातर लोग जानते हैं कि पेपर ने इसे विस्तार से नहीं पढ़ा है, क्योंकि यह लगभग 50 पृष्ठों (कुछ से अधिक) में है मुद्रण), और घने गद्य में लिखे गए हैं, इसलिए मुझे लोगों के लिए पहली पंक्ति के संदर्भ के रूप में अनुशंसा करने में परेशानी होती है। यह विषय पर एक दूसरे नज़र के लिए अच्छा है। एक विश्वकोशीय संदर्भ हिघम की सटीकता और संख्यात्मक एल्गोरिदम की स्थिरता है, जो इस सामग्री को कवर करता है, साथ ही कई अन्य एल्गोरिदम में संख्यात्मक त्रुटियों का संचय; यह 680 पृष्ठ का भी है, इसलिए मैं इस संदर्भ को पहले नहीं देखूंगा।


2
संपूर्णता के लिए, हिघम की पुस्तक में आपको पृष्ठ 82 पर मूल प्रश्न का उत्तर मिलेगा : बढ़ती क्रम सबसे अच्छा है। विधि की पसंद पर चर्चा करने वाला एक खंड (4.6) भी है।
फेडरिको पोलोनी

7

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

s=0; 
for \ i=1:n 
    printf("Hello World");
    s=s + z_{i} ; 
end

अपने योग में कम परिशुद्धता प्राप्त करने के लिए पर्याप्त है! (!!)। यदि आप सटीकता के लिए जाँच करते समय अपने कोड को प्रिंट-डीबग करना चाहते हैं तो बहुत सावधान रहें।

रुचि के लिए, यह पेपर व्यापक रूप से इस्तेमाल किए जाने वाले संख्यात्मक दिनचर्या (लापैक के रैंक-खुलासा क्यूआर फैक्टराइजेशन) में एक समस्या का वर्णन करता है जिसका डिबगिंग और विश्लेषण इस मुद्दे के कारण बहुत मुश्किल था।


1
अधिकांश आधुनिक मशीनें 64-बिट हैं और वे स्केलर ऑपरेशन के लिए भी एसएसई या एवीएक्स इकाइयों का उपयोग करते हैं। वे इकाइयाँ 80-बिट अंकगणित का समर्थन नहीं करती हैं और ऑपरेशन के तर्कों के समान आंतरिक परिशुद्धता का उपयोग करती हैं। X87 FPU का उपयोग आम तौर पर अब हतोत्साहित किया जाता है और अधिकांश 64-बिट संकलक को इसका उपयोग करने के लिए मजबूर करने के लिए विशेष विकल्पों की आवश्यकता होती है।
हिस्टोरो इलिव

1
@HristoIliev टिप्पणी के लिए धन्यवाद, मुझे यह नहीं पता था!
फेडेरिको पोलोनी

4

2 विकल्पों में से, छोटे से बड़े को जोड़ने से कम संख्यात्मक त्रुटि उत्पन्न होगी और फिर बड़े से छोटे में जोड़ दी जाएगी।

हालांकि,> 20 साल पहले मेरे "न्यूमेरिकल मेथड्स" क्लास में इंस्ट्रक्टर ने यह कहा था और मेरे साथ यह हुआ कि यह अभी भी संचयकर्ता के बीच मूल्य में सापेक्ष अंतर और जोड़े जा रहे मूल्यों के कारण आवश्यकता से अधिक त्रुटि का परिचय दे रहा था।

तार्किक रूप से, एक बेहतर समाधान सूची में 2 सबसे छोटी संख्याओं को जोड़ना है, फिर छांटे गए मूल्य को क्रमबद्ध सूची में डालें।

इसे प्रदर्शित करने के लिए, मैंने एक एल्गोरिथ्म तैयार किया, जो अंतरिक्ष को मुक्त करके कुशलतापूर्वक (अंतरिक्ष और समय में) ऐसा कर सकता है क्योंकि प्राथमिक सरणी से तत्वों को हटा दिया गया था, जो कि जोड़ के बाद से आदेशित मूल्यों के एक माध्यमिक सरणी का निर्माण करने के लिए प्राथमिक सरणी से निकाला गया था उन मूल्यों का था जो हमेशा बढ़ते रहे थे। प्रत्येक पुनरावृत्ति पर दोनों सरणियों के "सुझावों" को 2 सबसे छोटे मूल्यों को खोजने के लिए जाँच की जाती है।


2

चूंकि आपने उपयोग किए जाने वाले डेटा-प्रकार को प्रतिबंधित नहीं किया है, इसलिए पूरी तरह से सटीक परिणाम प्राप्त करने के लिए, बस मनमाना लंबाई संख्या का उपयोग करें ... जिस स्थिति में ऑर्डर मायने नहीं रखेगा। यह बहुत धीमा होगा, लेकिन पूर्णता प्राप्त करने में समय लगता है।


0

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


यह मूल सरणी में आसन्न जोड़े को जोड़ने के समान है (क्योंकि यह क्रमबद्ध है)। सभी मूल्यों को पेड़ में डालने का कोई कारण नहीं है।
गोदरिक सीयर

0

Histo Iliev ने 64-बिट संकलक के बारे में जो ऊपर कहा है, SSE और AVX निर्देशों को FPU (AKA NDP) से अधिक पसंद करता है, यह बिल्कुल सच है, कम से कम Microsoft Visual Studio 2013 के लिए। हालाँकि, दोहरे सटीक फ़्लोटिंग-पॉइंट ऑपरेशन के लिए मैं उपयोग कर रहा था। यह वास्तव में तेजी से, साथ ही सिद्धांत में अधिक सटीक है, FPU का उपयोग करने के लिए। यदि आपके लिए यह महत्वपूर्ण है, तो मैं अंतिम दृष्टिकोण चुनने से पहले, पहले विभिन्न समाधानों का परीक्षण करने का सुझाव दूंगा।

जावा में काम करते समय, मैं बहुत बार मनमाने ढंग से सटीक बिगडेसिमल डेटा प्रकार का उपयोग करता हूं। यह सिर्फ बहुत आसान है, और एक आमतौर पर गति में कमी को नोटिस नहीं करता है। न्यूटन की विधि का उपयोग करके अनंत श्रृंखला और sqrt के साथ पारलौकिक कार्यों की गणना करना एक मिलीसेकंड या अधिक ले सकता है, लेकिन यह उचित और काफी सटीक है।


0

मैंने केवल इसे यहां छोड़ दिया है /programming//a/58006104/860099 (जब आप वहां जाते हैं, तो 'शो कोड स्निपेट' पर क्लिक करें और इसे बटन द्वारा चलाएं

यह जावास्क्रिप्ट उदाहरण है जो स्पष्ट रूप से दिखाता है कि सबसे बड़ी से शुरू होने वाली राशि बड़ी त्रुटि देती है

arr=[9,.6,.1,.1,.1,.1];

sum     =             arr.reduce((a,c)=>a+c,0);  // =  9.999999999999998
sortSum = [...arr].sort().reduce((a,c)=>a+c,0);  // = 10

console.log('sum:     ',sum);
console.log('sortSum:',sortSum);

इस साइट में लिंक-केवल उत्तर हतोत्साहित किए जाते हैं। क्या आप बता सकते हैं कि लिंक में क्या प्रदान किया गया है?
nicoguaro

@nicoguaro मैं अपडेट का उत्तर देता हूं - सभी उत्तर बहुत अच्छे हैं, लेकिन यहां इसका ठोस उदाहरण है
कामिल कीलव्यूस्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.