दिलचस्प पोस्ट
Django: एक ऑब्जेक्ट फॉर्म डीबी, या 'कोई नहीं' प्राप्त करें अगर कुछ मेल नहीं खाता मैं बाश का उपयोग कर फ़ाइल के बीच में एक पंक्ति की रेखा कैसे जोड़ूं? $ () के बीच कोई अंतर है। तैयार () और $ (दस्तावेज़) .ready () AddChildViewController वास्तव में क्या करता है? जावा में आदिम आंकड़े धागा सुरक्षित हैं वेबजीएल में पारदर्शी बनावटी व्यवहार bash: $ बनाम। $ ((<अंकगणितीय-अभिव्यक्ति>)) ग्रैड डुप्लिकेट एंट्री: java.util.zip.ZipException एक UIView धक्का जब UITabBar छुपा बैश स्क्रिप्ट में पिंग का उपयोग करके होस्ट की उपलब्धता की जांच करना टी-एसक्यूएल के साथ यादृच्छिक तार उत्पन्न करना मैं वास्तव में दृश्य स्टूडियो विंडो लेआउट कैसे रीसेट कर सकता हूं? 'अनपैक करने के लिए बहुत अधिक मूल्य', एक डिक्ट पर फिर से चलना कुंजी => स्ट्रिंग, मान => सूची आईओएस 6/7 में संदेश "सेल सेल के लिए कोई इंडेक्स पथ पुनः उपयोग नहीं किया जा रहा है" का क्या अर्थ है? AJAX सफलता से JSON परिणाम पर jQuery पाश?

सबसे सटीक परिणाम प्राप्त करने के लिए किस आदेश में जोड़ा जाना चाहिए?

यह एक सवाल था जो मुझे मेरे हालिया साक्षात्कार में कहा गया था और मैं जानना चाहता हूं (मुझे वास्तव में संख्यात्मक विश्लेषण के सिद्धांत को याद नहीं है, इसलिए कृपया मेरी मदद करें 🙂

अगर हमारे पास कुछ फ़ंक्शन है, जो फ़्लोटिंग-पॉइंट नंबर जमा करता है:

std::accumulate(v.begin(), v.end(), 0.0); 

v एक std::vector<float> , उदाहरण के लिए।

  • क्या इन आंकड़ों को संचित करने से पहले बेहतर करना बेहतर होगा?

  • कौन सा आदेश सबसे सटीक जवाब देगा?

मुझे संदेह है कि आरोही क्रम में संख्याओं को छांटने से वास्तव में संख्यात्मक त्रुटि कम हो जाएगी , लेकिन दुर्भाग्य से मैं खुद को साबित नहीं कर सकता

पी एस मुझे पता है कि शायद असली दुनिया प्रोग्रामिंग के साथ कुछ नहीं करना है, बस उत्सुक हो रहा है।

Solutions Collecting From Web of "सबसे सटीक परिणाम प्राप्त करने के लिए किस आदेश में जोड़ा जाना चाहिए?"

आपकी वृत्ति मूल रूप से सही है, आरोही क्रम में वर्गीकरण (परिमाण की) आमतौर पर कुछ चीजों में सुधार करती है इस मामले पर विचार करें जहां हम एकल-परिशुद्धता (32 बिट) फ़्लोट्स जोड़ रहे हैं, और 1 अरब (1 अरब) के बराबर 1 अरब मूल्य और 1 के बराबर मूल्य हैं। अगर 1 पहले आता है, तो योग आ जाएगा 1 के लिए, 1 + (1/1 अरब) 1 के कारण शुद्धता के नुकसान के कारण है प्रत्येक अतिरिक्त का कोई भी प्रभाव कुल पर नहीं होता है।

यदि छोटे मूल्य पहले आते हैं, तो वे कम से कम कुछ राशि देंगे, फिर भी मेरे पास उनमें से 2 ^ 30 हैं, जबकि 2 ^ 25 या उसके बाद मैं स्थिति में वापस आ गया हूं जहां प्रत्येक व्यक्ति व्यक्तिगत रूप से कुल प्रभावित नहीं कर रहा है किसी भी अधिक इसलिए मुझे अभी भी अधिक चाल की जरूरत है।

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

फिर भी, यदि ऋणात्मक संख्याएं शामिल हैं तो यह दृष्टिकोण "चकनाचूर" करना आसान है। योग के तीन मानों पर विचार करें, {1, -1, 1 billionth} अंकगणितीय रूप से सही राशि 1 billionth , लेकिन अगर मेरी पहली जोड़ में छोटे मूल्य शामिल हैं तो मेरी अंतिम राशि 0 होगी। 6 संभावित आदेशों में से केवल 2 "सही" – {1, -1, 1 billionth} और {-1, 1, 1 billionth} सभी 6 ऑर्डर ऐसे परिणाम देते हैं जो इनपुट (0.0000001% आउट) के सबसे बड़े पैमाने के पैमाने पर सटीक होते हैं, लेकिन उनमें से 4 के लिए इसका सही समाधान (100% आउट) के पैमाने पर गलत है। आप जिस विशेष समस्या को हल कर रहे हैं वह आपको बताएगा कि क्या पूर्व काफी अच्छा है या नहीं।

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

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

इस तरह के संचय ऑपरेशन के लिए डिज़ाइन किए गए एक एल्गोरिदम भी हैं, जिन्हें कहन समेशन कहा जाता है, आपको शायद जागरूक होना चाहिए।

विकिपीडिया के अनुसार,

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

स्यूडोकोड में, एल्गोरिदम है:

 function kahanSum(input) var sum = input[1] var c = 0.0 //A running compensation for lost low-order bits. for i = 2 to input.length y = input[i] - c //So far, so good: c is zero. t = sum + y //Alas, sum is big, y small, so low-order digits of y are lost. c = (t - sum) - y //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y) sum = t //Algebraically, c should always be zero. Beware eagerly optimising compilers! next i //Next time around, the lost low part will be added to y in a fresh attempt. return sum 

मैंने स्टीव जेसप द्वारा दिए गए उत्तर में चरम उदाहरण की कोशिश की

 #include <iostream> #include <iomanip> #include <cmath> int main() { long billion = 1000000000; double big = 1.0; double small = 1e-9; double expected = 2.0; double sum = big; for (long i = 0; i < billion; ++i) sum += small; std::cout << std::scientific << std::setprecision(1) << big << " + " << billion << " * " << small << " = " << std::fixed << std::setprecision(15) << sum << " (difference = " << std::fabs(expected - sum) << ")" << std::endl; sum = 0; for (long i = 0; i < billion; ++i) sum += small; sum += big; std::cout << std::scientific << std::setprecision(1) << billion << " * " << small << " + " << big << " = " << std::fixed << std::setprecision(15) << sum << " (difference = " << std::fabs(expected - sum) << ")" << std::endl; return 0; } 

मुझे निम्न परिणाम मिला:

 1.0e+00 + 1000000000 * 1.0e-09 = 2.000000082740371 (difference = 0.000000082740371) 1000000000 * 1.0e-09 + 1.0e+00 = 1.999999992539933 (difference = 0.000000007460067) 

पहली पंक्ति में त्रुटि दूसरे में दस गुना बड़ा है।

अगर मैं उपरोक्त कोड में float करने के लिए double एस बदलता हूं, तो मुझे मिल जाता है:

 1.0e+00 + 1000000000 * 1.0e-09 = 1.000000000000000 (difference = 1.000000000000000) 1000000000 * 1.0e-09 + 1.0e+00 = 1.031250000000000 (difference = 0.968750000000000) 

न तो जवाब भी करीब 2.0 है (लेकिन दूसरा थोड़ा करीब है)।

कहेन का सारांश ( double साथ) का प्रयोग करते हुए डैनियल प्राइडेन द्वारा वर्णित किया गया है:

 #include <iostream> #include <iomanip> #include <cmath> int main() { long billion = 1000000000; double big = 1.0; double small = 1e-9; double expected = 2.0; double sum = big; double c = 0.0; for (long i = 0; i < billion; ++i) { double y = small - c; double t = sum + y; c = (t - sum) - y; sum = t; } std::cout << "Kahan sum = " << std::fixed << std::setprecision(15) << sum << " (difference = " << std::fabs(expected - sum) << ")" << std::endl; return 0; } 

मैं बिल्कुल 2.0 मिलता है:

 Kahan sum = 2.000000000000000 (difference = 0.000000000000000) 

और यहां तक ​​कि अगर मैं उपरोक्त कोड में float करने के लिए double एस बदलता हूं, तो मुझे मिल जाता है:

 Kahan sum = 2.000000000000000 (difference = 0.000000000000000) 

ऐसा प्रतीत होता है कि कहां जाने का रास्ता है!

एल्गोरिदम का एक वर्ग है जो इस सटीक समस्या को हल करता है, डेटा को सॉर्ट करने या अन्यथा पुन: ऑर्डर करने की आवश्यकता के बिना

दूसरे शब्दों में, डेटा पर एक पास में समीकरण किया जा सकता है यह ऐसी स्थितियों में लागू ऐसे एल्गोरिदम भी बना देता है जहां डाटासेट पहले से नहीं जाना जाता है, उदाहरण के लिए यदि डेटा वास्तविक समय में आता है और चलने की राशि को बनाए रखा जाना चाहिए।

यहां एक हालिया कागज का सार है:

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

स्रोत: एल्गोरिथ्म 908: फ्लोटिंग-प्वाइंट स्ट्रीम्स का ऑनलाइन सटीक सारांश ।

स्टीव ने पहले नंबरों को आरोही क्रम में क्रमबद्ध करने का जवाब दिया, मैं दो और विचारों को पेश करता हूं:

  1. दो नंबरों के एक्सपोनेंट में अंतर तय करें, इससे आप तय कर सकते हैं कि आप बहुत सटीकता खो देंगे।

  2. इसके बाद संचयकर्ता का एक्सपोनेंट अगली संख्या के लिए बहुत बड़ा होने तक नंबरों को जोड़ दें, फिर एक अस्थायी कतार पर संचयकर्ता को रखें और संचयकर्ता को अगले नंबर के साथ शुरू करें। जब तक आप मूल सूची को समाप्त नहीं करते तब तक जारी रखें

आप अस्थायी कतार (इसे सॉर्ट करते हुए) के साथ प्रक्रिया को दोहराते हैं और एक्सपोनेंट में संभवत: बड़ा अंतर रखते हैं।

मुझे लगता है कि यदि आपको हर समय एक्सपोनेंट्स की गणना करना है तो यह काफी धीमा होगा।

मैं एक कार्यक्रम के साथ एक त्वरित जा रहा था और परिणाम 1.99 9 03 था

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

 while the list has multiple elements remove the two smallest elements from the list add them and put the result back in the single element in the list is the result 

बेशक यह एल्गोरिथ्म एक सूची के बजाय प्राथमिकता कतार के साथ सबसे अधिक कुशल होगा। सी ++ कोड:

 template <typename Queue> void reduce(Queue& queue) { typedef typename Queue::value_type vt; while (queue.size() > 1) { vt x = queue.top(); queue.pop(); vt y = queue.top(); queue.pop(); queue.push(x + y); } } 

चालक:

 #include <iterator> #include <queue> template <typename Iterator> typename std::iterator_traits<Iterator>::value_type reduce(Iterator begin, Iterator end) { typedef typename std::iterator_traits<Iterator>::value_type vt; std::priority_queue<vt> positive_queue; positive_queue.push(0); std::priority_queue<vt> negative_queue; negative_queue.push(0); for (; begin != end; ++begin) { vt x = *begin; if (x < 0) { negative_queue.push(x); } else { positive_queue.push(-x); } } reduce(positive_queue); reduce(negative_queue); return negative_queue.top() - positive_queue.top(); } 

कतार में दिए गए नंबर नकारात्मक हैं, क्योंकि सबसे बड़ी संख्या सबसे top है, लेकिन हम सबसे छोटी मांग चाहते हैं। मैं कतार में अधिक टेम्पलेट तर्क प्रदान कर सकता था, लेकिन यह दृष्टिकोण सरल लगता है।

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

अंतराल अंकगणितीय पर एक नज़र डालें जहां आप इस तरह के सभी गणित करते हैं, जैसा कि आप जाते हैं, उच्चतम और निम्नतम मान रखते हैं। यह कुछ रोचक परिणाम और अनुकूलन की ओर जाता है।

सटीकता को सुधारने वाला सरलतम क्रम आरोही निरपेक्ष मान द्वारा क्रमबद्ध करना है इससे बड़े परिमाण के मूल्यों के साथ बातचीत करने से पहले छोटे परिमाण के मानों को इकट्ठा करने या रद्द करने का मौका मिलता है जिससे सटीकता में कमी आती है।

उसने कहा, आप कई गैर-ओवरलैपिंग आंशिक रकम पर नज़र रखने से बेहतर कर सकते हैं। तकनीक का वर्णन करने वाला एक पेपर और सटीकता प्रमाणित करने वाला एक ऐसा तरीका है: www2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps

उस एल्गोरिदम और सटीक फ़्लोटिंग पॉइंट सम्मेलन के अन्य तरीकों को सरल पायथन में इस पर लागू किया जाता है: http://code.activestate.com/recipes/393090/ उनमें से कम से कम दो को तुच्छ सी ++ में परिवर्तित किया जा सकता है।

आईईईई 754 एकल या दोहरी सटीक या ज्ञात प्रारूप संख्या के लिए, एक अन्य विकल्प, एक्सपोनेंट द्वारा अनुक्रमित संख्याओं (कॉलर द्वारा पारित किया गया है, या सी ++ के लिए क्लास में) का उपयोग करना है। सरणी में संख्याओं को जोड़ते समय, एक ही एक्सपोनेंट के साथ केवल संख्याएं जोड़ दी जाती हैं (जब तक कि एक रिक्त स्लॉट नहीं मिलती और संख्या संग्रहीत हो)। जब एक राशि के लिए कहा जाता है, तो सरणी को छोटा करने से सबसे बड़ा करने के लिए संक्षेप में संक्षेप किया जाता है। एकल सटीक उदाहरण:

 /* clear array */ void clearsum(float asum[256]) { size_t i; for(i = 0; i < 256; i++) asum[i] = 0.f; } /* add a number into array */ void addtosum(float f, float asum[256]) { size_t i; while(1){ /* i = exponent of f */ i = ((size_t)((*(unsigned int *)&f)>>23))&0xff; if(i == 0xff){ /* max exponent, could be overflow */ asum[i] += f; return; } if(asum[i] == 0.f){ /* if empty slot store f */ asum[i] = f; return; } f += asum[i]; /* else add slot to f, clear slot */ asum[i] = 0.f; /* and continue until empty slot */ } } /* return sum from array */ float returnsum(float asum[256]) { float sum = 0.f; size_t i; for(i = 0; i < 256; i++) sum += asum[i]; return sum; } 

डबल सटीक उदाहरण:

 /* clear array */ void clearsum(double asum[2048]) { size_t i; for(i = 0; i < 2048; i++) asum[i] = 0.; } /* add a number into array */ void addtosum(double d, double asum[2048]) { size_t i; while(1){ /* i = exponent of d */ i = ((size_t)((*(unsigned long long *)&d)>>52))&0x7ff; if(i == 0x7ff){ /* max exponent, could be overflow */ asum[i] += d; return; } if(asum[i] == 0.){ /* if empty slot store d */ asum[i] = d; return; } d += asum[i]; /* else add slot to d, clear slot */ asum[i] = 0.; /* and continue until empty slot */ } } /* return sum from array */ double returnsum(double asum[2048]) { double sum = 0.; size_t i; for(i = 0; i < 2048; i++) sum += asum[i]; return sum; } 

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

यदि आप डबल सटीक संख्या जोड़ रहे हैं, तो राशि के लिए लंबे समय से दो बार उपयोग करें – हालांकि, कार्यान्वयन में इसका केवल एक सकारात्मक असर होगा, जहां लंबे समय से दोगुने वास्तव में डबल (आमतौर पर x86, कंपाइलर सेटिंग्स के आधार पर, PowerPC) की तुलना में अधिक सटीक होता है।

सॉर्टिंग के बारे में, मुझे ऐसा लगता है कि यदि आप निरस्तीकरण की उम्मीद करते हैं तो संख्याओं को आरोही क्रम के क्रम में जोड़ा जाना चाहिए, आरोही नहीं। उदाहरण के लिए:

((-1 + 1) + 1 ए -20) 1e-20 दे देंगे

परंतु

((1e-20 + 1) – 1) 0 दे देंगे

पहले समीकरण में दो बड़ी संख्याएं रद्द कर दी गई हैं, जबकि दूसरे में 1e-20 पद खो दिया जाता है जब 1 को जोड़ा जाता है, क्योंकि इसे बनाए रखने के लिए पर्याप्त परिशुद्धता नहीं है।

इसके अलावा, जोड़ों का सार बहुत सारे संख्याओं के लिए संक्षेप में है।